package packets

import (
	"embed"
	"eq2emu/internal/packets/parser"
	"fmt"
	"log"
	"path"
	"strings"
	"sync"
)

//go:embed xml/**/*.xml
var xmlFiles embed.FS

var (
	loadedPackets = make(map[string]*parser.PacketDef)
	loadedMutex   sync.RWMutex
	loadError     error
)

func init() {
	err := loadAllPackets()
	if err != nil {
		loadError = err
		log.Printf("Failed to load packet definitions: %v", err)
	}
}

func loadAllPackets() error {
	entries, err := xmlFiles.ReadDir("xml")
	if err != nil {
		return fmt.Errorf("failed to read xml directory: %w", err)
	}

	packets := make(map[string]*parser.PacketDef)

	for _, entry := range entries {
		if !entry.IsDir() {
			continue
		}

		dirPath := path.Join("xml", entry.Name())
		err := processDirectory(dirPath, packets)
		if err != nil {
			return fmt.Errorf("failed to process directory %s: %w", entry.Name(), err)
		}
	}

	loadedMutex.Lock()
	loadedPackets = packets
	loadedMutex.Unlock()

	log.Printf("Loaded %d packet definitions", len(packets))
	return nil
}

func processDirectory(dirPath string, packets map[string]*parser.PacketDef) error {
	entries, err := xmlFiles.ReadDir(dirPath)
	if err != nil {
		return err
	}

	for _, entry := range entries {
		entryPath := path.Join(dirPath, entry.Name())

		if entry.IsDir() {
			err := processDirectory(entryPath, packets)
			if err != nil {
				return err
			}
			continue
		}

		if !strings.HasSuffix(entry.Name(), ".xml") {
			continue
		}

		err := processXMLFile(entryPath, packets)
		if err != nil {
			log.Printf("Warning: failed to process %s: %v", entryPath, err)
		}
	}

	return nil
}

func processXMLFile(filePath string, packets map[string]*parser.PacketDef) error {
	content, err := xmlFiles.ReadFile(filePath)
	if err != nil {
		return fmt.Errorf("failed to read file: %w", err)
	}

	parsedPackets, err := parser.Parse(string(content))
	if err != nil {
		return fmt.Errorf("failed to parse XML: %w", err)
	}

	for name, packet := range parsedPackets {
		if existing, exists := packets[name]; exists {
			log.Printf("Warning: packet '%s' already exists, overwriting", name)
			_ = existing
		}
		packets[name] = packet
	}

	return nil
}

func GetPacket(name string) (*parser.PacketDef, bool) {
	if loadError != nil {
		return nil, false
	}

	loadedMutex.RLock()
	defer loadedMutex.RUnlock()

	packet, exists := loadedPackets[name]
	return packet, exists
}

func GetPacketNames() []string {
	if loadError != nil {
		return nil
	}

	loadedMutex.RLock()
	defer loadedMutex.RUnlock()

	names := make([]string, 0, len(loadedPackets))
	for name := range loadedPackets {
		names = append(names, name)
	}
	return names
}

func GetPacketCount() int {
	if loadError != nil {
		return 0
	}

	loadedMutex.RLock()
	defer loadedMutex.RUnlock()

	return len(loadedPackets)
}
