package command

import (
	"fmt"
	"strings"

	"git.gophernest.net/azpect/TextEditor/internal/action"
	tea "github.com/charmbracelet/bubbletea"
)

// Command represents a command that can be executed from command mode
type Command struct {
	Name      string                                      // Full name: "quit"
	ShortForm string                                      // Minimum abbreviation: "q"
	Handler   func(m action.Model, args []string) tea.Cmd // Handler function
}

// Registry holds all registered commands
type Registry struct {
	commands []Command
}

// NewRegistry creates a new command registry with default commands
func NewRegistry() *Registry {
	r := &Registry{}
	r.registerDefaults()
	return r
}

// Register adds a command to the registry
func (r *Registry) Register(cmd Command) {
	r.commands = append(r.commands, cmd)
}

// Lookup finds a command by name or abbreviation
// Returns the command and any error (unknown or ambiguous)
func (r *Registry) Lookup(input string) (*Command, error) {
	if input == "" {
		return nil, fmt.Errorf("no command given")
	}

	var matches []*Command

	for i := range r.commands {
		cmd := &r.commands[i]

		// Exact match on short form
		if input == cmd.ShortForm {
			return cmd, nil
		}

		// Exact match on full name
		if input == cmd.Name {
			return cmd, nil
		}

		// Prefix match: input must be at least as long as short form
		// and must be a prefix of the full name
		if len(input) >= len(cmd.ShortForm) && strings.HasPrefix(cmd.Name, input) {
			matches = append(matches, cmd)
		}
	}

	if len(matches) == 0 {
		return nil, fmt.Errorf("unknown command: %s", input)
	}
	if len(matches) > 1 {
		names := make([]string, len(matches))
		for i, m := range matches {
			names[i] = m.Name
		}
		return nil, fmt.Errorf("ambiguous command: %s (could be: %s)", input, strings.Join(names, ", "))
	}

	return matches[0], nil
}

// Parse splits a command line into command name and arguments
func Parse(cmdLine string) (name string, args []string) {
	parts := strings.Fields(cmdLine)
	if len(parts) == 0 {
		return "", nil
	}
	return parts[0], parts[1:]
}

// Execute parses and executes a command line
func (r *Registry) Execute(m action.Model, cmdLine string) (tea.Cmd, error) {
	name, args := Parse(cmdLine)

	cmd, err := r.Lookup(name)
	if err != nil {
		return nil, err
	}

	return cmd.Handler(m, args), nil
}

// DefaultRegistry is the global command registry
var DefaultRegistry = NewRegistry()

// registerDefaults registers the built-in commands
func (r *Registry) registerDefaults() {
	// Quit commands
	r.Register(Command{
		Name:      "quit",
		ShortForm: "q",
		Handler:   cmdQuit,
	})

	r.Register(Command{
		Name:      "qall",
		ShortForm: "qa",
		Handler:   cmdQuitAll,
	})

	// Write commands
	r.Register(Command{
		Name:      "write",
		ShortForm: "w",
		Handler:   cmdWrite,
	})

	r.Register(Command{
		Name:      "wall",
		ShortForm: "wa",
		Handler:   cmdWriteAll,
	})

	r.Register(Command{
		Name:      "wq",
		ShortForm: "wq",
		Handler:   cmdWriteQuit,
	})

	// Set command
	r.Register(Command{
		Name:      "set",
		ShortForm: "se",
		Handler:   cmdSet,
	})

	// Register commands
	r.Register(Command{
		Name:      "register",
		ShortForm: "reg",
		Handler:   cmdRegisters,
	})
}
