// SPDX-FileContributor: FlameFlag <github@flameflag.dev>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package handle

import (
	"strings"

	"github.com/asciimoo/hister/config"
	"github.com/asciimoo/hister/ui/model"
	"github.com/asciimoo/hister/ui/network"
	"github.com/asciimoo/hister/ui/render"
	"github.com/asciimoo/hister/ui/theme"

	tea "github.com/charmbracelet/bubbletea"
	"github.com/pkg/browser"
	"github.com/rs/zerolog/log"
)

func DispatchCommonAction(m *model.Model, action config.Action) (tea.Cmd, bool) {
	switch action {
	case config.ActionQuit:
		return tea.Batch(m.FlashHint(config.ActionQuit), tea.Quit), true
	case config.ActionToggleHelp:
		m.OpenOverlay(model.StateHelp)
		return m.FlashHint(config.ActionToggleHelp), true
	case config.ActionToggleTheme:
		if m.ThemeName == "no-color" {
			return nil, true
		}
		m.OpenThemePicker()
		return nil, true
	case config.ActionToggleSettings:
		m.SettingsIdx = 0
		m.OpenOverlay(model.StateSettings)
		return nil, true
	case config.ActionToggleSort:
		if m.SortMode == "" {
			m.SortMode = "domain"
		} else {
			m.SortMode = ""
		}
		return startSearch(m, m.FlashHint(config.ActionToggleSort)), true
	case config.ActionScrollUp:
		if m.SelectedIdx > 0 {
			m.SelectedIdx--
			render.RefreshAndScroll(m)
		}
		return m.FlashHint(config.ActionScrollUp), true
	case config.ActionScrollDown:
		if m.SelectedIdx < m.GetTotalResults()-1 {
			m.SelectedIdx++
			render.RefreshAndScroll(m)
		}
		return m.FlashHint(config.ActionScrollDown), true
	case config.ActionDeleteResult:
		if u := m.GetSelectedURL(); u != "" {
			m.OpenDeleteDialog("Delete Result", u, -1, func() tea.Cmd {
				return tea.Batch(
					m.DeleteURLCmd(u),
					doSearch(m),
				)
			})
		}
		return m.FlashHint(config.ActionDeleteResult), true
	case config.ActionTabSearch, config.ActionTabHistory, config.ActionTabRules, config.ActionTabAdd:
		return SwitchTab(m, action), true
	}
	return nil, false
}

func ExecuteAction(m *model.Model, action config.Action) tea.Cmd {
	if cmd, handled := DispatchCommonAction(m, action); handled {
		return cmd
	}
	switch action {
	case config.ActionOpenResult:
		if m.SelectedIdx >= 0 {
			if u := m.GetSelectedURL(); u != "" {
				if err := browser.OpenURL(u); err != nil {
					log.Warn().Err(err).Msg("failed to open URL in browser")
				}
				return tea.Batch(m.FlashHint(config.ActionOpenResult), m.PostHistoryCmd(u))
			}
		}
		return m.FlashHint(config.ActionOpenResult)
	case config.ActionToggleFocus:
		if m.State == model.StateInput {
			if m.GetTotalResults() > 0 {
				m.State = model.StateResults
				m.TextInput.Blur()
				if m.SelectedIdx < 0 {
					m.SelectedIdx = 0
				}
				render.RefreshAndScroll(m)
			}
		} else {
			m.State = model.StateInput
			return m.TextInput.Focus()
		}
		return nil
	}
	return nil
}

func SwitchTab(m *model.Model, action config.Action) tea.Cmd {
	prevTab := m.ActiveTab
	if tab, ok := model.ActionToTab[action]; ok {
		m.ActiveTab = tab
	}
	if m.ActiveTab == prevTab {
		return nil
	}
	m.TextInput.Blur()
	m.State = model.StateResults
	var cmd tea.Cmd
	switch m.ActiveTab {
	case model.TabSearch:
		m.State = model.StateInput
		cmd = m.TextInput.Focus()
	case model.TabHistory:
		m.HistoryLoading = true
		cmd = m.FetchHistoryCmd()
	case model.TabRules:
		m.RulesLoading = true
		m.RulesFormFocus = model.RulesFieldList
		m.RulesEditingIdx = -1
		m.BlurAllRulesInputs()
		cmd = m.FetchRulesCmd()
	case model.TabAdd:
		m.AddInputs[0].Focus()
		m.AddFocusIdx = 0
	}
	return cmd
}

func startSearch(m *model.Model, extra ...tea.Cmd) tea.Cmd {
	cmds := append([]tea.Cmd{doSearch(m)}, extra...)
	if m.WsReady {
		m.IsSearching = true
		cmds = append(cmds, m.Spinner.Tick)
	}
	return tea.Batch(cmds...)
}

func doSearch(m *model.Model) tea.Cmd {
	q := m.TextInput.Value()
	if strings.TrimSpace(q) == "" {
		return func() tea.Msg {
			return model.ResultsMsg{Results: nil}
		}
	}
	return network.Search(m.Conn, &m.WsMu, m.WsReady, model.SearchQuery{
		Text:      strings.TrimSpace(q),
		Highlight: "tui",
		Limit:     m.Limit + 1,
		Sort:      m.SortMode,
	})
}

func CloseOverlay(m *model.Model) tea.Cmd {
	m.DismissOverlay()
	if m.State == model.StateInput {
		return m.TextInput.Focus()
	}
	return nil
}

func submitAdd(m *model.Model) tea.Cmd {
	u := strings.TrimSpace(m.AddInputs[0].Value())
	if u == "" {
		m.AddStatus = "URL is required"
		return nil
	}
	if !strings.Contains(u, "://") {
		u = "https://" + u
		m.AddInputs[0].SetValue(u)
	}
	title := strings.TrimSpace(m.AddInputs[1].Value())
	text := strings.TrimSpace(m.AddInputs[2].Value())
	m.AddStatus = "Adding..."
	return m.AddPageCmd(u, title, text)
}

func CloseThemePickerWithRevert(m *model.Model) tea.Cmd {
	m.Cfg.TUI.DarkTheme = m.OrigDarkTheme
	m.Cfg.TUI.LightTheme = m.OrigLightTheme
	m.Cfg.TUI.ColorScheme = m.OrigColorScheme
	m.ThemePickerMode = m.OrigColorScheme
	if p, ok := theme.GetPalette(m.OrigThemeName); ok {
		m.ApplyTheme(p)
		render.RefreshViewport(m)
	}
	return CloseOverlay(m)
}
