package registry

import (
	"context"

	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"
	cssanalyzer "bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/css"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/dart"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/detectors"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/fallback"
	htmlanalyzer "bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/html"
	javaanalyzer "bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/java"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/javascript"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/lua"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/php"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/analyzers/python"
	goparser "bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/service/parser/go"
)

// Options controls analyzer registry construction.
type Options struct {
	EnableFallback bool
}

// BuiltRegistry contains language analyzers and optional fallback parser.
type BuiltRegistry struct {
	Analyzers []parser.LanguageAnalyzer
	Fallback  parser.FallbackAnalyzer
}

// multiLangParser is implemented by analyzers that accept an explicit language at parse time.
type multiLangParser interface {
	ParseFile(ctx context.Context, source []byte, filePath, language string) (*graph.Artifact, []contractevents.CodeChunk, error)
	SupportedLanguages() []string
}

// Build constructs the full analyzer registry from a single place.
func Build(opts Options) BuiltRegistry {
	det := detectors.DefaultRegistry()

	parsers := []multiLangParser{
		wrapGo(goparser.NewAnalyzer()),
		javascript.NewAnalyzer(det),
		python.NewAnalyzer(det),
		javaanalyzer.NewAnalyzer(det),
		php.NewAnalyzer(det),
		htmlanalyzer.NewAnalyzer(),
		cssanalyzer.NewAnalyzer(),
		dart.NewAnalyzer(det),
		lua.NewAnalyzer(),
	}

	var analyzers []parser.LanguageAnalyzer
	for _, p := range parsers {
		for _, lang := range p.SupportedLanguages() {
			analyzers = append(analyzers, newLanguageAdapter(lang, p))
		}
	}

	var fb parser.FallbackAnalyzer
	if opts.EnableFallback {
		fb = fallback.NewAnalyzer()
	}

	return BuiltRegistry{
		Analyzers: analyzers,
		Fallback:  fb,
	}
}

type goWrapper struct {
	inner *goparser.Analyzer
}

func wrapGo(a *goparser.Analyzer) multiLangParser {
	return &goWrapper{inner: a}
}

func (g *goWrapper) SupportedLanguages() []string { return []string{"go"} }

func (g *goWrapper) ParseFile(ctx context.Context, source []byte, filePath, language string) (*graph.Artifact, []contractevents.CodeChunk, error) {
	return g.inner.ParseFile(ctx, source, filePath)
}

type languageAdapter struct {
	language string
	parser   multiLangParser
}

func newLanguageAdapter(language string, parser multiLangParser) parser.LanguageAnalyzer {
	return &languageAdapter{language: language, parser: parser}
}

func (a *languageAdapter) SupportedLanguage() string { return a.language }

func (a *languageAdapter) ParseFile(ctx context.Context, source []byte, filePath string) (*graph.Artifact, []contractevents.CodeChunk, error) {
	return a.parser.ParseFile(ctx, source, filePath, a.language)
}
