package parser

import (
	"fmt"
	"sort"
	"sync"
)

var (
	registry     = make(map[string]VendorParser)
	registryLock sync.RWMutex
)

// Register adds a vendor parser to the registry
// Called from vendor module init() functions
func Register(p VendorParser) {
	registryLock.Lock()
	defer registryLock.Unlock()

	vendor := p.Vendor()
	if _, exists := registry[vendor]; exists {
		panic(fmt.Sprintf("parser already registered for vendor: %s", vendor))
	}
	registry[vendor] = p
}

// GetParser returns parser for specific vendor
func GetParser(vendor string) (VendorParser, bool) {
	registryLock.RLock()
	defer registryLock.RUnlock()

	p, ok := registry[vendor]
	return p, ok
}

// ListParsers returns list of all registered vendor names
func ListParsers() []string {
	registryLock.RLock()
	defer registryLock.RUnlock()

	vendors := make([]string, 0, len(registry))
	for v := range registry {
		vendors = append(vendors, v)
	}
	sort.Strings(vendors)
	return vendors
}

// ParserInfo contains information about a registered parser
type ParserInfo struct {
	Vendor  string `json:"vendor"`
	Name    string `json:"name"`
	Version string `json:"version"`
}

// ListParsersInfo returns detailed info about all registered parsers
func ListParsersInfo() []ParserInfo {
	registryLock.RLock()
	defer registryLock.RUnlock()

	parsers := make([]ParserInfo, 0, len(registry))
	for _, p := range registry {
		parsers = append(parsers, ParserInfo{
			Vendor:  p.Vendor(),
			Name:    p.Name(),
			Version: p.Version(),
		})
	}

	// Sort by vendor name
	sort.Slice(parsers, func(i, j int) bool {
		return parsers[i].Vendor < parsers[j].Vendor
	})

	return parsers
}

// DetectResult holds detection result for a parser
type DetectResult struct {
	Parser     VendorParser
	Confidence int
}

// DetectFormat tries to detect archive format and returns best matching parser
func DetectFormat(files []ExtractedFile) (VendorParser, error) {
	registryLock.RLock()
	defer registryLock.RUnlock()

	var results []DetectResult

	for _, p := range registry {
		confidence := p.Detect(files)
		if confidence > 0 {
			results = append(results, DetectResult{
				Parser:     p,
				Confidence: confidence,
			})
		}
	}

	if len(results) == 0 {
		return nil, fmt.Errorf("no parser found for this archive format")
	}

	// Sort by confidence descending
	sort.Slice(results, func(i, j int) bool {
		return results[i].Confidence > results[j].Confidence
	})

	return results[0].Parser, nil
}

// DetectAllFormats returns all parsers that can handle the files with their confidence
func DetectAllFormats(files []ExtractedFile) []DetectResult {
	registryLock.RLock()
	defer registryLock.RUnlock()

	var results []DetectResult

	for _, p := range registry {
		confidence := p.Detect(files)
		if confidence > 0 {
			results = append(results, DetectResult{
				Parser:     p,
				Confidence: confidence,
			})
		}
	}

	sort.Slice(results, func(i, j int) bool {
		return results[i].Confidence > results[j].Confidence
	})

	return results
}
