package lua

import (
	"context"
	"regexp"
	"strings"

	contractevents "bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/contracts/events"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/contracts/graph"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/common"
)

// Analyzer parses Lua source files.
type Analyzer struct{}

func NewAnalyzer() *Analyzer {
	return &Analyzer{}
}

func (a *Analyzer) SupportedLanguages() []string {
	return []string{"lua"}
}

func (a *Analyzer) ParseFile(ctx context.Context, source []byte, filePath, language string) (*graph.Artifact, []contractevents.CodeChunk, error) {
	_ = ctx
	b := common.NewBuilder(filePath, "lua")
	lines := common.Lines(source)

	requirePattern := regexp.MustCompile(`(?:^|\s)(?:local\s+[\w_]+\s*=\s*)?require\s*\(?\s*["']([^"']+)["']`)
	functionPattern := regexp.MustCompile(`^\s*(?:local\s+)?function\s+([A-Za-z_][A-Za-z0-9_.:]*)\s*\(`)
	assignmentFunctionPattern := regexp.MustCompile(`^\s*(?:local\s+)?([A-Za-z_][A-Za-z0-9_.:]*)\s*=\s*function\s*\(`)
	tablePattern := regexp.MustCompile(`^\s*(?:local\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\{`)

	for i, line := range lines {
		trimmed := strings.TrimSpace(line)
		if m := requirePattern.FindStringSubmatch(line); len(m) > 1 {
			b.AddImport(m[1], i+1)
		}
		if m := tablePattern.FindStringSubmatch(line); len(m) > 1 {
			b.AddSymbol(m[1], contractevents.SymbolTypeType, i+1, findLuaBlockEnd(lines, i), map[string]string{"type_kind": "table"})
		}
		if m := functionPattern.FindStringSubmatch(line); len(m) > 1 {
			name := normalizeLuaSymbolName(m[1])
			b.AddSymbol(name, luaSymbolType(m[1]), i+1, findLuaBlockEnd(lines, i), nil)
		}
		if m := assignmentFunctionPattern.FindStringSubmatch(line); len(m) > 1 {
			if strings.HasPrefix(trimmed, "if ") || strings.HasPrefix(trimmed, "for ") || strings.HasPrefix(trimmed, "while ") {
				continue
			}
			name := normalizeLuaSymbolName(m[1])
			b.AddSymbol(name, luaSymbolType(m[1]), i+1, findLuaBlockEnd(lines, i), nil)
		}
	}

	b.EnsureLineWindowChunks(source)
	return b.Artifact(), b.Chunks(), nil
}

func normalizeLuaSymbolName(name string) string {
	if idx := strings.LastIndexAny(name, ".:"); idx >= 0 && idx < len(name)-1 {
		return name[idx+1:]
	}
	return name
}

func luaSymbolType(name string) contractevents.SymbolType {
	if strings.ContainsAny(name, ".:") {
		return contractevents.SymbolTypeMethod
	}
	return contractevents.SymbolTypeFunction
}

func findLuaBlockEnd(lines []string, start int) int {
	depth := 0
	started := false
	for i := start; i < len(lines); i++ {
		trimmed := strings.TrimSpace(lines[i])
		if trimmed == "" || strings.HasPrefix(trimmed, "--") {
			continue
		}
		if opensLuaBlock(trimmed) {
			depth++
			started = true
		}
		if trimmed == "end" || strings.HasPrefix(trimmed, "end ") || strings.HasPrefix(trimmed, "end--") {
			depth--
			if started && depth <= 0 {
				return i + 1
			}
		}
	}
	return start + 1
}

func opensLuaBlock(trimmed string) bool {
	switch {
	case strings.HasPrefix(trimmed, "function "),
		strings.Contains(trimmed, "= function("),
		strings.Contains(trimmed, "= function ("),
		strings.HasPrefix(trimmed, "if ") && strings.Contains(trimmed, " then"),
		strings.HasPrefix(trimmed, "for ") && strings.Contains(trimmed, " do"),
		strings.HasPrefix(trimmed, "while ") && strings.Contains(trimmed, " do"),
		strings.HasPrefix(trimmed, "repeat"):
		return true
	default:
		return false
	}
}
