package command

import (
	"context"
	"fmt"
	"strings"
)

// CommandContext carries execution context for a sub-command.
type CommandContext struct {
	Ctx   context.Context
	BotID string
	Role  string // "owner", "admin", "member", or "" (guest)
	Args  []string
}

// SubCommand describes a single sub-command within a resource group.
type SubCommand struct {
	Name    string
	Usage   string
	IsWrite bool
	Handler func(cc CommandContext) (string, error)
}

// CommandGroup groups sub-commands under a resource name.
type CommandGroup struct {
	Name          string
	Description   string
	DefaultAction string
	commands      map[string]SubCommand
	order         []string // preserves registration order for help output
}

func newCommandGroup(name, description string) *CommandGroup {
	return &CommandGroup{
		Name:        name,
		Description: description,
		commands:    make(map[string]SubCommand),
	}
}

func (g *CommandGroup) Register(sub SubCommand) {
	g.commands[sub.Name] = sub
	g.order = append(g.order, sub.Name)
}

// Usage returns the usage text for this resource group.
func (g *CommandGroup) Usage() string {
	var b strings.Builder
	fmt.Fprintf(&b, "/%s - %s\n", g.Name, g.Description)
	for _, name := range g.order {
		sub := g.commands[name]
		perm := ""
		if sub.IsWrite {
			perm = " [owner]"
		}
		fmt.Fprintf(&b, "- %s%s\n", sub.Usage, perm)
	}
	return b.String()
}

// Registry holds all registered command groups.
type Registry struct {
	groups map[string]*CommandGroup
	order  []string
}

func newRegistry() *Registry {
	return &Registry{
		groups: make(map[string]*CommandGroup),
	}
}

func (r *Registry) RegisterGroup(group *CommandGroup) {
	r.groups[group.Name] = group
	r.order = append(r.order, group.Name)
}

// GlobalHelp returns the top-level help text listing all commands.
func (r *Registry) GlobalHelp() string {
	var b strings.Builder
	b.WriteString("Available commands:\n\n")
	b.WriteString("/help - Show this help message\n")
	b.WriteString("/new - Start a new conversation (resets session context)\n\n")
	for i, name := range r.order {
		if i > 0 {
			b.WriteByte('\n')
		}
		group := r.groups[name]
		b.WriteString(group.Usage())
	}
	return strings.TrimRight(b.String(), "\n")
}
