package interactive

import (
	"fmt"
	"strings"

	"git.solsynth.dev/goatworks/turbine/pkg/launchpad/config"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
)

var (
	titleStyle = lipgloss.NewStyle().
			Background(lipgloss.Color("62")).
			Foreground(lipgloss.Color("230")).
			Padding(0, 1)

	helpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241"))
)

type model struct {
	services      []config.Service
	cursor        int
	selected      map[int]struct{}
	startServices bool
}

func initialModel(services []config.Service) model {
	selected := make(map[int]struct{})
	for i := range services {
		selected[i] = struct{}{}
	}
	return model{
		services: services,
		selected: selected,
	}
}

func (m model) Init() tea.Cmd {
	return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch msg.String() {
		case "ctrl+c", "q":
			return m, tea.Quit

		case "up", "k":
			if m.cursor > 0 {
				m.cursor--
			}

		case "down", "j":
			if m.cursor < len(m.services)-1 {
				m.cursor++
			}

		case " ":
			if _, ok := m.selected[m.cursor]; ok {
				delete(m.selected, m.cursor)
			} else {
				m.selected[m.cursor] = struct{}{}
			}
		case "enter":
			m.startServices = true
			return m, tea.Quit
		}
	}
	return m, nil
}

func (m model) View() string {
	var b strings.Builder

	b.WriteString(titleStyle.Render("Select services to start"))
	b.WriteString("\n\n")

	for i, service := range m.services {
		cursor := " "
		if m.cursor == i {
			cursor = ">"
		}

		checked := " "
		if _, ok := m.selected[i]; ok {
			checked = "x"
		}

		b.WriteString(fmt.Sprintf("%s [%s] %s\n", cursor, checked, service.Name))
	}

	b.WriteString("\n")
	b.WriteString(helpStyle.Render("Use up/down to navigate, space to select, enter to start, q to quit."))

	return b.String()
}

func (m model) SelectedServices() []config.Service {
	var selectedServices []config.Service
	for i := range m.selected {
		selectedServices = append(selectedServices, m.services[i])
	}
	return selectedServices
}

func SelectServices(services []config.Service) ([]config.Service, error) {
	if len(services) == 0 {
		return nil, fmt.Errorf("no services defined in launchpad.toml")
	}
	m := initialModel(services)
	p := tea.NewProgram(m)

	finalModel, err := p.Run()
	if err != nil {
		return nil, err
	}

	fm := finalModel.(model)
	if fm.startServices {
		return fm.SelectedServices(), nil
	}

	return nil, nil // User quit
}
