package compiler

import (
	"c65gm/internal/preproc"

	"go.starlark.net/starlark"
)

// ScriptMacro represents a named, parameterized script macro
type ScriptMacro struct {
	Name       string   // macro name
	Params     []string // parameter names
	Body       []string // Starlark code lines (the macro body)
	SourceFile string   // source file where macro is defined
	StartLine  int      // 1-based line number in source file of first body line
}

// CompilerContext holds all shared resources needed by commands during compilation
type CompilerContext struct {
	// Symbol table for variables and constants
	SymbolTable *SymbolTable

	// Function handler for FUNC/CALL/FEND commands
	FunctionHandler *FunctionHandler

	// Constant string handler
	ConstStrHandler *ConstantStringHandler

	// Label stacks for control flow
	LoopStartStack *LabelStack  // Start of loop (like WHILE)
	LoopEndStack   *LabelStack  // WHILE...WEND
	IfStack        *LabelStack  // IF...ENDIF
	GeneralStack   *LabelStack  // General purpose (GOSUB, etc)
	ForStack       *ForStack    // For loop stack
	SwitchStack    *SwitchStack // Switch/case stack
	CaseSkipStack  *LabelStack  // SWITCH/CASE skip labels

	// Pragma access for per-line pragma lookup
	Pragma *preproc.Pragma

	// ScriptLibraryGlobals holds persisted Starlark globals from SCRIPT LIBRARY blocks
	ScriptLibraryGlobals starlark.StringDict

	// ScriptMacros holds named macro definitions from SCRIPT MACRO blocks
	ScriptMacros map[string]*ScriptMacro

	// ProjectRoot is the absolute path of the directory containing the main input .c65 file.
	// Used by scripting built-ins (load_binary, load_text) to resolve relative file paths
	// and enforce security (no access outside project root).
	ProjectRoot string
}

// NewCompilerContext creates a new compiler context with initialized resources
func NewCompilerContext(pragma *preproc.Pragma) *CompilerContext {
	symTable := NewSymbolTable()
	constStrHandler := NewConstantStringHandler()
	generalStack := NewLabelStack("_L")

	ctx := &CompilerContext{
		SymbolTable:          symTable,
		ConstStrHandler:      constStrHandler,
		LoopStartStack:       NewLabelStack("_LOOPSTART"),
		LoopEndStack:         NewLabelStack("_LOOPEND"),
		IfStack:              NewLabelStack("_I"),
		GeneralStack:         generalStack,
		ForStack:             NewForStack(),
		SwitchStack:          NewSwitchStack(),
		CaseSkipStack:        NewLabelStack("_SKIPCASE"),
		Pragma:               pragma,
		ScriptLibraryGlobals: make(starlark.StringDict),
		ScriptMacros:         make(map[string]*ScriptMacro),
	}

	// FunctionHandler needs references to other components
	ctx.FunctionHandler = NewFunctionHandler(symTable, generalStack, constStrHandler, pragma)

	// Connect SymbolTable to FunctionHandler for absolute variable notifications
	symTable.SetFunctionHandler(ctx.FunctionHandler)
	
	// Set pragma reference for pragma lookup during warning generation
	symTable.SetPragma(pragma)

	return ctx
}

// CurrentScope returns the current function scope(s) for symbol resolution
func (ctx *CompilerContext) CurrentScope() []string {
	funcName := ctx.FunctionHandler.CurrentFunction()
	if funcName == "" {
		return nil
	}
	return []string{funcName}
}
