package tui

import (
	"fmt"
	"strings"

	"github.com/charmbracelet/bubbles/textinput"
	tea "github.com/charmbracelet/bubbletea"

	"github.com/jixishi/SerialTerminalForWindowsTerminal/internal/event"
	"github.com/jixishi/SerialTerminalForWindowsTerminal/pkg/forward"
)

func (m *Model) handleModalKey(msg tea.KeyMsg) (bool, tea.Cmd) {
	keyStr := strings.ToLower(msg.String())

	if m.formActive {
		return m.handleFormKey(msg)
	}
	if m.promptActive {
		return m.handlePromptKey(msg)
	}
	if keyStr == "esc" {
		m.closeModal()
		return true, nil
	}
	if m.panelKind == event.UIPanelNone {
		if keyStr == "enter" {
			m.closeModal()
		}
		return true, nil
	}

	switch m.panelKind {
	case event.UIPanelForward:
		return m.handleForwardPanelKey(keyStr), nil
	case event.UIPanelPlugin:
		return m.handlePluginPanelKey(keyStr), nil
	case event.UIPanelMode:
		return m.handleModePanelKey(keyStr), nil
	default:
		return true, nil
	}
}

func (m *Model) closeModal() {
	m.showModal = false
	m.panelKind = event.UIPanelNone
	m.modalTitle = ""
	m.modalBody = ""
	m.promptActive = false
	m.promptSubmit = nil
	m.formActive = false
	m.formSubmit = nil
	m.panelError = ""
}

func (m *Model) openPanel(kind event.UIPanelKind) {
	m.showModal = true
	m.panelKind = kind
	m.panelIndex = 0
	m.promptActive = false
	m.promptSubmit = nil
	m.panelError = ""
	m.refreshPanel()
}

func (m *Model) refreshPanel() {
	switch m.panelKind {
	case event.UIPanelForward:
		m.forwardItems = m.App.Forward().List()
		m.panelIndex = clampIndex(m.panelIndex, len(m.forwardItems))
	case event.UIPanelPlugin:
		m.pluginItems = m.App.Plugins().List()
		m.panelIndex = clampIndex(m.panelIndex, len(m.pluginItems))
	case event.UIPanelMode:
		m.modeItems = m.buildModeItems()
		m.panelIndex = clampIndex(m.panelIndex, len(m.modeItems))
	}
}

func (m *Model) buildModeItems() []modeItem {
	cfg := m.App.Cfg()
	return []modeItem{
		{"in", "Input Charset", cfg.InputCode, cfg.InputCode},
		{"out", "Output Charset", cfg.OutputCode, cfg.OutputCode},
		{"end", "Line End", fmt.Sprintf("%q", cfg.EndStr), cfg.EndStr},
		{"frame", "Hex Frame Size", fmt.Sprintf("%d", cfg.FrameSize), fmt.Sprintf("%d", cfg.FrameSize)},
		{"timestamp", "Timestamp", fmt.Sprintf("%v", cfg.TimesTamp), fmt.Sprintf("%v", cfg.TimesTamp)},
		{"timefmt", "Timestamp Format", cfg.TimesFmt, cfg.TimesFmt},
	}
}

// Forward modes for tab cycling
var forwardModes = []string{"tcp", "udp", "tcp-s", "udp-s", "com"}

