package commands

import (
	"strings"

	"c65gm/internal/compiler"
	"c65gm/internal/preproc"
	"c65gm/internal/utils"
)

// CallCommand handles function calls
// Syntax:
//
//	CALL funcname                          # void call
//	CALL funcname ( arg1 arg2 )            # call with arguments
//	funcname                               # implicit call syntax
//	funcname ( arg1 arg2 )                 # implicit call with args
//
// Arguments can be:
//   - Variables: varname
//   - Constants: 123, $FF
//   - Labels: @labelname
//   - Strings: "text"
type CallCommand struct {
	funcHandler *compiler.FunctionHandler
	asmOutput   []string
}

// NewCallCommand creates a CallCommand with access to function registry
func NewCallCommand(funcHandler *compiler.FunctionHandler) *CallCommand {
	return &CallCommand{
		funcHandler: funcHandler,
	}
}

func (c *CallCommand) WillHandle(line preproc.Line) bool {
	params, err := utils.ParseParams(line.Text)
	if err != nil || len(params) == 0 {
		return false
	}

	// Check if starts with CALL keyword
	if strings.ToUpper(params[0]) == "CALL" {
		return true
	}

	// Check if first token is a declared function
	if c.funcHandler.FuncExists(params[0]) {
		return true
	}

	// For intuitive syntax like "funcname(args)", extract function name
	// by looking for '(' and taking everything before it
	firstToken := params[0]
	if idx := strings.IndexByte(firstToken, '('); idx > 0 {
		funcName := firstToken[:idx]
		return c.funcHandler.FuncExists(funcName)
	}

	return false
}

func (c *CallCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext) error {
	c.asmOutput = nil

	asm, err := ctx.FunctionHandler.HandleFuncCall(line)
	if err != nil {
		return err
	}

	c.asmOutput = asm
	return nil
}

func (c *CallCommand) Generate(_ *compiler.CompilerContext) ([]string, error) {
	return c.asmOutput, nil
}

func (c *CallCommand) GetClass() compiler.CmdClass { return compiler.CmdLinear }
func (c *CallCommand) GetName() string             { return "CALL" }
