package dart

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"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/detectors"
)

// Analyzer parses Dart source files, including Flutter widget classes.
type Analyzer struct {
	detectors *detectors.Registry
}

func NewAnalyzer(det *detectors.Registry) *Analyzer {
	if det == nil {
		det = detectors.DefaultRegistry()
	}
	return &Analyzer{detectors: det}
}

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

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

	importPattern := regexp.MustCompile(`^\s*(?:import|export|part)\s+['"]([^'"]+)['"]`)
	classPattern := regexp.MustCompile(`^\s*(?:(?:abstract|base|final|interface|sealed)\s+)*class\s+([A-Za-z_][A-Za-z0-9_]*)`)
	enumPattern := regexp.MustCompile(`^\s*enum\s+([A-Za-z_][A-Za-z0-9_]*)`)
	mixinPattern := regexp.MustCompile(`^\s*mixin\s+([A-Za-z_][A-Za-z0-9_]*)`)
	funcPattern := regexp.MustCompile(`^\s*(?:static\s+)?(?:[A-Za-z_<>,?\[\]\s]+\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*(?:<[^>]+>)?\s*\([^;{}]*\)\s*(?:async\s*)?(?:\{|=>)`)

	for i, line := range lines {
		trimmed := strings.TrimSpace(line)
		if m := importPattern.FindStringSubmatch(line); len(m) > 1 {
			b.AddImport(m[1], i+1)
		}
		if m := classPattern.FindStringSubmatch(line); len(m) > 1 {
			end := findBraceBlockEnd(lines, i)
			b.AddSymbol(m[1], contractevents.SymbolTypeType, i+1, end, map[string]string{"type_kind": "class"})
		}
		if m := enumPattern.FindStringSubmatch(line); len(m) > 1 {
			end := findBraceBlockEnd(lines, i)
			b.AddSymbol(m[1], contractevents.SymbolTypeType, i+1, end, map[string]string{"type_kind": "enum"})
		}
		if m := mixinPattern.FindStringSubmatch(line); len(m) > 1 {
			end := findBraceBlockEnd(lines, i)
			b.AddSymbol(m[1], contractevents.SymbolTypeType, i+1, end, map[string]string{"type_kind": "mixin"})
		}
		if m := funcPattern.FindStringSubmatch(line); len(m) > 1 {
			name := m[1]
			if isDartControlKeyword(name) || strings.HasPrefix(trimmed, "class ") || strings.HasPrefix(trimmed, "enum ") {
				continue
			}
			symbolType := contractevents.SymbolTypeFunction
			if leadingIndent(line) > 0 || strings.HasPrefix(trimmed, "static ") {
				symbolType = contractevents.SymbolTypeMethod
			}
			end := findBraceBlockEnd(lines, i)
			b.AddSymbol(name, symbolType, i+1, end, nil)
		}
	}

	a.detectors.ApplyAll(detectors.Context{
		Source:   source,
		FilePath: filePath,
		Language: "dart",
		Builder:  b,
	})

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

func findBraceBlockEnd(lines []string, start int) int {
	depth := 0
	started := false
	for i := start; i < len(lines); i++ {
		for _, ch := range lines[i] {
			switch ch {
			case '{':
				depth++
				started = true
			case '}':
				depth--
				if started && depth == 0 {
					return i + 1
				}
			}
		}
	}
	return start + 1
}

func leadingIndent(line string) int {
	n := 0
	for _, ch := range line {
		if ch == ' ' {
			n++
		} else if ch == '\t' {
			n += 4
		} else {
			break
		}
	}
	return n
}

func isDartControlKeyword(name string) bool {
	switch name {
	case "if", "for", "while", "switch", "catch", "assert", "return":
		return true
	default:
		return false
	}
}