func (m *Model) handleForwardPanelKey(key string) bool {
	switch key {
	case "up", "k":
		if m.panelIndex > 0 {
			m.panelIndex--
		}
		return true
	case "down", "j":
		if m.panelIndex < len(m.forwardItems)-1 {
			m.panelIndex++
		}
		return true
	case "r":
		m.panelError = ""
		m.refreshPanel()
		return true
	case "a":
		m.startForwardForm("Add", "tcp", "")
		return true
	}
	if len(m.forwardItems) == 0 {
		return true
	}

	sel := m.forwardItems[m.panelIndex]
	switch key {
	case "enter":
		if sel.Enabled {
			_ = m.App.Forward().Disable(sel.ID)
		} else {
			_ = m.App.Forward().Enable(sel.ID)
		}
		m.panelError = ""
		m.refreshPanel()
		return true
	case "d", "delete":
		m.startPrompt("Remove Forward #"+fmt.Sprint(sel.ID), "type 'y' to confirm", "", func(v string) {
			if strings.TrimSpace(strings.ToLower(v)) == "y" {
				if err := m.App.Forward().Remove(sel.ID); err != nil {
					m.panelError = err.Error()
				} else {
					m.panelError = ""
					m.refreshPanel()
				}
			}
		})
		return true
	case "u":
		m.startForwardForm("Update #"+fmt.Sprint(sel.ID), sel.Mode, sel.Address)
		return true
	default:
		return true
	}
}

func (m *Model) startForwardForm(title, mode, address string) {
	modeIn := textinput.New()
	modeIn.Prompt = "  Type: "
	modeIn.Placeholder = "Tab to cycle modes"
	modeIn.SetValue(mode)
	modeIn.CharLimit = 10
	modeIn.Width = 36

	addrIn := textinput.New()
	addrIn.Prompt = "  Addr: "
	addrIn.Placeholder = "host:port or COM port"
	addrIn.SetValue(address)
	addrIn.CharLimit = 60
	addrIn.Width = 36

	m.formActive = true
	m.formTitle = title
	m.formLabels = []string{"Type (Tab cycle)", "Address"}
	m.formFields = []textinput.Model{modeIn, addrIn}
	m.formFocus = 0
	m.formFields[0].Focus()

	m.formSubmit = func(vals []string) {
		modeStr := strings.TrimSpace(vals[0])
		addrStr := strings.TrimSpace(vals[1])

		fm, ok := forward.ParseMode(modeStr)
		if !ok {
			m.panelError = "unknown mode: " + modeStr
			return
		}
		if addrStr == "" {
			m.panelError = "address is required"
			return
		}

		if strings.HasPrefix(title, "Add") {
			if _, err := m.App.Forward().Add(fm, addrStr); err != nil {
				m.panelError = err.Error()
				return
			}
		} else {
			sel := m.forwardItems[m.panelIndex]
			if err := m.App.Forward().Update(sel.ID, fm, addrStr); err != nil {
				m.panelError = err.Error()
				return
			}
		}
		m.panelError = ""
		m.refreshPanel()
	}
}

func (m *Model) handlePluginPanelKey(key string) bool {
	switch key {
	case "up", "k":
		if m.panelIndex > 0 {
			m.panelIndex--
		}
		return true
	case "down", "j":
		if m.panelIndex < len(m.pluginItems)-1 {
			m.panelIndex++
		}
		return true
	case "r":
		m.panelError = ""
		m.refreshPanel()
		return true
	case "l":
		m.startPrompt("Load Plugin", "./plugins/demo.lua", "", func(v string) {
			path := strings.TrimSpace(v)
			if path == "" {
				m.panelError = "load path is empty"
				return
			}
			if _, err := m.App.Plugins().Load(path); err != nil {
				m.panelError = err.Error()
			} else {
				m.panelError = ""
				m.refreshPanel()
			}
		})
		return true
	}
	if len(m.pluginItems) == 0 {
		return true
	}

	sel := m.pluginItems[m.panelIndex]
	switch key {
	case "enter":
		if sel.Enabled {
			_ = m.App.Plugins().Disable(sel.Name)
		} else {
			_ = m.App.Plugins().Enable(sel.Name)
		}
		m.panelError = ""
		m.refreshPanel()
		return true
	case "u":
		if err := m.App.Plugins().Reload(sel.Name); err != nil {
			m.panelError = err.Error()
		} else {
			m.panelError = ""
			m.refreshPanel()
		}
		return true
	case "d", "delete":
		m.startPrompt("Unload Plugin "+sel.Name, "type 'y' to confirm", "", func(v string) {
			if strings.TrimSpace(strings.ToLower(v)) == "y" {
				if err := m.App.Plugins().Unload(sel.Name); err != nil {
					m.panelError = err.Error()
				} else {
					m.panelError = ""
					m.refreshPanel()
				}
			}
		})
		return true
	default:
		return true
	}
}

