package ted

import (
	"encoding/xml"
	"fmt"
	"strings"
	"tm/pkg/xmlparser"
)

type TEDParser struct {
	ContractNotice         xmlparser.Parser[ContractNotice]
	ContractAwardNotice    xmlparser.Parser[ContractAwardNotice]
	PriorInformationNotice xmlparser.Parser[PriorInformationNotice]
	// BusinessRegistrationInformationNotice xmlparser.Parser[BusinessRegistrationInformationNotice]
}

// NewTEDParser creates a new TED parser
func NewTEDParser() *TEDParser {
	options := xmlparser.DefaultParserOptions()
	options.MaxSize = 50 * 1024 * 1024   // 50MB limit for TED XML files
	options.IgnoreUnknownElements = true // TED XML has many optional fields

	contractNoticeParser := xmlparser.NewParser[ContractNotice](options)
	contractAwardNoticeParser := xmlparser.NewParser[ContractAwardNotice](options)
	priorInformationNoticeParser := xmlparser.NewParser[PriorInformationNotice](options)
	// businessRegistrationInformationNoticeParser := xmlparser.NewParser[BusinessRegistrationInformationNotice](options)

	return &TEDParser{
		ContractNotice:         contractNoticeParser,
		ContractAwardNotice:    contractAwardNoticeParser,
		PriorInformationNotice: priorInformationNoticeParser,
		// BusinessRegistrationInformationNotice: businessRegistrationInformationNoticeParser,
	}
}

// ParseXML automatically detects and parses any supported TED XML document type
func (p *TEDParser) ParseXML(content []byte) (*ParsedDocument, string, DocumentType, error) {
	// First, detect the root element type
	rootElement, err := detectRootElement(content)
	if err != nil {
		return nil, "", DocumentType(""), fmt.Errorf("failed to detect root element: %w", err)
	}

	parsedDoc := &ParsedDocument{Type: DocumentType(rootElement)}

	switch parsedDoc.Type {
	case DocumentTypeContractNotice:
		notice, err := p.ContractNotice.ParseBytes(content)
		if err != nil {
			return nil, "", DocumentType(""), fmt.Errorf("failed to parse contract notice: %w", err)
		}
		parsedDoc.ContractNotice = notice
		return parsedDoc, notice.GetID(), parsedDoc.Type, nil

	case DocumentTypeContractAwardNotice:
		notice, err := p.ContractAwardNotice.ParseBytes(content)
		if err != nil {
			return nil, "", DocumentType(""), fmt.Errorf("failed to parse contract award notice: %w", err)
		}
		parsedDoc.ContractAwardNotice = notice
		return parsedDoc, notice.GetID(), parsedDoc.Type, nil

	case DocumentTypePriorInformationNotice:
		notice, err := p.PriorInformationNotice.ParseBytes(content)
		if err != nil {
			return nil, "", DocumentType(""), fmt.Errorf("failed to parse prior information notice: %w", err)
		}
		parsedDoc.PriorInformationNotice = notice
		return parsedDoc, notice.GetID(), parsedDoc.Type, nil
	default:
		return nil, "", DocumentType(""), fmt.Errorf("unsupported document type: %s", parsedDoc.Type)
	}
}

// detectRootElement detects the root XML element name
func detectRootElement(content []byte) (string, error) {
	decoder := xml.NewDecoder(strings.NewReader(string(content)))
	for {
		token, err := decoder.Token()
		if err != nil {
			return "", err
		}
		if startElement, ok := token.(xml.StartElement); ok {
			return startElement.Name.Local, nil
		}
	}
}
