package htmlanalyzer

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"
)

type Analyzer struct {
	detectors *detectors.Registry
}

func NewAnalyzer() *Analyzer {
	return NewAnalyzerWithDetectors(detectors.DefaultRegistry())
}

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

func (a *Analyzer) SupportedLanguages() []string {
	return []string{"html", "vue", "blade", "twig", "jinja", "thymeleaf"}
}

func (a *Analyzer) ParseFile(ctx context.Context, source []byte, filePath, language string) (*graph.Artifact, []contractevents.CodeChunk, error) {
	_ = ctx
	if language == "" {
		language = inferHTMLLanguage(filePath)
	}

	b := common.NewBuilder(filePath, language)
	lines := common.Lines(source)

	tagPattern := regexp.MustCompile(`<([a-zA-Z][a-zA-Z0-9-]*)`)
	idPattern := regexp.MustCompile(`\bid\s*=\s*["']([^"']+)["']`)
	classPattern := regexp.MustCompile(`\bclass\s*=\s*["']([^"']+)["']`)
	formPattern := regexp.MustCompile(`<form\b`)
	linkPattern := regexp.MustCompile(`<a\b[^>]*href\s*=\s*["']([^"']+)["']`)

	seenTags := make(map[string]struct{})
	for i, line := range lines {
		if formPattern.MatchString(line) {
			b.AddSymbol("form", contractevents.SymbolTypeType, i+1, i+1, map[string]string{"element": "form"})
		}
		if m := linkPattern.FindStringSubmatch(line); len(m) > 1 {
			b.AddRoute(m[1], "link", i+1, i+1, map[string]string{"element": "a"})
		}
		if m := idPattern.FindStringSubmatch(line); len(m) > 1 {
			b.AddSymbol("#"+m[1], contractevents.SymbolTypeVariable, i+1, i+1, map[string]string{"element_id": m[1]})
		}
		if m := classPattern.FindStringSubmatch(line); len(m) > 1 {
			for _, cls := range strings.Fields(m[1]) {
				key := "." + cls
				if _, ok := seenTags[key]; ok {
					continue
				}
				seenTags[key] = struct{}{}
				b.AddSymbol(key, contractevents.SymbolTypeVariable, i+1, i+1, map[string]string{"class_name": cls})
			}
		}
		if m := tagPattern.FindStringSubmatch(line); len(m) > 1 {
			tag := m[1]
			if tag == "script" || tag == "style" {
				continue
			}
			if _, ok := seenTags[tag]; !ok {
				seenTags[tag] = struct{}{}
				b.AddSymbol(tag, contractevents.SymbolTypeType, i+1, i+1, map[string]string{"element": tag})
			}
		}
	}

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

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

func inferHTMLLanguage(filePath string) string {
	lower := strings.ToLower(filePath)
	switch {
	case strings.HasSuffix(lower, ".blade.php"):
		return "blade"
	case strings.HasSuffix(lower, ".twig"):
		return "twig"
	case strings.HasSuffix(lower, ".vue"):
		return "vue"
	default:
		return "html"
	}
}