func (m *Model) handleModePanelKey(key string) bool {
	switch key {
	case "up", "k":
		if m.panelIndex > 0 {
			m.panelIndex--
		}
		return true
	case "down", "j":
		if m.panelIndex < len(m.modeItems)-1 {
			m.panelIndex++
		}
		return true
	case "r":
		m.panelError = ""
		m.refreshPanel()
		return true
	}
	if len(m.modeItems) == 0 {
		return true
	}

	sel := m.modeItems[m.panelIndex]
	cfg := m.App.Cfg()
	switch key {
	case " ":
		if sel.key == "timestamp" {
			cfg.TimesTamp = !cfg.TimesTamp
			m.refreshPanel()
		}
		return true
	case "enter", "e":
		hint := "enter value"
		switch sel.key {
		case "timestamp":
			hint = "on/off"
		case "frame":
			hint = "positive integer"
		case "in", "out":
			hint = "charset name (e.g. utf-8, gbk)"
		}
		initial := sel.rawValue
		m.startPrompt("Edit Mode: "+sel.label, hint, initial, func(v string) {
			m.App.HandleLine(fmt.Sprintf(".mode set %s %s", sel.key, v))
			m.refreshPanel()
		})
		return true
	default:
		return true
	}
}

func (m *Model) startPrompt(title, hint, initial string, submit func(string)) {
	in := textinput.New()
	in.Prompt = "> "
	in.Placeholder = hint
	in.SetValue(initial)
	in.Focus()
	in.CharLimit = 0
	in.Width = 64

	m.promptActive = true
	m.promptTitle = title
	m.promptHint = hint
	m.promptInput = in
	m.promptSubmit = submit
}

// --- Form methods (multi-field input) ---

func (m *Model) handleFormKey(msg tea.KeyMsg) (bool, tea.Cmd) {
	key := strings.ToLower(msg.String())
	switch key {
	case "esc":
		m.formActive = false
		m.formSubmit = nil
		return true, nil
	case "tab":
		m.formFields[m.formFocus].Blur()
		m.formFocus = (m.formFocus + 1) % len(m.formFields)

		// Cycle forward mode on Tab when type field is focused
		if m.formFocus == 0 {
			cur := strings.TrimSpace(m.formFields[0].Value())
			idx := -1
			for i, m := range forwardModes {
				if m == cur {
					idx = i
					break
				}
			}
			idx = (idx + 1) % len(forwardModes)
			m.formFields[0].SetValue(forwardModes[idx])
		}
		m.formFields[m.formFocus].Focus()
		return true, nil
	case "shift+tab":
		m.formFields[m.formFocus].Blur()
		m.formFocus = (m.formFocus - 1 + len(m.formFields)) % len(m.formFields)
		if m.formFocus == 0 {
			cur := strings.TrimSpace(m.formFields[0].Value())
			idx := -1
			for i, m := range forwardModes {
				if m == cur { idx = i; break }
			}
			idx = (idx - 1 + len(forwardModes)) % len(forwardModes)
			m.formFields[0].SetValue(forwardModes[idx])
		}
		m.formFields[m.formFocus].Focus()
		return true, nil
	case "enter":
		vals := make([]string, len(m.formFields))
		for i, f := range m.formFields {
			vals[i] = f.Value()
		}
		submit := m.formSubmit
		m.formActive = false
		m.formSubmit = nil
		if submit != nil {
			submit(vals)
		}
		return true, nil
	default:
		var cmd tea.Cmd
		m.formFields[m.formFocus], cmd = m.formFields[m.formFocus].Update(msg)
		return true, cmd
	}
}

