package cmds

import (
	"agent/client/events"
	"agent/defines/derrs"
	"context"
	"fmt"
	"strings"
)

func NewCommandManager() *CommandManager {
	return &CommandManager{
		commands: map[string]ICommand{},
	}
}

type CommandManager struct {
	commands map[string]ICommand
}

func (c *CommandManager) Add(ctx context.Context, cmd ICommand) (err error) {
	path := c.path(cmd)
	if _, ok := c.commands[path]; ok {
		return derrs.NewExistError(fmt.Sprintf(`command "%s" already exists`, path))
	}
	c.commands[path] = cmd
	return nil
}

func (c *CommandManager) Execute(ctx context.Context, eventIn events.IEvent) (eventOut events.IEvent, err error) {
	cmd, ok := c.get(eventIn)
	if !ok {
		return nil, derrs.NewCommandNotFoundError(fmt.Sprintf(`command "%s" not found`, eventIn.Signature()))
	}
	return cmd.Execute(ctx, eventIn)
}

func (c *CommandManager) get(sig ICommandSignature) (ICommand, bool) {
	if cmd, ok := c.commands[c.path(sig)]; ok {
		return cmd, true
	}
	return nil, false
}

func (c *CommandManager) path(sig ICommandSignature) string {
	var sb strings.Builder
	sb.WriteString(fmt.Sprintf("%d", sig.Kind()))
	sb.WriteString(fmt.Sprintf(".%d", sig.Action()))
	for _, val := range sig.Category() {
		sb.WriteString(fmt.Sprintf(".%d", val))
	}
	return sb.String()
}
