package ui

import (
	"fmt"
	"strings"
	"woke/db"

	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
	"github.com/robfig/cron/v3"
)

type formField int

const (
	fieldName formField = iota
	fieldDescription
	fieldTime
	fieldTrigger
	fieldSound
	fieldCount // sentinel
)

type formModel struct {
	editing  *db.Alarm // nil = creating new
	fields   [fieldCount]string
	active   formField
	err      string
}

func newFormModel(alarm *db.Alarm) *formModel {
	f := &formModel{}
	if alarm != nil {
		f.editing = alarm
		f.fields[fieldName] = alarm.Name
		f.fields[fieldDescription] = alarm.Description
		f.fields[fieldTime] = alarm.Time
		f.fields[fieldTrigger] = alarm.Trigger
		f.fields[fieldSound] = alarm.SoundPath
	} else {
		f.fields[fieldTrigger] = "once"
		f.fields[fieldSound] = "default"
	}
	return f
}

func (f *formModel) Update(msg tea.Msg, m *Model) (tea.Model, tea.Cmd) {
	return *m, nil
}

func (f *formModel) HandleKey(msg tea.KeyMsg, m *Model) (tea.Model, tea.Cmd) {
	key := msg.String()

	switch key {
	case "esc", "escape":
		m.mode = viewMain
		m.form = nil
		m.statusMsg = ""
		return *m, nil

	case "tab", "down":
		f.active = (f.active + 1) % fieldCount
		return *m, nil

	case "shift+tab", "up":
		f.active = (f.active - 1 + fieldCount) % fieldCount
		return *m, nil

	case "enter":
		return f.save(m)

	case "backspace":
		field := &f.fields[f.active]
		if len(*field) > 0 {
			*field = (*field)[:len(*field)-1]
		}
		f.err = ""
		return *m, nil

	case "ctrl+u":
		f.fields[f.active] = ""
		f.err = ""
		return *m, nil

	default:
		// Only accept printable characters
		if len(key) == 1 {
			f.fields[f.active] += key
			f.err = ""
		}
		return *m, nil
	}
}

func (f *formModel) save(m *Model) (tea.Model, tea.Cmd) {
	name := strings.TrimSpace(f.fields[fieldName])
	if name == "" {
		f.err = "Name is required"
		return *m, nil
	}

	timeStr := strings.TrimSpace(f.fields[fieldTime])
	trigger := strings.TrimSpace(f.fields[fieldTrigger])

	if trigger == "once" || trigger == "" {
		trigger = "once"
		// Validate HH:MM format
		if !isValidTime(timeStr) {
			f.err = "Time must be in HH:MM format (00:00-23:59)"
			return *m, nil
		}
	} else {
		// Validate cron expression
		parser := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)
		if _, err := parser.Parse(trigger); err != nil {
			f.err = fmt.Sprintf("Invalid cron expression: %v", err)
			return *m, nil
		}
	}

	soundPath := strings.TrimSpace(f.fields[fieldSound])
	if soundPath == "" {
		soundPath = "default"
	}

	alarm := db.Alarm{
		Name:        name,
		Description: strings.TrimSpace(f.fields[fieldDescription]),
		Time:        timeStr,
		Trigger:     trigger,
		SoundPath:   soundPath,
		Enabled:     true,
	}

	if f.editing != nil {
		alarm.ID = f.editing.ID
		alarm.Enabled = f.editing.Enabled
		if err := m.alarmStore.UpdateAlarm(alarm); err != nil {
			f.err = fmt.Sprintf("Save failed: %v", err)
			return *m, nil
		}
		m.statusMsg = "Alarm updated"
	} else {
		if _, err := m.alarmStore.CreateAlarm(alarm); err != nil {
			f.err = fmt.Sprintf("Save failed: %v", err)
			return *m, nil
		}
		m.statusMsg = "Alarm created"
	}

	m.refreshAlarms()
	m.mode = viewMain
	m.form = nil
	return *m, nil
}

const (
	formLabelWidth = 14 // longest label is "Time (HH:MM):" = 13 + 1 padding
	formValueWidth = 30
	formHintWidth  = 32
)

func (f *formModel) View() string {
	title := "Add Alarm"
	if f.editing != nil {
		title = "Edit Alarm"
	}

	labels := [fieldCount]string{
		"Name:",
		"Description:",
		"Time (HH:MM):",
		"Trigger:",
		"Sound:",
	}

	hints := [fieldCount]string{
		"",
		"(optional)",
		"e.g. 07:30",
		"'once' or cron: 30 7 * * 1-5",
		"'default' or path to sound file",
	}

	var lines []string
	lines = append(lines, TitleStyle.Render(title), "")

	for i := formField(0); i < fieldCount; i++ {
		// Right-align labels in a fixed-width column
		labelStr := fmt.Sprintf("%*s", formLabelWidth, labels[i])

		value := f.fields[i]
		var style lipgloss.Style
		if i == f.active {
			style = FormActiveStyle
			value += "█"
		} else {
			style = FormLabelStyle
		}

		// Truncate from the left if too long, then pad to fixed width
		if len(value) > formValueWidth {
			value = value[len(value)-formValueWidth:]
		}
		valueStr := fmt.Sprintf("%-*s", formValueWidth, value)

		hintStr := fmt.Sprintf("%-*s", formHintWidth, hints[i])

		line := FormLabelStyle.Render(labelStr) + " " + style.Render(valueStr) + " " + HelpStyle.Render(hintStr)
		lines = append(lines, line)
	}

	if f.err != "" {
		lines = append(lines, "", FormErrorStyle.Render("  Error: "+f.err))
	}

	return strings.Join(lines, "\n")
}

func isValidTime(s string) bool {
	if len(s) != 5 || s[2] != ':' {
		return false
	}
	h := (s[0]-'0')*10 + (s[1] - '0')
	m := (s[3]-'0')*10 + (s[4] - '0')
	return h <= 23 && m <= 59 && s[0] >= '0' && s[0] <= '9' &&
		s[1] >= '0' && s[1] <= '9' && s[3] >= '0' && s[3] <= '9' &&
		s[4] >= '0' && s[4] <= '9'
}
