package tui

import (
	"fmt"
	"strconv"
	"strings"

	tea "github.com/charmbracelet/bubbletea"

	"dbbackup/internal/config"
	"dbbackup/internal/logger"
)

// InputModel for getting user input
type InputModel struct {
	config   *config.Config
	logger   logger.Logger
	parent   tea.Model
	title    string
	prompt   string
	value    string
	cursor   int
	done     bool
	err      error
	validate func(string) error
}

func NewInputModel(cfg *config.Config, log logger.Logger, parent tea.Model, title, prompt, defaultValue string, validate func(string) error) InputModel {
	return InputModel{
		config:   cfg,
		logger:   log,
		parent:   parent,
		title:    title,
		prompt:   prompt,
		value:    defaultValue,
		validate: validate,
		cursor:   len(defaultValue),
	}
}

func (m InputModel) Init() tea.Cmd {
	// Auto-confirm: use default value and proceed
	if m.config.TUIAutoConfirm && m.value != "" {
		return func() tea.Msg {
			return inputAutoConfirmMsg{}
		}
	}
	return nil
}

// inputAutoConfirmMsg triggers automatic input confirmation
type inputAutoConfirmMsg struct{}

func (m InputModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case inputAutoConfirmMsg:
		// Use default value and proceed
		if selector, ok := m.parent.(DatabaseSelectorModel); ok {
			ratio, _ := strconv.Atoi(m.value)
			executor := NewBackupExecution(selector.config, selector.logger, selector.parent, selector.ctx,
				selector.backupType, selector.selected, ratio)
			return executor, executor.Init()
		}
		return m.parent, tea.Quit

	case tea.KeyMsg:
		switch msg.String() {
		case "ctrl+c", "esc":
			// Return to grandparent (menu) not immediate parent (selector)
			if selector, ok := m.parent.(DatabaseSelectorModel); ok {
				return selector.parent, nil
			}
			return m.parent, nil

		case "enter":
			if m.validate != nil {
				if err := m.validate(m.value); err != nil {
					m.err = err
					return m, nil
				}
			}
			m.done = true

			// If this is from database selector, execute backup with ratio
			if selector, ok := m.parent.(DatabaseSelectorModel); ok {
				ratio, _ := strconv.Atoi(m.value)
				executor := NewBackupExecution(selector.config, selector.logger, selector.parent, selector.ctx,
					selector.backupType, selector.selected, ratio)
				return executor, executor.Init()
			}
			return m, nil

		case "backspace", "ctrl+h":
			if len(m.value) > 0 && m.cursor > 0 {
				m.value = m.value[:m.cursor-1] + m.value[m.cursor:]
				m.cursor--
			}

		case "left":
			if m.cursor > 0 {
				m.cursor--
			}

		case "right":
			if m.cursor < len(m.value) {
				m.cursor++
			}

		default:
			// Add character
			if len(msg.String()) == 1 {
				m.value = m.value[:m.cursor] + msg.String() + m.value[m.cursor:]
				m.cursor++
				m.err = nil
			}
		}
	}

	return m, nil
}

func (m InputModel) View() string {
	var s strings.Builder

	header := titleStyle.Render(m.title)
	s.WriteString(fmt.Sprintf("\n%s\n\n", header))

	s.WriteString(fmt.Sprintf("%s\n\n", m.prompt))

	// Show input with cursor
	before := m.value[:m.cursor]
	after := ""
	if m.cursor < len(m.value) {
		after = m.value[m.cursor:]
	}
	s.WriteString(inputStyle.Render(fmt.Sprintf("> %s▎%s", before, after)))
	s.WriteString("\n\n")

	if m.err != nil {
		s.WriteString(errorStyle.Render(fmt.Sprintf("[FAIL] Error: %v\n\n", m.err)))
	}

	s.WriteString("[KEYS]  Type value | Enter: Confirm | ESC: Cancel\n")

	return s.String()
}

func (m InputModel) GetValue() string {
	return m.value
}

func (m InputModel) GetIntValue() (int, error) {
	return strconv.Atoi(m.value)
}

func (m InputModel) IsDone() bool {
	return m.done
}

// Validation functions
func ValidateInt(min, max int) func(string) error {
	return func(s string) error {
		val, err := strconv.Atoi(s)
		if err != nil {
			return fmt.Errorf("must be a number")
		}
		if val < min || val > max {
			return fmt.Errorf("must be between %d and %d", min, max)
		}
		return nil
	}
}

func ValidateNotEmpty(s string) error {
	if strings.TrimSpace(s) == "" {
		return fmt.Errorf("value cannot be empty")
	}
	return nil
}