func (m *Model) renderForm() string {
	lines := make([]boxLine, 0, len(m.formFields)+2)
	for i, f := range m.formFields {
		prefix := "  "
		if i == m.formFocus {
			prefix = "▸ "
		}
		lines = append(lines, boxLine{
			text:  prefix + f.View(),
			style: modalBodyLineStyle(),
		})
	}
	footer := "Tab cycles Type | Enter submit | Esc cancel"
	if len(m.formFields) > 1 {
		footer = "Tab/Shift+Tab switch | Enter submit | Esc cancel"
	}
	lines = append(lines, boxLine{text: footer, style: modalFooterLineStyle()})
	return renderBox(m.formTitle, lines, 36, m.availableModalWidth())
}

func (m *Model) handlePromptKey(msg tea.KeyMsg) (bool, tea.Cmd) {
	key := strings.ToLower(msg.String())
	switch key {
	case "esc":
		m.promptActive = false
		m.promptSubmit = nil
		return true, nil
	case "enter":
		value := strings.TrimSpace(m.promptInput.Value())
		submit := m.promptSubmit
		m.promptActive = false
		m.promptSubmit = nil
		if submit != nil {
			submit(value)
		}
		return true, nil
	default:
		var cmd tea.Cmd
		m.promptInput, cmd = m.promptInput.Update(msg)
		return true, cmd
	}
}

func (m *Model) renderPanel() string {
	switch m.panelKind {
	case event.UIPanelForward:
		return m.renderForwardPanel()
	case event.UIPanelPlugin:
		return m.renderPluginPanel()
	case event.UIPanelMode:
		return m.renderModePanel()
	default:
		return renderModal("Info", "No panel", m.availableModalWidth())
	}
}

func (m *Model) renderForwardPanel() string {
	lines := make([]panelLine, 0, len(m.forwardItems)+3)
	if len(m.forwardItems) == 0 {
		lines = append(lines, panelLine{text: "No forwarding targets. Press 'a' to add one."})
	} else {
		lines = append(lines, panelLine{text: "ID  Mode  Enabled  Connected  Address"})
		for i, it := range m.forwardItems {
			lines = append(lines, panelLine{text: fmt.Sprintf("%-3d %-5s %-7v %-9v %s", it.ID, it.Mode, it.Enabled, it.Connected, it.Address), selected: i == m.panelIndex})
		}
	}
	if m.panelError != "" {
		lines = append(lines, panelLine{text: "ERROR: " + m.panelError})
	}
	return renderPanelModal("Forward Panel", lines, "j/k select | Enter toggle | a add(form) | u update | d remove | r refresh | Esc close", m.availableModalWidth())
}

func (m *Model) renderPluginPanel() string {
	lines := make([]panelLine, 0, len(m.pluginItems)+3)
	if len(m.pluginItems) == 0 {
		lines = append(lines, panelLine{text: "No plugins loaded. Press 'l' to load one."})
	} else {
		lines = append(lines, panelLine{text: "Name                 Enabled  Path"})
		for i, it := range m.pluginItems {
			lines = append(lines, panelLine{text: fmt.Sprintf("%-20s %-7v %s", it.Name, it.Enabled, it.Path), selected: i == m.panelIndex})
		}
	}
	if m.panelError != "" {
		lines = append(lines, panelLine{text: "ERROR: " + m.panelError})
	}
	return renderPanelModal("Plugin Panel", lines, "Up/Down select | Enter toggle | l load | u reload | d unload | r refresh | Esc close", m.availableModalWidth())
}

func (m *Model) renderModePanel() string {
	lines := make([]panelLine, 0, len(m.modeItems)+3)
	lines = append(lines, panelLine{text: "Field            Value"})
	for i, it := range m.modeItems {
		lines = append(lines, panelLine{text: fmt.Sprintf("%-16s %s", it.label, it.value), selected: i == m.panelIndex})
	}
	if m.panelError != "" {
		lines = append(lines, panelLine{text: "ERROR: " + m.panelError})
	}
	return renderPanelModal("Mode Panel", lines, "Up/Down select | Enter edit | Space toggle | r refresh | Esc close", m.availableModalWidth())
}

