package tui

import (
	"errors"
	"fmt"
	"strings"

	tea "github.com/charmbracelet/bubbletea"
	"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers"
	"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config"
	"github.com/trufflesecurity/trufflehog/v3/pkg/tui/common"
	"github.com/trufflesecurity/trufflehog/v3/pkg/tui/keymap"
	"github.com/trufflesecurity/trufflehog/v3/pkg/tui/styles"
)

// TUI is the main TUI model.
type TUI struct {
	keyType    string
	secretInfo *SecretInfo
	common     *common.Common
	model      tea.Model
}

type SecretInfo struct {
	Parts map[string]string
	Cfg   *config.Config
}

var AbortError error = errors.New("command aborted")

func Run(keyType string) (string, *SecretInfo, error) {
	// If a keyType is provided, make sure it's in the list of AvailableAnalyzers.
	if keyType != "" {
		var found bool
		for _, a := range analyzers.AvailableAnalyzers {
			if strings.EqualFold(a, keyType) {
				keyType = a
				found = true
				break
			}
		}
		if !found {
			return "", nil, fmt.Errorf("Unrecognized command %q", keyType)
		}
	}

	t := &TUI{
		keyType: keyType,
		common: &common.Common{
			KeyMap: keymap.DefaultKeyMap(),
		},
	}
	if _, err := tea.NewProgram(t).Run(); err != nil {
		return "", nil, err
	}
	if t.secretInfo == nil {
		return "", nil, AbortError
	}
	return t.keyType, t.secretInfo, nil
}

func (ui *TUI) Init() tea.Cmd {
	return nil
}

func (ui *TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	if msg, ok := msg.(tea.WindowSizeMsg); ok {
		ui.SetSize(msg)
	}
	// Always be able to force quit.
	if msg, ok := msg.(tea.KeyMsg); ok && msg.Type.String() == "ctrl+c" {
		return ui, tea.Quit
	}

	switch m := msg.(type) {
	case SetKeyTypeMsg:
		ui.keyType = string(m)
	case SecretInfo:
		ui.secretInfo = &m
		return ui, tea.Quit
	}

	if ui.model == nil {
		return ui, nil
	}

	var cmd tea.Cmd
	ui.model, cmd = ui.model.Update(msg)
	return ui, cmd
}

func (ui *TUI) View() string {
	if ui.model == nil {
		return "Loading..."
	}
	return ui.model.View()
}

func (ui *TUI) SetSize(msg tea.WindowSizeMsg) {
	h, v := styles.AppStyle.GetFrameSize()
	h, v = msg.Width-h, msg.Height-v
	ui.common.SetSize(h, v)
	if ui.model != nil {
		return
	}

	// Set the model only after we have size information.
	// TODO: Responsive pages.
	if ui.keyType == "" {
		ui.model = NewKeyTypePage(ui.common)
	} else {
		ui.model = NewFormPage(ui.common, ui.keyType)
	}
}

type SetKeyTypeMsg string

func SetKeyTypeCmd(keyType string) tea.Cmd {
	return func() tea.Msg {
		return SetKeyTypeMsg(keyType)
	}
}
