package ted

import (
	"encoding/xml"
	"fmt"
	"time"
)

// DocumentType represents the type of TED document
type DocumentType string

// Document type constants for all supported TED XML notice types
const (
	DocumentTypeContractNotice            DocumentType = "ContractNotice"
	DocumentTypeContractAwardNotice       DocumentType = "ContractAwardNotice"
	DocumentTypePriorInformationNotice    DocumentType = "PriorInformationNotice"
	DocumentTypeDesignContest             DocumentType = "DesignContest"
	DocumentTypeCorrigendum               DocumentType = "Corrigendum"
	DocumentTypeModificationNotice        DocumentType = "ModificationNotice"
	DocumentTypeConcessionNotice          DocumentType = "ConcessionNotice"
	DocumentTypeQualificationSystemNotice DocumentType = "QualificationSystemNotice"
	DocumentTypePlanningNotice            DocumentType = "PlanningNotice"
	DocumentTypeCompetitionNotice         DocumentType = "CompetitionNotice"
	DocumentTypeResultNotice              DocumentType = "ResultNotice"
	DocumentTypeChangeNotice              DocumentType = "ChangeNotice"
	DocumentTypeVoluntaryExAnte           DocumentType = "VoluntaryExAnte"
	DocumentTypeSubcontractNotice         DocumentType = "SubcontractNotice"
)

// ParsedDocument wraps any TED document with type information
type ParsedDocument struct {
	Type                      DocumentType
	ContractNotice            *ContractNotice            `json:"contract_notice,omitempty"`
	ContractAwardNotice       *ContractAwardNotice       `json:"contract_award_notice,omitempty"`
	PriorInformationNotice    *PriorInformationNotice    `json:"prior_information_notice,omitempty"`
	DesignContest             *DesignContest             `json:"design_contest,omitempty"`
	QualificationSystemNotice *QualificationSystemNotice `json:"qualification_system_notice,omitempty"`
	ConcessionNotice          *ConcessionNotice          `json:"concession_notice,omitempty"`
	PlanningNotice            *PlanningNotice            `json:"planning_notice,omitempty"`
	CompetitionNotice         *CompetitionNotice         `json:"competition_notice,omitempty"`
	ResultNotice              *ResultNotice              `json:"result_notice,omitempty"`
	ChangeNotice              *ChangeNotice              `json:"change_notice,omitempty"`
	SubcontractNotice         *SubcontractNotice         `json:"subcontract_notice,omitempty"`
}

// GetDocument returns the underlying document interface
func (pd *ParsedDocument) GetDocument() TEDDocument {
	switch pd.Type {
	case DocumentTypeContractNotice:
		return pd.ContractNotice
	case DocumentTypeContractAwardNotice:
		return pd.ContractAwardNotice
	case DocumentTypePriorInformationNotice:
		return pd.PriorInformationNotice
	case DocumentTypeDesignContest:
		return pd.DesignContest
	case DocumentTypeQualificationSystemNotice:
		return pd.QualificationSystemNotice
	case DocumentTypeConcessionNotice:
		return pd.ConcessionNotice
	case DocumentTypePlanningNotice:
		return pd.PlanningNotice
	case DocumentTypeCompetitionNotice:
		return pd.CompetitionNotice
	case DocumentTypeResultNotice:
		return pd.ResultNotice
	case DocumentTypeChangeNotice:
		return pd.ChangeNotice
	case DocumentTypeSubcontractNotice:
		return pd.SubcontractNotice
	default:
		return nil
	}
}

// TEDDocument represents the common interface for all TED document types
type TEDDocument interface {
	GetID() string
	GetNoticeType() string
	GetLanguage() string
	Validate() error
}

// PriorInformationNotice represents a prior information notice
type PriorInformationNotice struct {
	XMLName                     xml.Name                      `xml:"PriorInformationNotice"`
	Xmlns                       string                        `xml:"xmlns,attr,omitempty"`
	XmlnsCac                    string                        `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc                    string                        `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac                   string                        `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc                   string                        `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext                  string                        `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt                    string                        `xml:"xmlns:ext,attr,omitempty"`
	UBLVersionID                string                        `xml:"UBLVersionID"`
	CustomizationID             string                        `xml:"CustomizationID"`
	ID                          string                        `xml:"ID"`
	ContractFolderID            string                        `xml:"ContractFolderID"`
	IssueDate                   string                        `xml:"IssueDate"`
	IssueTime                   string                        `xml:"IssueTime"`
	VersionID                   string                        `xml:"VersionID"`
	RegulatoryDomain            string                        `xml:"RegulatoryDomain"`
	NoticeTypeCode              string                        `xml:"NoticeTypeCode"`
	NoticeLanguageCode          string                        `xml:"NoticeLanguageCode"`
	Extensions                  *UBLExtensions                `xml:"UBLExtensions,omitempty"`
	ContractingParty            *ContractingParty             `xml:"ContractingParty,omitempty"`
	TenderingTerms              *TenderingTerms               `xml:"TenderingTerms,omitempty"`
	TenderingProcess            *TenderingProcess             `xml:"TenderingProcess,omitempty"`
	ProcurementProject          *ProcurementProject           `xml:"ProcurementProject,omitempty"`
	ProcurementProjectLot       []ProcurementProjectLot       `xml:"ProcurementProjectLot,omitempty"`
	AdditionalDocumentReference []AdditionalDocumentReference `xml:"AdditionalDocumentReference,omitempty"`
}

// Interface methods for PriorInformationNotice
func (pin PriorInformationNotice) GetID() string {
	return pin.ID
}

func (pin PriorInformationNotice) GetNoticeType() string {
	return pin.NoticeTypeCode
}

func (pin PriorInformationNotice) GetLanguage() string {
	return pin.NoticeLanguageCode
}

func (pin PriorInformationNotice) Validate() error {
	if pin.ID == "" {
		return fmt.Errorf("prior information notice ID is required")
	}
	if pin.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}
	return nil
}

// DesignContest represents a design contest notice
type DesignContest struct {
	XMLName             xml.Name              `xml:"DesignContest"`
	Xmlns               string                `xml:"xmlns,attr,omitempty"`
	XmlnsCac            string                `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc            string                `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac           string                `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc           string                `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext          string                `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt            string                `xml:"xmlns:ext,attr,omitempty"`
	UBLVersionID        string                `xml:"UBLVersionID"`
	CustomizationID     string                `xml:"CustomizationID"`
	ID                  string                `xml:"ID"`
	ContractFolderID    string                `xml:"ContractFolderID"`
	IssueDate           string                `xml:"IssueDate"`
	IssueTime           string                `xml:"IssueTime"`
	VersionID           string                `xml:"VersionID"`
	RegulatoryDomain    string                `xml:"RegulatoryDomain"`
	NoticeTypeCode      string                `xml:"NoticeTypeCode"`
	NoticeLanguageCode  string                `xml:"NoticeLanguageCode"`
	Extensions          *UBLExtensions        `xml:"UBLExtensions,omitempty"`
	ContractingParty    *ContractingParty     `xml:"ContractingParty,omitempty"`
	TenderingTerms      *TenderingTerms       `xml:"TenderingTerms,omitempty"`
	TenderingProcess    *TenderingProcess     `xml:"TenderingProcess,omitempty"`
	ProcurementProject  *ProcurementProject   `xml:"ProcurementProject,omitempty"`
	ContestDesignJury   *ContestDesignJury    `xml:"ContestDesignJury,omitempty"`
	ContestDesignReward []ContestDesignReward `xml:"ContestDesignReward,omitempty"`
}

// Interface methods for DesignContest
func (dc DesignContest) GetID() string         { return dc.ID }
func (dc DesignContest) GetNoticeType() string { return dc.NoticeTypeCode }
func (dc DesignContest) GetLanguage() string   { return dc.NoticeLanguageCode }
func (dc DesignContest) Validate() error {
	if dc.ID == "" {
		return fmt.Errorf("design contest ID is required")
	}
	if dc.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}
	return nil
}

// QualificationSystemNotice represents a qualification system notice
type QualificationSystemNotice struct {
	XMLName                  xml.Name                   `xml:"QualificationSystemNotice"`
	Xmlns                    string                     `xml:"xmlns,attr,omitempty"`
	XmlnsCac                 string                     `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc                 string                     `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac                string                     `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc                string                     `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext               string                     `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt                 string                     `xml:"xmlns:ext,attr,omitempty"`
	UBLVersionID             string                     `xml:"UBLVersionID"`
	CustomizationID          string                     `xml:"CustomizationID"`
	ID                       string                     `xml:"ID"`
	ContractFolderID         string                     `xml:"ContractFolderID"`
	IssueDate                string                     `xml:"IssueDate"`
	IssueTime                string                     `xml:"IssueTime"`
	VersionID                string                     `xml:"VersionID"`
	RegulatoryDomain         string                     `xml:"RegulatoryDomain"`
	NoticeTypeCode           string                     `xml:"NoticeTypeCode"`
	NoticeLanguageCode       string                     `xml:"NoticeLanguageCode"`
	Extensions               *UBLExtensions             `xml:"UBLExtensions,omitempty"`
	ContractingParty         *ContractingParty          `xml:"ContractingParty,omitempty"`
	TenderingTerms           *TenderingTerms            `xml:"TenderingTerms,omitempty"`
	TenderingProcess         *TenderingProcess          `xml:"TenderingProcess,omitempty"`
	ProcurementProject       *ProcurementProject        `xml:"ProcurementProject,omitempty"`
	QualificationApplication []QualificationApplication `xml:"QualificationApplication,omitempty"`
}

// Interface methods for QualificationSystemNotice
func (qsn QualificationSystemNotice) GetID() string         { return qsn.ID }
func (qsn QualificationSystemNotice) GetNoticeType() string { return qsn.NoticeTypeCode }
func (qsn QualificationSystemNotice) GetLanguage() string   { return qsn.NoticeLanguageCode }
func (qsn QualificationSystemNotice) Validate() error {
	if qsn.ID == "" {
		return fmt.Errorf("qualification system notice ID is required")
	}
	if qsn.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}
	return nil
}

// ConcessionNotice represents a concession notice
type ConcessionNotice struct {
	XMLName               xml.Name                `xml:"ConcessionNotice"`
	Xmlns                 string                  `xml:"xmlns,attr,omitempty"`
	XmlnsCac              string                  `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc              string                  `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac             string                  `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc             string                  `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext            string                  `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt              string                  `xml:"xmlns:ext,attr,omitempty"`
	UBLVersionID          string                  `xml:"UBLVersionID"`
	CustomizationID       string                  `xml:"CustomizationID"`
	ID                    string                  `xml:"ID"`
	ContractFolderID      string                  `xml:"ContractFolderID"`
	IssueDate             string                  `xml:"IssueDate"`
	IssueTime             string                  `xml:"IssueTime"`
	VersionID             string                  `xml:"VersionID"`
	RegulatoryDomain      string                  `xml:"RegulatoryDomain"`
	NoticeTypeCode        string                  `xml:"NoticeTypeCode"`
	NoticeLanguageCode    string                  `xml:"NoticeLanguageCode"`
	Extensions            *UBLExtensions          `xml:"UBLExtensions,omitempty"`
	ContractingParty      *ContractingParty       `xml:"ContractingParty,omitempty"`
	TenderingTerms        *TenderingTerms         `xml:"TenderingTerms,omitempty"`
	TenderingProcess      *TenderingProcess       `xml:"TenderingProcess,omitempty"`
	ProcurementProject    *ProcurementProject     `xml:"ProcurementProject,omitempty"`
	ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
	ConcessionRevenue     *ConcessionRevenue      `xml:"ConcessionRevenue,omitempty"`
	ConcessionTerm        *ConcessionTerm         `xml:"ConcessionTerm,omitempty"`
}

// Interface methods for ConcessionNotice
func (cn ConcessionNotice) GetID() string         { return cn.ID }
func (cn ConcessionNotice) GetNoticeType() string { return cn.NoticeTypeCode }
func (cn ConcessionNotice) GetLanguage() string   { return cn.NoticeLanguageCode }
func (cn ConcessionNotice) Validate() error {
	if cn.ID == "" {
		return fmt.Errorf("concession notice ID is required")
	}
	if cn.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}
	return nil
}

// PlanningNotice represents a planning notice
type PlanningNotice struct {
	XMLName               xml.Name                `xml:"PlanningNotice"`
	Xmlns                 string                  `xml:"xmlns,attr,omitempty"`
	XmlnsCac              string                  `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc              string                  `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac             string                  `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc             string                  `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext            string                  `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt              string                  `xml:"xmlns:ext,attr,omitempty"`
	UBLVersionID          string                  `xml:"UBLVersionID"`
	CustomizationID       string                  `xml:"CustomizationID"`
	ID                    string                  `xml:"ID"`
	ContractFolderID      string                  `xml:"ContractFolderID"`
	IssueDate             string                  `xml:"IssueDate"`
	IssueTime             string                  `xml:"IssueTime"`
	VersionID             string                  `xml:"VersionID"`
	RegulatoryDomain      string                  `xml:"RegulatoryDomain"`
	NoticeTypeCode        string                  `xml:"NoticeTypeCode"`
	NoticeLanguageCode    string                  `xml:"NoticeLanguageCode"`
	Extensions            *UBLExtensions          `xml:"UBLExtensions,omitempty"`
	ContractingParty      *ContractingParty       `xml:"ContractingParty,omitempty"`
	ProcurementProject    *ProcurementProject     `xml:"ProcurementProject,omitempty"`
	ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
	BudgetAccountLine     []BudgetAccountLine     `xml:"BudgetAccountLine,omitempty"`
	PlannedPeriod         *PlannedPeriod          `xml:"PlannedPeriod,omitempty"`
}

// Interface methods for PlanningNotice
func (pn PlanningNotice) GetID() string         { return pn.ID }
func (pn PlanningNotice) GetNoticeType() string { return pn.NoticeTypeCode }
func (pn PlanningNotice) GetLanguage() string   { return pn.NoticeLanguageCode }
func (pn PlanningNotice) Validate() error {
	if pn.ID == "" {
		return fmt.Errorf("planning notice ID is required")
	}
	if pn.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}
	return nil
}

// CompetitionNotice represents a competition notice
type CompetitionNotice struct {
	XMLName               xml.Name                `xml:"CompetitionNotice"`
	Xmlns                 string                  `xml:"xmlns,attr,omitempty"`
	XmlnsCac              string                  `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc              string                  `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac             string                  `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc             string                  `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext            string                  `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt              string                  `xml:"xmlns:ext,attr,omitempty"`
	UBLVersionID          string                  `xml:"UBLVersionID"`
	CustomizationID       string                  `xml:"CustomizationID"`
	ID                    string                  `xml:"ID"`
	ContractFolderID      string                  `xml:"ContractFolderID"`
	IssueDate             string                  `xml:"IssueDate"`
	IssueTime             string                  `xml:"IssueTime"`
	VersionID             string                  `xml:"VersionID"`
	RegulatoryDomain      string                  `xml:"RegulatoryDomain"`
	NoticeTypeCode        string                  `xml:"NoticeTypeCode"`
	NoticeLanguageCode    string                  `xml:"NoticeLanguageCode"`
	Extensions            *UBLExtensions          `xml:"UBLExtensions,omitempty"`
	ContractingParty      *ContractingParty       `xml:"ContractingParty,omitempty"`
	TenderingTerms        *TenderingTerms         `xml:"TenderingTerms,omitempty"`
	TenderingProcess      *TenderingProcess       `xml:"TenderingProcess,omitempty"`
	ProcurementProject    *ProcurementProject     `xml:"ProcurementProject,omitempty"`
	ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
}

// Interface methods for CompetitionNotice
func (cn CompetitionNotice) GetID() string         { return cn.ID }
func (cn CompetitionNotice) GetNoticeType() string { return cn.NoticeTypeCode }
func (cn CompetitionNotice) GetLanguage() string   { return cn.NoticeLanguageCode }
func (cn CompetitionNotice) Validate() error {
	if cn.ID == "" {
		return fmt.Errorf("competition notice ID is required")
	}
	if cn.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}
	return nil
}

// ResultNotice represents a result notice (eForms specific)
type ResultNotice struct {
	XMLName               xml.Name                `xml:"ResultNotice"`
	Xmlns                 string                  `xml:"xmlns,attr,omitempty"`
	XmlnsCac              string                  `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc              string                  `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac             string                  `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc             string                  `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext            string                  `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt              string                  `xml:"xmlns:ext,attr,omitempty"`
	UBLVersionID          string                  `xml:"UBLVersionID"`
	CustomizationID       string                  `xml:"CustomizationID"`
	ID                    string                  `xml:"ID"`
	ContractFolderID      string                  `xml:"ContractFolderID"`
	IssueDate             string                  `xml:"IssueDate"`
	IssueTime             string                  `xml:"IssueTime"`
	VersionID             string                  `xml:"VersionID"`
	RegulatoryDomain      string                  `xml:"RegulatoryDomain"`
	NoticeTypeCode        string                  `xml:"NoticeTypeCode"`
	NoticeLanguageCode    string                  `xml:"NoticeLanguageCode"`
	Extensions            *UBLExtensions          `xml:"UBLExtensions,omitempty"`
	ContractingParty      *ContractingParty       `xml:"ContractingParty,omitempty"`
	TenderingProcess      *TenderingProcess       `xml:"TenderingProcess,omitempty"`
	ProcurementProject    *ProcurementProject     `xml:"ProcurementProject,omitempty"`
	ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
	TenderResult          []TenderResult          `xml:"TenderResult,omitempty"`
	SettledContract       []SettledContract       `xml:"SettledContract,omitempty"`
}

// Interface methods for ResultNotice
func (rn ResultNotice) GetID() string         { return rn.ID }
func (rn ResultNotice) GetNoticeType() string { return rn.NoticeTypeCode }
func (rn ResultNotice) GetLanguage() string   { return rn.NoticeLanguageCode }
func (rn ResultNotice) Validate() error {
	if rn.ID == "" {
		return fmt.Errorf("result notice ID is required")
	}
	if rn.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}
	return nil
}

// ChangeNotice represents a change notice (eForms specific)
type ChangeNotice struct {
	XMLName                 xml.Name                `xml:"ChangeNotice"`
	Xmlns                   string                  `xml:"xmlns,attr,omitempty"`
	XmlnsCac                string                  `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc                string                  `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac               string                  `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc               string                  `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext              string                  `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt                string                  `xml:"xmlns:ext,attr,omitempty"`
	UBLVersionID            string                  `xml:"UBLVersionID"`
	CustomizationID         string                  `xml:"CustomizationID"`
	ID                      string                  `xml:"ID"`
	ContractFolderID        string                  `xml:"ContractFolderID"`
	IssueDate               string                  `xml:"IssueDate"`
	IssueTime               string                  `xml:"IssueTime"`
	VersionID               string                  `xml:"VersionID"`
	RegulatoryDomain        string                  `xml:"RegulatoryDomain"`
	NoticeTypeCode          string                  `xml:"NoticeTypeCode"`
	NoticeLanguageCode      string                  `xml:"NoticeLanguageCode"`
	Extensions              *UBLExtensions          `xml:"UBLExtensions,omitempty"`
	ContractingParty        *ContractingParty       `xml:"ContractingParty,omitempty"`
	TenderingTerms          *TenderingTerms         `xml:"TenderingTerms,omitempty"`
	TenderingProcess        *TenderingProcess       `xml:"TenderingProcess,omitempty"`
	ProcurementProject      *ProcurementProject     `xml:"ProcurementProject,omitempty"`
	ProcurementProjectLot   []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
	NoticeVersionIdentifier string                  `xml:"NoticeVersionIdentifier,omitempty"`
	ChangeReason            []ChangeReason          `xml:"ChangeReason,omitempty"`
}

// Interface methods for ChangeNotice
func (cn ChangeNotice) GetID() string         { return cn.ID }
func (cn ChangeNotice) GetNoticeType() string { return cn.NoticeTypeCode }
func (cn ChangeNotice) GetLanguage() string   { return cn.NoticeLanguageCode }
func (cn ChangeNotice) Validate() error {
	if cn.ID == "" {
		return fmt.Errorf("change notice ID is required")
	}
	if cn.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}
	return nil
}

// SubcontractNotice represents a subcontract notice
type SubcontractNotice struct {
	XMLName            xml.Name            `xml:"SubcontractNotice"`
	Xmlns              string              `xml:"xmlns,attr,omitempty"`
	XmlnsCac           string              `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc           string              `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac          string              `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc          string              `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext         string              `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt           string              `xml:"xmlns:ext,attr,omitempty"`
	UBLVersionID       string              `xml:"UBLVersionID"`
	CustomizationID    string              `xml:"CustomizationID"`
	ID                 string              `xml:"ID"`
	ContractFolderID   string              `xml:"ContractFolderID"`
	IssueDate          string              `xml:"IssueDate"`
	IssueTime          string              `xml:"IssueTime"`
	VersionID          string              `xml:"VersionID"`
	RegulatoryDomain   string              `xml:"RegulatoryDomain"`
	NoticeTypeCode     string              `xml:"NoticeTypeCode"`
	NoticeLanguageCode string              `xml:"NoticeLanguageCode"`
	Extensions         *UBLExtensions      `xml:"UBLExtensions,omitempty"`
	ContractingParty   *ContractingParty   `xml:"ContractingParty,omitempty"`
	TenderingTerms     *TenderingTerms     `xml:"TenderingTerms,omitempty"`
	TenderingProcess   *TenderingProcess   `xml:"TenderingProcess,omitempty"`
	ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
	SubcontractCall    []SubcontractCall   `xml:"SubcontractCall,omitempty"`
	ParentContract     *ParentContract     `xml:"ParentContract,omitempty"`
}

// Interface methods for SubcontractNotice
func (sn SubcontractNotice) GetID() string         { return sn.ID }
func (sn SubcontractNotice) GetNoticeType() string { return sn.NoticeTypeCode }
func (sn SubcontractNotice) GetLanguage() string   { return sn.NoticeLanguageCode }
func (sn SubcontractNotice) Validate() error {
	if sn.ID == "" {
		return fmt.Errorf("subcontract notice ID is required")
	}
	if sn.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}
	return nil
}

// Additional structures for new notice types

// ContestDesignJury contains design contest jury information
type ContestDesignJury struct {
	XMLName          xml.Name         `xml:"ContestDesignJury"`
	JuryDecisionDate string           `xml:"JuryDecisionDate,omitempty"`
	JuryDecision     string           `xml:"JuryDecision,omitempty"`
	JuryMember       []JuryMember     `xml:"JuryMember,omitempty"`
	JudgingCriteria  *JudgingCriteria `xml:"JudgingCriteria,omitempty"`
}

// ContestDesignReward contains design contest reward information
type ContestDesignReward struct {
	XMLName    xml.Name `xml:"ContestDesignReward"`
	RewardCode string   `xml:"RewardCode,omitempty"`
	Benefit    *Benefit `xml:"Benefit,omitempty"`
}

// JuryMember contains jury member information
type JuryMember struct {
	XMLName xml.Name `xml:"JuryMember"`
	Party   *Party   `xml:"Party,omitempty"`
}

// JudgingCriteria contains judging criteria information
type JudgingCriteria struct {
	XMLName     xml.Name `xml:"JudgingCriteria"`
	Description string   `xml:"Description,omitempty"`
	LanguageID  string   `xml:"languageID,attr,omitempty"`
}

// Benefit contains benefit information
type Benefit struct {
	XMLName      xml.Name     `xml:"Benefit"`
	BenefitValue CurrencyText `xml:"BenefitValue,omitempty"`
}

// QualificationApplication contains qualification application information
type QualificationApplication struct {
	XMLName                      xml.Name                      `xml:"QualificationApplication"`
	QualificationTypeCode        string                        `xml:"QualificationTypeCode,omitempty"`
	ApplicationPeriod            *ApplicationPeriod            `xml:"ApplicationPeriod,omitempty"`
	TendererQualificationRequest *TendererQualificationRequest `xml:"TendererQualificationRequest,omitempty"`
}

// ApplicationPeriod contains application period information
type ApplicationPeriod struct {
	XMLName   xml.Name `xml:"ApplicationPeriod"`
	StartDate string   `xml:"StartDate,omitempty"`
	EndDate   string   `xml:"EndDate,omitempty"`
	StartTime string   `xml:"StartTime,omitempty"`
	EndTime   string   `xml:"EndTime,omitempty"`
}

// ConcessionRevenue contains concession revenue information
type ConcessionRevenue struct {
	XMLName       xml.Name     `xml:"ConcessionRevenue"`
	RevenueType   string       `xml:"RevenueType,omitempty"`
	RevenueAmount CurrencyText `xml:"RevenueAmount,omitempty"`
}

// ConcessionTerm contains concession term information
type ConcessionTerm struct {
	XMLName         xml.Name         `xml:"ConcessionTerm"`
	ConcessionValue CurrencyText     `xml:"ConcessionValue,omitempty"`
	Duration        *DurationMeasure `xml:"DurationMeasure,omitempty"`
}

// BudgetAccountLine contains budget account line information
type BudgetAccountLine struct {
	XMLName       xml.Name       `xml:"BudgetAccountLine"`
	ID            string         `xml:"ID,omitempty"`
	BudgetYear    string         `xml:"BudgetYear,omitempty"`
	TotalAmount   CurrencyText   `xml:"TotalAmount,omitempty"`
	BudgetAccount *BudgetAccount `xml:"BudgetAccount,omitempty"`
}

// BudgetAccount contains budget account information
type BudgetAccount struct {
	XMLName                      xml.Name                      `xml:"BudgetAccount"`
	BudgetCode                   string                        `xml:"BudgetCode,omitempty"`
	RequiredClassificationScheme *RequiredClassificationScheme `xml:"RequiredClassificationScheme,omitempty"`
}

// RequiredClassificationScheme contains classification scheme information
type RequiredClassificationScheme struct {
	XMLName                xml.Name `xml:"RequiredClassificationScheme"`
	ItemClassificationCode string   `xml:"ItemClassificationCode,omitempty"`
}

// SubcontractCall contains subcontract call information
type SubcontractCall struct {
	XMLName                xml.Name            `xml:"SubcontractCall"`
	SubcontractingTypeCode string              `xml:"SubcontractingTypeCode,omitempty"`
	TenderingTerms         *TenderingTerms     `xml:"TenderingTerms,omitempty"`
	ProcurementProject     *ProcurementProject `xml:"ProcurementProject,omitempty"`
}

// ParentContract contains parent contract information
type ParentContract struct {
	XMLName            xml.Name            `xml:"ParentContract"`
	ContractReference  *ContractReference  `xml:"ContractReference,omitempty"`
	FrameworkAgreement *FrameworkAgreement `xml:"FrameworkAgreement,omitempty"`
}

// FrameworkAgreement contains framework agreement information
type FrameworkAgreement struct {
	XMLName                      xml.Name         `xml:"FrameworkAgreement"`
	EstimatedMaximumValue        CurrencyText     `xml:"EstimatedMaximumValue,omitempty"`
	MaximumParticipants          string           `xml:"MaximumParticipants,omitempty"`
	Duration                     *DurationMeasure `xml:"DurationMeasure,omitempty"`
	SubsequentProcedureIndicator string           `xml:"SubsequentProcedureIndicator,omitempty"`
}

// AdditionalDocumentReference contains additional document reference information
type AdditionalDocumentReference struct {
	XMLName             xml.Name        `xml:"AdditionalDocumentReference"`
	ID                  string          `xml:"ID,omitempty"`
	DocumentType        string          `xml:"DocumentType,omitempty"`
	DocumentDescription string          `xml:"DocumentDescription,omitempty"`
	LanguageID          string          `xml:"LanguageID,omitempty"`
	Attachment          *Attachment     `xml:"Attachment,omitempty"`
	ValidityPeriod      *ValidityPeriod `xml:"ValidityPeriod,omitempty"`
	UBLExtensions       *UBLExtensions  `xml:"UBLExtensions,omitempty"`
}

// ValidityPeriod contains validity period information
type ValidityPeriod struct {
	XMLName   xml.Name `xml:"ValidityPeriod"`
	StartDate string   `xml:"StartDate,omitempty"`
	EndDate   string   `xml:"EndDate,omitempty"`
	StartTime string   `xml:"StartTime,omitempty"`
	EndTime   string   `xml:"EndTime,omitempty"`
}

// EnhancedTenderResult structure with more comprehensive information
type EnhancedTenderResult struct {
	XMLName                       xml.Name                        `xml:"TenderResult"`
	AwardDate                     string                          `xml:"AwardDate"`
	AwardTime                     string                          `xml:"AwardTime,omitempty"`
	ReceivedTenderQuantity        string                          `xml:"ReceivedTenderQuantity,omitempty"`
	LowerTenderAmount             CurrencyText                    `xml:"LowerTenderAmount,omitempty"`
	HigherTenderAmount            CurrencyText                    `xml:"HigherTenderAmount,omitempty"`
	AwardedTenderedProject        *AwardedTenderedProject         `xml:"AwardedTenderedProject,omitempty"`
	ContractAwardNotice           *ContractAwardNotice            `xml:"ContractAwardNotice,omitempty"`
	SubcontractingTerm            []SubcontractingTerm            `xml:"SubcontractingTerm,omitempty"`
	WinningTenderLot              []WinningTenderLot              `xml:"WinningTenderLot,omitempty"`
	ReceivedSubmissionsStatistics []ReceivedSubmissionsStatistics `xml:"ReceivedSubmissionsStatistics,omitempty"`
	Extensions                    *UBLExtensions                  `xml:"UBLExtensions,omitempty"`
}

// AwardedTenderedProject contains awarded tendered project information
type AwardedTenderedProject struct {
	XMLName             xml.Name            `xml:"AwardedTenderedProject"`
	ProcurementTypeCode string              `xml:"ProcurementTypeCode,omitempty"`
	TotalAmount         CurrencyText        `xml:"TotalAmount,omitempty"`
	ProcurementProject  *ProcurementProject `xml:"ProcurementProject,omitempty"`
	LegalMonetaryTotal  *LegalMonetaryTotal `xml:"LegalMonetaryTotal,omitempty"`
	TenderLot           []TenderLot         `xml:"TenderLot,omitempty"`
}

// WinningTenderLot contains winning tender lot information
type WinningTenderLot struct {
	XMLName       xml.Name        `xml:"WinningTenderLot"`
	TenderLot     *TenderLot      `xml:"TenderLot,omitempty"`
	WinningTender []WinningTender `xml:"WinningTender,omitempty"`
}

// WinningTender contains winning tender information
type WinningTender struct {
	XMLName                xml.Name             `xml:"WinningTender"`
	ID                     string               `xml:"ID"`
	TenderVariantIndicator string               `xml:"TenderVariantIndicator,omitempty"`
	LegalMonetaryTotal     *LegalMonetaryTotal  `xml:"LegalMonetaryTotal,omitempty"`
	TenderingParty         *TenderingParty      `xml:"TenderingParty,omitempty"`
	SubcontractingTerm     []SubcontractingTerm `xml:"SubcontractingTerm,omitempty"`
}

// Enhanced SubcontractingTerm structure
type SubcontractingTerm struct {
	XMLName                   xml.Name     `xml:"SubcontractingTerm"`
	TermCode                  string       `xml:"TermCode"`
	Amount                    CurrencyText `xml:"Amount,omitempty"`
	Rate                      string       `xml:"Rate,omitempty"`
	Description               string       `xml:"Description,omitempty"`
	UnknownPriceIndicator     string       `xml:"UnknownPriceIndicator,omitempty"`
	SubcontractingDescription string       `xml:"SubcontractingDescription,omitempty"`
}

// ContractNotice represents the main TED XML contract notice structure
type ContractNotice struct {
	XMLName               xml.Name               `xml:"ContractNotice"`
	Xmlns                 string                 `xml:"xmlns,attr,omitempty"`
	XmlnsCac              string                 `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc              string                 `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac             string                 `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc             string                 `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext            string                 `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt              string                 `xml:"xmlns:ext,attr,omitempty"`
	UBLVersionID          string                 `xml:"UBLVersionID"`
	CustomizationID       string                 `xml:"CustomizationID"`
	ID                    string                 `xml:"ID"`
	ContractFolderID      string                 `xml:"ContractFolderID"`
	IssueDate             string                 `xml:"IssueDate"`
	IssueTime             string                 `xml:"IssueTime"`
	VersionID             string                 `xml:"VersionID"`
	RegulatoryDomain      string                 `xml:"RegulatoryDomain"`
	NoticeTypeCode        string                 `xml:"NoticeTypeCode"`
	NoticeLanguageCode    string                 `xml:"NoticeLanguageCode"`
	Extensions            *UBLExtensions         `xml:"UBLExtensions,omitempty"`
	ContractingParty      *ContractingParty      `xml:"ContractingParty,omitempty"`
	TenderingTerms        *TenderingTerms        `xml:"TenderingTerms,omitempty"`
	TenderingProcess      *TenderingProcess      `xml:"TenderingProcess,omitempty"`
	ProcurementProject    *ProcurementProject    `xml:"ProcurementProject,omitempty"`
	ProcurementProjectLot *ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
}

// ContractAwardNotice represents the main TED XML contract award notice structure
type ContractAwardNotice struct {
	XMLName               xml.Name                `xml:"ContractAwardNotice"`
	Xmlns                 string                  `xml:"xmlns,attr,omitempty"`
	XmlnsCac              string                  `xml:"xmlns:cac,attr,omitempty"`
	XmlnsCbc              string                  `xml:"xmlns:cbc,attr,omitempty"`
	XmlnsEfac             string                  `xml:"xmlns:efac,attr,omitempty"`
	XmlnsEfbc             string                  `xml:"xmlns:efbc,attr,omitempty"`
	XmlnsEfext            string                  `xml:"xmlns:efext,attr,omitempty"`
	XmlnsExt              string                  `xml:"xmlns:ext,attr,omitempty"`
	Extensions            *UBLExtensions          `xml:"UBLExtensions,omitempty"`
	UBLVersionID          string                  `xml:"UBLVersionID"`
	CustomizationID       string                  `xml:"CustomizationID"`
	ID                    string                  `xml:"ID"`
	ContractFolderID      string                  `xml:"ContractFolderID"`
	IssueDate             string                  `xml:"IssueDate"`
	IssueTime             string                  `xml:"IssueTime"`
	VersionID             string                  `xml:"VersionID"`
	RegulatoryDomain      string                  `xml:"RegulatoryDomain"`
	NoticeTypeCode        string                  `xml:"NoticeTypeCode"`
	NoticeLanguageCode    string                  `xml:"NoticeLanguageCode"`
	ContractingParty      *ContractingParty       `xml:"ContractingParty,omitempty"`
	TenderingProcess      *TenderingProcess       `xml:"TenderingProcess,omitempty"`
	ProcurementProject    *ProcurementProject     `xml:"ProcurementProject,omitempty"`
	ProcurementProjectLot []ProcurementProjectLot `xml:"ProcurementProjectLot,omitempty"`
	TenderResult          *TenderResult           `xml:"TenderResult,omitempty"`
}

// NoticeResult contains notice result information from extensions
type NoticeResult struct {
	XMLName     xml.Name      `xml:"NoticeResult"`
	TotalAmount *CurrencyText `xml:"TotalAmount,omitempty"`
	LotResult   []LotResult   `xml:"LotResult,omitempty"`
}

// LotResult contains lot result information
type LotResult struct {
	XMLName                       xml.Name                        `xml:"LotResult"`
	ID                            string                          `xml:"ID"`
	TenderResultCode              string                          `xml:"TenderResultCode"`
	LotTender                     []LotTender                     `xml:"LotTender,omitempty"`
	ReceivedSubmissionsStatistics []ReceivedSubmissionsStatistics `xml:"ReceivedSubmissionsStatistics,omitempty"`
	SettledContract               []SettledContract               `xml:"SettledContract,omitempty"`
	TenderLot                     *TenderLot                      `xml:"TenderLot,omitempty"`
}

// LotTender contains lot tender information
type LotTender struct {
	XMLName                xml.Name            `xml:"LotTender"`
	ID                     string              `xml:"ID"`
	RankCode               string              `xml:"RankCode,omitempty"`
	TenderRankedIndicator  string              `xml:"TenderRankedIndicator,omitempty"`
	TenderVariantIndicator string              `xml:"TenderVariantIndicator,omitempty"`
	LegalMonetaryTotal     *LegalMonetaryTotal `xml:"LegalMonetaryTotal,omitempty"`
	SubcontractingTerm     *SubcontractingTerm `xml:"SubcontractingTerm,omitempty"`
	TenderingParty         *TenderingParty     `xml:"TenderingParty,omitempty"`
	TenderLot              *TenderLot          `xml:"TenderLot,omitempty"`
	TenderReference        *TenderReference    `xml:"TenderReference,omitempty"`
}

// LegalMonetaryTotal contains monetary total information
type LegalMonetaryTotal struct {
	XMLName       xml.Name     `xml:"LegalMonetaryTotal"`
	PayableAmount CurrencyText `xml:"PayableAmount"`
}

// TenderingParty contains tendering party information
type TenderingParty struct {
	XMLName xml.Name `xml:"TenderingParty"`
	ID      string   `xml:"ID"`
}

// TenderLot contains tender lot information
type TenderLot struct {
	XMLName xml.Name `xml:"TenderLot"`
	ID      string   `xml:"ID"`
}

// TenderReference contains tender reference information
type TenderReference struct {
	XMLName xml.Name `xml:"TenderReference"`
	ID      string   `xml:"ID"`
}

// ReceivedSubmissionsStatistics contains received submissions statistics
type ReceivedSubmissionsStatistics struct {
	XMLName           xml.Name `xml:"ReceivedSubmissionsStatistics"`
	StatisticsCode    string   `xml:"StatisticsCode"`
	StatisticsNumeric string   `xml:"StatisticsNumeric"`
}

// SettledContract contains settled contract information
type SettledContract struct {
	XMLName           xml.Name           `xml:"SettledContract"`
	ID                string             `xml:"ID"`
	IssueDate         string             `xml:"IssueDate,omitempty"`
	Title             string             `xml:"Title,omitempty"`
	SignatoryParty    *SignatoryParty    `xml:"SignatoryParty,omitempty"`
	ContractReference *ContractReference `xml:"ContractReference,omitempty"`
	LotTender         *LotTender         `xml:"LotTender,omitempty"`
}

// SignatoryParty contains signatory party information
type SignatoryParty struct {
	XMLName             xml.Name             `xml:"SignatoryParty"`
	PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
}

// ContractReference contains contract reference information
type ContractReference struct {
	XMLName xml.Name `xml:"ContractReference"`
	ID      string   `xml:"ID"`
}

// TenderResult contains tender result information
type TenderResult struct {
	XMLName   xml.Name `xml:"TenderResult"`
	AwardDate string   `xml:"AwardDate"`
}

// NoticeDocumentReference contains notice document reference information
type NoticeDocumentReference struct {
	XMLName xml.Name `xml:"NoticeDocumentReference"`
	ID      string   `xml:"ID"`
}

// PresentationPeriod contains presentation period information
type PresentationPeriod struct {
	XMLName     xml.Name `xml:"PresentationPeriod"`
	Description string   `xml:"Description,omitempty"`
	LanguageID  string   `xml:"languageID,attr,omitempty"`
}

// AppealInformationParty contains appeal information party
type AppealInformationParty struct {
	XMLName             xml.Name             `xml:"AppealInformationParty"`
	PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
}

// MediationParty contains mediation party information
type MediationParty struct {
	XMLName             xml.Name             `xml:"MediationParty"`
	PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
}

// UBLExtensions contains eForms extensions
type UBLExtensions struct {
	XMLName      xml.Name      `xml:"UBLExtensions"`
	UBLExtension *UBLExtension `xml:"UBLExtension,omitempty"`
}

// UBLExtension contains extension content
type UBLExtension struct {
	XMLName          xml.Name          `xml:"UBLExtension"`
	ExtensionContent *ExtensionContent `xml:"ExtensionContent,omitempty"`
}

// ExtensionContent contains eForms extension data
type ExtensionContent struct {
	XMLName         xml.Name         `xml:"ExtensionContent"`
	EformsExtension *EformsExtension `xml:"EformsExtension,omitempty"`
}

// EformsExtension contains eForms specific data
type EformsExtension struct {
	XMLName                 xml.Name                 `xml:"EformsExtension"`
	NoticeResult            *NoticeResult            `xml:"NoticeResult,omitempty"`
	NoticeSubType           *NoticeSubType           `xml:"NoticeSubType,omitempty"`
	Organizations           *Organizations           `xml:"Organizations,omitempty"`
	Publication             *Publication             `xml:"Publication,omitempty"`
	Changes                 *Changes                 `xml:"Changes,omitempty"`
	SelectionCriteria       []SelectionCriteria      `xml:"SelectionCriteria,omitempty"`
	OfficialLanguages       *OfficialLanguages       `xml:"OfficialLanguages,omitempty"`
	AwardCriterionParameter *AwardCriterionParameter `xml:"AwardCriterionParameter,omitempty"`
	AccessToolName          string                   `xml:"AccessToolName,omitempty"`
}

// NoticeSubType contains notice subtype information
type NoticeSubType struct {
	XMLName     xml.Name `xml:"NoticeSubType"`
	SubTypeCode string   `xml:"SubTypeCode"`
}

// SelectionCriteria contains tenderer requirement information
type SelectionCriteria struct {
	XMLName                     xml.Name `xml:"SelectionCriteria"`
	CriterionTypeCode           string   `xml:"CriterionTypeCode"`
	TendererRequirementTypeCode string   `xml:"TendererRequirementTypeCode"`
	Name                        string   `xml:"Name,omitempty"`
	Description                 string   `xml:"Description,omitempty"`
	CalculationExpressionCode   string   `xml:"CalculationExpressionCode,omitempty"`
	LanguageID                  string   `xml:"languageID,attr,omitempty"`
}

// OfficialLanguages contains official language information
type OfficialLanguages struct {
	XMLName  xml.Name   `xml:"OfficialLanguages"`
	Language []Language `xml:"Language"`
}

// Language represents a language entry
type Language struct {
	XMLName xml.Name `xml:"Language"`
	ID      string   `xml:"ID"`
}

// Organizations contains organization information
type Organizations struct {
	XMLName      xml.Name       `xml:"Organizations"`
	Organization []Organization `xml:"Organization"`
}

// Organization represents an organization entity
type Organization struct {
	XMLName                xml.Name `xml:"Organization"`
	NaturalPersonIndicator string   `xml:"NaturalPersonIndicator,omitempty"`
	Company                *Company `xml:"Company,omitempty"`
}

// Company represents company informationf
type Company struct {
	XMLName             xml.Name             `xml:"Company"`
	WebsiteURI          string               `xml:"WebsiteURI,omitempty"`
	PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
	PartyName           *PartyName           `xml:"PartyName,omitempty"`
	PostalAddress       *PostalAddress       `xml:"PostalAddress,omitempty"`
	PartyLegalEntity    *PartyLegalEntity    `xml:"PartyLegalEntity,omitempty"`
	Contact             *Contact             `xml:"Contact,omitempty"`
}

// PartyIdentification contains party ID information
type PartyIdentification struct {
	XMLName xml.Name `xml:"PartyIdentification"`
	ID      string   `xml:"ID"`
}

// PartyName contains party name
type PartyName struct {
	XMLName xml.Name `xml:"PartyName"`
	Name    string   `xml:"Name"`
}

// PostalAddress contains address information
type PostalAddress struct {
	XMLName              xml.Name `xml:"PostalAddress"`
	StreetName           string   `xml:"StreetName,omitempty"`
	CityName             string   `xml:"CityName,omitempty"`
	PostalZone           string   `xml:"PostalZone,omitempty"`
	CountrySubentityCode string   `xml:"CountrySubentityCode,omitempty"`
	Department           string   `xml:"Department,omitempty"`
	Country              *Country `xml:"Country,omitempty"`
}

// Country contains country information
type Country struct {
	XMLName            xml.Name `xml:"Country"`
	IdentificationCode string   `xml:"IdentificationCode"`
}

// PartyLegalEntity contains legal entity information
type PartyLegalEntity struct {
	XMLName   xml.Name `xml:"PartyLegalEntity"`
	CompanyID string   `xml:"CompanyID"`
}

// Contact contains contact information
type Contact struct {
	XMLName        xml.Name `xml:"Contact"`
	Name           string   `xml:"Name,omitempty"`
	Telephone      string   `xml:"Telephone,omitempty"`
	Telefax        string   `xml:"Telefax,omitempty"`
	ElectronicMail string   `xml:"ElectronicMail,omitempty"`
}

// Publication contains publication information
type Publication struct {
	XMLName             xml.Name `xml:"Publication"`
	NoticePublicationID string   `xml:"NoticePublicationID"`
	GazetteID           string   `xml:"GazetteID"`
	PublicationDate     string   `xml:"PublicationDate"`
}

// Changes contains notice change information
type Changes struct {
	XMLName                 xml.Name      `xml:"Changes"`
	ChangedNoticeIdentifier string        `xml:"ChangedNoticeIdentifier"`
	ChangeReason            *ChangeReason `xml:"ChangeReason,omitempty"`
}

// ChangeReason contains change reason information
type ChangeReason struct {
	XMLName    xml.Name `xml:"ChangeReason"`
	ReasonCode string   `xml:"ReasonCode"`
}

// ContractingParty contains contracting party information
type ContractingParty struct {
	XMLName              xml.Name              `xml:"ContractingParty"`
	BuyerProfileURI      string                `xml:"BuyerProfileURI,omitempty"`
	ContractingPartyType *ContractingPartyType `xml:"ContractingPartyType,omitempty"`
	ContractingActivity  *ContractingActivity  `xml:"ContractingActivity,omitempty"`
	Party                *Party                `xml:"Party,omitempty"`
}

// ContractingPartyType contains party type information
type ContractingPartyType struct {
	XMLName       xml.Name `xml:"ContractingPartyType"`
	PartyTypeCode string   `xml:"PartyTypeCode"`
}

// ContractingActivity contains contracting activity information
type ContractingActivity struct {
	XMLName          xml.Name `xml:"ContractingActivity"`
	ActivityTypeCode string   `xml:"ActivityTypeCode"`
}

// Party contains party information
type Party struct {
	XMLName              xml.Name              `xml:"Party"`
	PartyIdentification  *PartyIdentification  `xml:"PartyIdentification,omitempty"`
	ServiceProviderParty *ServiceProviderParty `xml:"ServiceProviderParty,omitempty"`
}

// ServiceProviderParty contains service provider information
type ServiceProviderParty struct {
	XMLName         xml.Name `xml:"ServiceProviderParty"`
	ServiceTypeCode string   `xml:"ServiceTypeCode,omitempty"`
	Party           *Party   `xml:"Party,omitempty"`
}

// TenderingTerms contains tendering terms
type TenderingTerms struct {
	XMLName                         xml.Name                          `xml:"TenderingTerms"`
	VariantConstraintCode           string                            `xml:"VariantConstraintCode,omitempty"`
	FundingProgramCode              string                            `xml:"FundingProgramCode,omitempty"`
	RecurringProcurementIndicator   string                            `xml:"RecurringProcurementIndicator,omitempty"`
	MultipleTendersCode             string                            `xml:"MultipleTendersCode,omitempty"`
	TendererQualificationRequest    []TendererQualificationRequest    `xml:"TendererQualificationRequest,omitempty"`
	AppealTerms                     *AppealTerms                      `xml:"AppealTerms,omitempty"`
	CallForTendersDocumentReference []CallForTendersDocumentReference `xml:"CallForTendersDocumentReference,omitempty"`
	RequiredFinancialGuarantee      *RequiredFinancialGuarantee       `xml:"RequiredFinancialGuarantee,omitempty"`
	PaymentTerms                    *PaymentTerms                     `xml:"PaymentTerms,omitempty"`
	AwardingTerms                   *AwardingTerms                    `xml:"AwardingTerms,omitempty"`
	AdditionalInformationParty      *AdditionalInformationParty       `xml:"AdditionalInformationParty,omitempty"`
	TenderRecipientParty            *TenderRecipientParty             `xml:"TenderRecipientParty,omitempty"`
	TenderValidityPeriod            *TenderValidityPeriod             `xml:"TenderValidityPeriod,omitempty"`
	Language                        *Language                         `xml:"Language,omitempty"`
	PostAwardProcess                *PostAwardProcess                 `xml:"PostAwardProcess,omitempty"`
	ContractExecutionRequirement    []ContractExecutionRequirement    `xml:"ContractExecutionRequirement,omitempty"`
	UBLExtensions                   *UBLExtensions                    `xml:"UBLExtensions,omitempty"`
}

// RequiredFinancialGuarantee contains financial guarantee information
type RequiredFinancialGuarantee struct {
	XMLName           xml.Name `xml:"RequiredFinancialGuarantee"`
	GuaranteeTypeCode string   `xml:"GuaranteeTypeCode,omitempty"`
	Description       string   `xml:"Description,omitempty"`
	LanguageID        string   `xml:"languageID,attr,omitempty"`
}

// PaymentTerms contains payment terms information
type PaymentTerms struct {
	XMLName    xml.Name `xml:"PaymentTerms"`
	Note       string   `xml:"Note,omitempty"`
	LanguageID string   `xml:"languageID,attr,omitempty"`
}

// AwardingTerms contains awarding terms information
type AwardingTerms struct {
	XMLName           xml.Name            `xml:"AwardingTerms"`
	AwardingCriterion []AwardingCriterion `xml:"AwardingCriterion,omitempty"`
}

// AwardingCriterion contains awarding criteria information
type AwardingCriterion struct {
	XMLName                      xml.Name                       `xml:"AwardingCriterion"`
	SubordinateAwardingCriterion []SubordinateAwardingCriterion `xml:"SubordinateAwardingCriterion,omitempty"`
}

// SubordinateAwardingCriterion contains subordinate awarding criteria
type SubordinateAwardingCriterion struct {
	XMLName                   xml.Name       `xml:"SubordinateAwardingCriterion"`
	AwardingCriterionTypeCode string         `xml:"AwardingCriterionTypeCode,omitempty"`
	Name                      string         `xml:"Name,omitempty"`
	Description               string         `xml:"Description,omitempty"`
	UBLExtensions             *UBLExtensions `xml:"UBLExtensions,omitempty"`
}

// AwardCriterionParameter contains award criterion parameter information
type AwardCriterionParameter struct {
	XMLName          xml.Name `xml:"AwardCriterionParameter"`
	ParameterCode    string   `xml:"ParameterCode,omitempty"`
	ParameterNumeric string   `xml:"ParameterNumeric,omitempty"`
}

// AdditionalInformationParty contains additional information party
type AdditionalInformationParty struct {
	XMLName             xml.Name             `xml:"AdditionalInformationParty"`
	PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
}

// TenderRecipientParty contains tender recipient party information
type TenderRecipientParty struct {
	XMLName    xml.Name `xml:"TenderRecipientParty"`
	EndpointID string   `xml:"EndpointID,omitempty"`
}

// TenderValidityPeriod contains tender validity period
type TenderValidityPeriod struct {
	XMLName         xml.Name         `xml:"TenderValidityPeriod"`
	DurationMeasure *DurationMeasure `xml:"DurationMeasure,omitempty"`
}

// PostAwardProcess contains post award process information
type PostAwardProcess struct {
	XMLName                           xml.Name `xml:"PostAwardProcess"`
	ElectronicCatalogueUsageIndicator string   `xml:"ElectronicCatalogueUsageIndicator,omitempty"`
	ElectronicOrderUsageIndicator     string   `xml:"ElectronicOrderUsageIndicator,omitempty"`
	ElectronicPaymentUsageIndicator   string   `xml:"ElectronicPaymentUsageIndicator,omitempty"`
}

// ContractExecutionRequirement contains contract execution requirements
type ContractExecutionRequirement struct {
	XMLName                  xml.Name `xml:"ContractExecutionRequirement"`
	ExecutionRequirementCode string   `xml:"ExecutionRequirementCode,omitempty"`
	Description              string   `xml:"Description,omitempty"`
	LanguageID               string   `xml:"languageID,attr,omitempty"`
}

// AppealTerms contains appeal terms information
type AppealTerms struct {
	XMLName                xml.Name                `xml:"AppealTerms"`
	Description            string                  `xml:"Description,omitempty"`
	LanguageID             string                  `xml:"languageID,attr,omitempty"`
	PresentationPeriod     *PresentationPeriod     `xml:"PresentationPeriod,omitempty"`
	AppealInformationParty *AppealInformationParty `xml:"AppealInformationParty,omitempty"`
	AppealReceiverParty    *AppealReceiverParty    `xml:"AppealReceiverParty,omitempty"`
	MediationParty         *MediationParty         `xml:"MediationParty,omitempty"`
}

// AppealReceiverParty contains appeal receiver party information
type AppealReceiverParty struct {
	XMLName             xml.Name             `xml:"AppealReceiverParty"`
	PartyIdentification *PartyIdentification `xml:"PartyIdentification,omitempty"`
}

// CallForTendersDocumentReference contains document reference information
type CallForTendersDocumentReference struct {
	XMLName            xml.Name       `xml:"CallForTendersDocumentReference"`
	ID                 string         `xml:"ID,omitempty"`
	DocumentType       string         `xml:"DocumentType,omitempty"`
	LanguageID         string         `xml:"LanguageID,omitempty"`
	DocumentStatusCode string         `xml:"DocumentStatusCode,omitempty"`
	Attachment         *Attachment    `xml:"Attachment,omitempty"`
	UBLExtensions      *UBLExtensions `xml:"UBLExtensions,omitempty"`
}

// Attachment contains attachment information
type Attachment struct {
	XMLName           xml.Name           `xml:"Attachment"`
	ExternalReference *ExternalReference `xml:"ExternalReference,omitempty"`
}

// ExternalReference contains external reference information
type ExternalReference struct {
	XMLName      xml.Name `xml:"ExternalReference"`
	URI          string   `xml:"URI"`
	DocumentHash string   `xml:"DocumentHash,omitempty"`
	FileName     string   `xml:"FileName,omitempty"`
}

// TendererQualificationRequest contains qualification request information
type TendererQualificationRequest struct {
	XMLName                     xml.Name                      `xml:"TendererQualificationRequest"`
	CompanyLegalFormCode        string                        `xml:"CompanyLegalFormCode,omitempty"`
	SpecificTendererRequirement []SpecificTendererRequirement `xml:"SpecificTendererRequirement,omitempty"`
}

// SpecificTendererRequirement contains specific requirement information
type SpecificTendererRequirement struct {
	XMLName                     xml.Name `xml:"SpecificTendererRequirement"`
	TendererRequirementTypeCode string   `xml:"TendererRequirementTypeCode"`
	Description                 string   `xml:"Description,omitempty"`
}

// TenderingProcess contains tendering process information
type TenderingProcess struct {
	XMLName                                xml.Name                        `xml:"TenderingProcess"`
	Description                            string                          `xml:"Description,omitempty"`
	ProcedureCode                          string                          `xml:"ProcedureCode"`
	SubmissionMethodCode                   string                          `xml:"SubmissionMethodCode,omitempty"`
	GovernmentAgreementConstraintIndicator string                          `xml:"GovernmentAgreementConstraintIndicator,omitempty"`
	ProcessJustification                   *ProcessJustification           `xml:"ProcessJustification,omitempty"`
	TenderSubmissionDeadlinePeriod         *TenderSubmissionDeadlinePeriod `xml:"TenderSubmissionDeadlinePeriod,omitempty"`
	OpenTenderEvent                        *OpenTenderEvent                `xml:"OpenTenderEvent,omitempty"`
	AuctionTerms                           *AuctionTerms                   `xml:"AuctionTerms,omitempty"`
	ContractingSystem                      []ContractingSystem             `xml:"ContractingSystem,omitempty"`
	NoticeDocumentReference                []NoticeDocumentReference       `xml:"NoticeDocumentReference,omitempty"`
	UBLExtensions                          *UBLExtensions                  `xml:"UBLExtensions,omitempty"`
}

// TenderSubmissionDeadlinePeriod contains tender submission deadline information
type TenderSubmissionDeadlinePeriod struct {
	XMLName xml.Name `xml:"TenderSubmissionDeadlinePeriod"`
	EndDate string   `xml:"EndDate"`
	EndTime string   `xml:"EndTime,omitempty"`
}

// OpenTenderEvent contains open tender event information
type OpenTenderEvent struct {
	XMLName           xml.Name           `xml:"OpenTenderEvent"`
	OccurrenceDate    string             `xml:"OccurrenceDate,omitempty"`
	OccurrenceTime    string             `xml:"OccurrenceTime,omitempty"`
	Description       string             `xml:"Description,omitempty"`
	LanguageID        string             `xml:"languageID,attr,omitempty"`
	OccurenceLocation *OccurenceLocation `xml:"OccurenceLocation,omitempty"`
}

// OccurenceLocation contains occurrence location information
type OccurenceLocation struct {
	XMLName     xml.Name `xml:"OccurenceLocation"`
	Description string   `xml:"Description,omitempty"`
	LanguageID  string   `xml:"languageID,attr,omitempty"`
}

// AuctionTerms contains auction terms information
type AuctionTerms struct {
	XMLName                    xml.Name `xml:"AuctionTerms"`
	AuctionConstraintIndicator string   `xml:"AuctionConstraintIndicator,omitempty"`
}

// ContractingSystem contains contracting system information
type ContractingSystem struct {
	XMLName                   xml.Name `xml:"ContractingSystem"`
	ContractingSystemTypeCode string   `xml:"ContractingSystemTypeCode,omitempty"`
}

// ProcurementProject contains procurement project information
type ProcurementProject struct {
	XMLName              xml.Name `xml:"ProcurementProject"`
	ID                   string   `xml:"ID"`
	Name                 string   `xml:"Name"`
	Description          string   `xml:"Description"`
	ProcurementTypeCode  string   `xml:"ProcurementTypeCode"`
	SMESuitableIndicator string   `xml:"SMESuitableIndicator,omitempty"`
	Note                 string   `xml:"Note,omitempty"`

	RequestedTenderTotal              *RequestedTenderTotal               `xml:"RequestedTenderTotal,omitempty"`
	MainCommodityClassification       *MainCommodityClassification        `xml:"MainCommodityClassification,omitempty"`
	AdditionalCommodityClassification []AdditionalCommodityClassification `xml:"AdditionalCommodityClassification,omitempty"`
	ProcurementAdditionalType         *ProcurementAdditionalType          `xml:"ProcurementAdditionalType,omitempty"`
	RealizedLocation                  *RealizedLocation                   `xml:"RealizedLocation,omitempty"`
	PlannedPeriod                     *PlannedPeriod                      `xml:"PlannedPeriod,omitempty"`
	ContractExtension                 *ContractExtension                  `xml:"ContractExtension,omitempty"`
}

// ProcurementAdditionalType contains additional procurement type information
type ProcurementAdditionalType struct {
	XMLName             xml.Name `xml:"ProcurementAdditionalType"`
	ProcurementTypeCode string   `xml:"ProcurementTypeCode,omitempty"`
}

// ContractExtension contains contract extension information
type ContractExtension struct {
	XMLName              xml.Name `xml:"ContractExtension"`
	MaximumNumberNumeric string   `xml:"MaximumNumberNumeric,omitempty"`
}

// ProcessJustification contains process justification
type ProcessJustification struct {
	XMLName           xml.Name `xml:"ProcessJustification"`
	ProcessReasonCode string   `xml:"ProcessReasonCode"`
}

// RequestedTenderTotal contains tender total information
type RequestedTenderTotal struct {
	XMLName                        xml.Name     `xml:"RequestedTenderTotal"`
	EstimatedOverallContractAmount CurrencyText `xml:"EstimatedOverallContractAmount"`
}

// CurrencyText represents text with currency attribute
type CurrencyText struct {
	CurrencyID string `xml:"currencyID,attr,omitempty"`
	Text       string `xml:",chardata"`
}

// MainCommodityClassification contains main commodity classification
type MainCommodityClassification struct {
	XMLName                xml.Name `xml:"MainCommodityClassification"`
	ItemClassificationCode string   `xml:"ItemClassificationCode"`
}

// AdditionalCommodityClassification contains additional commodity classification
type AdditionalCommodityClassification struct {
	XMLName                xml.Name `xml:"AdditionalCommodityClassification"`
	ItemClassificationCode string   `xml:"ItemClassificationCode"`
}

// RealizedLocation contains location information
type RealizedLocation struct {
	XMLName     xml.Name `xml:"RealizedLocation"`
	Description string   `xml:"Description,omitempty"`
	Address     *Address `xml:"Address,omitempty"`
}

// Address contains address information (different from PostalAddress)
type Address struct {
	XMLName              xml.Name `xml:"Address"`
	StreetName           string   `xml:"StreetName,omitempty"`
	AdditionalStreetName string   `xml:"AdditionalStreetName,omitempty"`
	CityName             string   `xml:"CityName,omitempty"`
	PostalZone           string   `xml:"PostalZone,omitempty"`
	CountrySubentityCode string   `xml:"CountrySubentityCode,omitempty"`
	Region               string   `xml:"Region,omitempty"`
	Country              *Country `xml:"Country,omitempty"`
}

// PlannedPeriod contains planned period information
type PlannedPeriod struct {
	XMLName         xml.Name         `xml:"PlannedPeriod"`
	StartDate       string           `xml:"StartDate,omitempty"`
	EndDate         string           `xml:"EndDate,omitempty"`
	DurationMeasure *DurationMeasure `xml:"DurationMeasure,omitempty"`
}

// DurationMeasure contains duration with unit information
type DurationMeasure struct {
	XMLName  xml.Name `xml:"DurationMeasure"`
	UnitCode string   `xml:"unitCode,attr,omitempty"`
	Text     string   `xml:",chardata"`
}

// ProcurementProjectLot contains lot information
type ProcurementProjectLot struct {
	XMLName            xml.Name            `xml:"ProcurementProjectLot"`
	ID                 string              `xml:"ID"`
	TenderingTerms     *TenderingTerms     `xml:"TenderingTerms,omitempty"`
	TenderingProcess   *TenderingProcess   `xml:"TenderingProcess,omitempty"`
	ProcurementProject *ProcurementProject `xml:"ProcurementProject,omitempty"`
}

// Validate validates the ContractNotice structure
func (cn ContractNotice) Validate() error {
	if cn.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}

	// Validate date format - TED XML uses ISO 8601 format with timezone
	validFormats := []string{
		"2006-01-02+07:00",
		"2006-01-02-07:00",
		"2006-01-02T15:04:05+07:00",
		"2006-01-02T15:04:05-07:00",
		"2006-01-02T15:04:05Z",
		"2006-01-02Z",
		"2006-01-02",
		time.RFC3339,
		time.RFC3339Nano,
	}

	var validDate bool
	for _, format := range validFormats {
		if _, err := time.Parse(format, cn.IssueDate); err == nil {
			validDate = true
			break
		}
	}

	if !validDate {
		return fmt.Errorf("invalid issue date format: %s (expected ISO 8601 format)", cn.IssueDate)
	}

	// Validate language code if provided (should be 3-letter ISO code)
	if cn.NoticeLanguageCode != "" && len(cn.NoticeLanguageCode) != 3 {
		return fmt.Errorf("invalid notice language code: %s (expected 3-letter ISO code)", cn.NoticeLanguageCode)
	}

	// Validate tender submission deadline format if present
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.TenderingProcess != nil &&
		cn.ProcurementProjectLot.TenderingProcess.TenderSubmissionDeadlinePeriod != nil {

		deadline := cn.ProcurementProjectLot.TenderingProcess.TenderSubmissionDeadlinePeriod.EndDate
		if deadline != "" {
			var validDeadline bool
			for _, format := range validFormats {
				if _, err := time.Parse(format, deadline); err == nil {
					validDeadline = true
					break
				}
			}
			if !validDeadline {
				return fmt.Errorf("invalid tender submission deadline format: %s (expected ISO 8601 format)", deadline)
			}
		}
	}

	// Validate currency code if provided in budget
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.ProcurementProject != nil &&
		cn.ProcurementProjectLot.ProcurementProject.RequestedTenderTotal != nil {

		currency := cn.ProcurementProjectLot.ProcurementProject.RequestedTenderTotal.EstimatedOverallContractAmount.CurrencyID
		if currency != "" && len(currency) != 3 {
			return fmt.Errorf("invalid currency code: %s (expected 3-letter ISO code)", currency)
		}
	}

	// Validate duration unit code if provided
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.ProcurementProject != nil &&
		cn.ProcurementProjectLot.ProcurementProject.PlannedPeriod != nil &&
		cn.ProcurementProjectLot.ProcurementProject.PlannedPeriod.DurationMeasure != nil {

		unitCode := cn.ProcurementProjectLot.ProcurementProject.PlannedPeriod.DurationMeasure.UnitCode
		if unitCode != "" {
			validUnits := map[string]bool{
				"MONTH": true,
				"DAY":   true,
				"WEEK":  true,
				"YEAR":  true,
			}
			if !validUnits[unitCode] {
				return fmt.Errorf("invalid duration unit code: %s (expected MONTH, DAY, WEEK, or YEAR)", unitCode)
			}
		}
	}

	return nil
}

// GetID returns the contract notice ID
func (cn ContractNotice) GetID() string {
	return cn.ID
}

// GetNoticeType returns the notice type
func (cn ContractNotice) GetNoticeType() string {
	return cn.NoticeTypeCode
}

// GetLanguage returns the notice language
func (cn ContractNotice) GetLanguage() string {
	return cn.NoticeLanguageCode
}

// GetPublicationInfo returns publication information if available
func (cn ContractNotice) GetPublicationInfo() *Publication {
	if cn.Extensions != nil &&
		cn.Extensions.UBLExtension != nil &&
		cn.Extensions.UBLExtension.ExtensionContent != nil &&
		cn.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
		return cn.Extensions.UBLExtension.ExtensionContent.EformsExtension.Publication
	}
	return nil
}

// GetOrganizations returns organizations from extensions
func (cn ContractNotice) GetOrganizations() *Organizations {
	if cn.Extensions != nil &&
		cn.Extensions.UBLExtension != nil &&
		cn.Extensions.UBLExtension.ExtensionContent != nil &&
		cn.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
		return cn.Extensions.UBLExtension.ExtensionContent.EformsExtension.Organizations
	}
	return nil
}

// GetNoticeSubType returns the notice subtype code from extensions
func (cn ContractNotice) GetNoticeSubType() string {
	if cn.Extensions != nil &&
		cn.Extensions.UBLExtension != nil &&
		cn.Extensions.UBLExtension.ExtensionContent != nil &&
		cn.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil &&
		cn.Extensions.UBLExtension.ExtensionContent.EformsExtension.NoticeSubType != nil {
		return cn.Extensions.UBLExtension.ExtensionContent.EformsExtension.NoticeSubType.SubTypeCode
	}
	return ""
}

// GetNoticePublicationID returns the notice publication ID from extensions
func (cn ContractNotice) GetNoticePublicationID() string {
	pub := cn.GetPublicationInfo()
	if pub != nil {
		return pub.NoticePublicationID
	}
	return ""
}

// GetOJSID returns the OJS gazette ID from extensions
func (cn ContractNotice) GetOJSID() string {
	pub := cn.GetPublicationInfo()
	if pub != nil {
		return pub.GazetteID
	}
	return ""
}

// GetPublicationDate returns the publication date from extensions
func (cn ContractNotice) GetPublicationDate() string {
	pub := cn.GetPublicationInfo()
	if pub != nil {
		return pub.PublicationDate
	}
	return ""
}

// GetOrganizationByID returns an organization by its ID
func (cn ContractNotice) GetOrganizationByID(orgID string) *Organization {
	orgs := cn.GetOrganizations()
	if orgs == nil {
		return nil
	}

	for _, org := range orgs.Organization {
		if org.Company != nil &&
			org.Company.PartyIdentification != nil &&
			org.Company.PartyIdentification.ID == orgID {
			return &org
		}
	}
	return nil
}

// GetBuyerID returns the buyer organization ID from contracting party
func (cn ContractNotice) GetBuyerID() string {
	if cn.ContractingParty != nil &&
		cn.ContractingParty.Party != nil &&
		cn.ContractingParty.Party.PartyIdentification != nil {
		return cn.ContractingParty.Party.PartyIdentification.ID
	}
	return ""
}

// GetReviewOrganizationID returns the review organization ID from appeal terms
func (cn ContractNotice) GetReviewOrganizationID() string {
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.TenderingTerms != nil &&
		cn.ProcurementProjectLot.TenderingTerms.AppealTerms != nil &&
		cn.ProcurementProjectLot.TenderingTerms.AppealTerms.AppealReceiverParty != nil &&
		cn.ProcurementProjectLot.TenderingTerms.AppealTerms.AppealReceiverParty.PartyIdentification != nil {
		return cn.ProcurementProjectLot.TenderingTerms.AppealTerms.AppealReceiverParty.PartyIdentification.ID
	}
	return ""
}

// GetProcedureCode returns the type of procedure
func (cn ContractNotice) GetProcedureCode() string {
	if cn.TenderingProcess != nil {
		return cn.TenderingProcess.ProcedureCode
	}
	return ""
}

// GetProcurementTitle returns the procurement project title
func (cn ContractNotice) GetProcurementTitle() string {
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.ProcurementProject != nil {
		return cn.ProcurementProjectLot.ProcurementProject.Name
	}
	return ""
}

// GetProcurementDescription returns the procurement project description
func (cn ContractNotice) GetProcurementDescription() string {
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.ProcurementProject != nil {
		return cn.ProcurementProjectLot.ProcurementProject.Description
	}
	return ""
}

// GetContractNature returns the main nature of the contract
func (cn ContractNotice) GetContractNature() string {
	if cn.ProcurementProject != nil {
		return cn.ProcurementProject.ProcurementTypeCode
	}
	return ""
}

// GetMainClassification returns the main CPV classification code
func (cn ContractNotice) GetMainClassification() string {
	if cn.ProcurementProject != nil &&
		cn.ProcurementProject.MainCommodityClassification != nil {
		return cn.ProcurementProject.MainCommodityClassification.ItemClassificationCode
	}
	return ""
}

// GetPlaceOfPerformance returns the place of performance
func (cn ContractNotice) GetPlaceOfPerformance() string {
	if cn.ProcurementProject != nil &&
		cn.ProcurementProject.RealizedLocation != nil &&
		cn.ProcurementProject.RealizedLocation.Address != nil {
		return cn.ProcurementProject.RealizedLocation.Address.Region
	}
	return ""
}

// GetLotID returns the procurement lot ID
func (cn ContractNotice) GetLotID() string {
	if cn.ProcurementProjectLot != nil {
		return cn.ProcurementProjectLot.ID
	}
	return ""
}

// GetSelectionCriteria returns selection criteria from extensions
func (cn ContractNotice) GetSelectionCriteria() []SelectionCriteria {
	if cn.Extensions != nil &&
		cn.Extensions.UBLExtension != nil &&
		cn.Extensions.UBLExtension.ExtensionContent != nil &&
		cn.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
		return cn.Extensions.UBLExtension.ExtensionContent.EformsExtension.SelectionCriteria
	}
	return nil
}

// GetOfficialLanguages returns official languages from tender terms extensions
func (cn ContractNotice) GetOfficialLanguages() []string {
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.TenderingTerms != nil &&
		len(cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference) > 0 &&
		cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions != nil &&
		cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension != nil &&
		cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent != nil &&
		cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension != nil &&
		cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension.OfficialLanguages != nil {

		languages := make([]string, len(cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension.OfficialLanguages.Language))
		for i, lang := range cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference[0].UBLExtensions.UBLExtension.ExtensionContent.EformsExtension.OfficialLanguages.Language {
			languages[i] = lang.ID
		}
		return languages
	}
	return nil
}

// GetDocumentURI returns the document URI from call for tenders document reference
func (cn ContractNotice) GetDocumentURI() string {
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.TenderingTerms != nil &&
		len(cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference) > 0 &&
		cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference[0].Attachment != nil &&
		cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference[0].Attachment.ExternalReference != nil {
		return cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference[0].Attachment.ExternalReference.URI
	}
	return ""
}

// GetAllDocumentURIs returns all document URIs from call for tenders document references
func (cn ContractNotice) GetAllDocumentURIs() []string {
	var uris []string
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.TenderingTerms != nil {

		for _, docRef := range cn.ProcurementProjectLot.TenderingTerms.CallForTendersDocumentReference {
			if docRef.Attachment != nil &&
				docRef.Attachment.ExternalReference != nil &&
				docRef.Attachment.ExternalReference.URI != "" {
				uris = append(uris, docRef.Attachment.ExternalReference.URI)
			}
		}
	}
	return uris
}

// GetTenderDeadline returns the tender submission deadline
func (cn ContractNotice) GetTenderDeadline() string {
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.TenderingProcess != nil &&
		cn.ProcurementProjectLot.TenderingProcess.TenderSubmissionDeadlinePeriod != nil {
		return cn.ProcurementProjectLot.TenderingProcess.TenderSubmissionDeadlinePeriod.EndDate
	}
	return ""
}

// GetBudget returns the estimated contract amount and currency
func (cn ContractNotice) GetBudget() (amount string, currency string) {
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.ProcurementProject != nil &&
		cn.ProcurementProjectLot.ProcurementProject.RequestedTenderTotal != nil {

		contractAmount := cn.ProcurementProjectLot.ProcurementProject.RequestedTenderTotal.EstimatedOverallContractAmount
		return contractAmount.Text, contractAmount.CurrencyID
	}
	return "", ""
}

// GetDuration returns the contract duration and unit
func (cn ContractNotice) GetDuration() (duration string, unit string) {
	if cn.ProcurementProjectLot != nil &&
		cn.ProcurementProjectLot.ProcurementProject != nil &&
		cn.ProcurementProjectLot.ProcurementProject.PlannedPeriod != nil &&
		cn.ProcurementProjectLot.ProcurementProject.PlannedPeriod.DurationMeasure != nil {

		durationMeasure := cn.ProcurementProjectLot.ProcurementProject.PlannedPeriod.DurationMeasure
		return durationMeasure.Text, durationMeasure.UnitCode
	}
	return "", ""
}

// ==================== ContractAwardNotice Methods ====================

// Validate validates the ContractAwardNotice structure
func (can ContractAwardNotice) Validate() error {
	if can.ID == "" {
		return fmt.Errorf("contract award notice ID is required")
	}

	if can.ContractFolderID == "" {
		return fmt.Errorf("contract folder ID is required")
	}

	if can.IssueDate == "" {
		return fmt.Errorf("issue date is required")
	}

	// Validate date format - TED XML uses ISO 8601 format with timezone
	validFormats := []string{
		"2006-01-02+07:00",
		"2006-01-02-07:00",
		"2006-01-02T15:04:05+07:00",
		"2006-01-02T15:04:05-07:00",
		"2006-01-02T15:04:05Z",
		"2006-01-02Z",
		"2006-01-02",
		time.RFC3339,
		time.RFC3339Nano,
	}

	var validDate bool
	for _, format := range validFormats {
		if _, err := time.Parse(format, can.IssueDate); err == nil {
			validDate = true
			break
		}
	}

	if !validDate {
		return fmt.Errorf("invalid issue date format: %s (expected ISO 8601 format)", can.IssueDate)
	}

	// Validate language code if provided (should be 3-letter ISO code)
	if can.NoticeLanguageCode != "" && len(can.NoticeLanguageCode) != 3 {
		return fmt.Errorf("invalid notice language code: %s (expected 3-letter ISO code)", can.NoticeLanguageCode)
	}

	return nil
}

// GetID returns the contract award notice ID
func (can ContractAwardNotice) GetID() string {
	return can.ID
}

// GetNoticeType returns the notice type
func (can ContractAwardNotice) GetNoticeType() string {
	return can.NoticeTypeCode
}

// GetLanguage returns the notice language
func (can ContractAwardNotice) GetLanguage() string {
	return can.NoticeLanguageCode
}

// GetPublicationInfo returns publication information if available
func (can ContractAwardNotice) GetPublicationInfo() *Publication {
	if can.Extensions != nil &&
		can.Extensions.UBLExtension != nil &&
		can.Extensions.UBLExtension.ExtensionContent != nil &&
		can.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
		return can.Extensions.UBLExtension.ExtensionContent.EformsExtension.Publication
	}
	return nil
}

// GetOrganizations returns organizations from extensions
func (can ContractAwardNotice) GetOrganizations() *Organizations {
	if can.Extensions != nil &&
		can.Extensions.UBLExtension != nil &&
		can.Extensions.UBLExtension.ExtensionContent != nil &&
		can.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
		return can.Extensions.UBLExtension.ExtensionContent.EformsExtension.Organizations
	}
	return nil
}

// GetNoticeResult returns notice result from extensions
func (can ContractAwardNotice) GetNoticeResult() *NoticeResult {
	if can.Extensions != nil &&
		can.Extensions.UBLExtension != nil &&
		can.Extensions.UBLExtension.ExtensionContent != nil &&
		can.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil {
		return can.Extensions.UBLExtension.ExtensionContent.EformsExtension.NoticeResult
	}
	return nil
}

// GetNoticeSubType returns the notice subtype code from extensions
func (can ContractAwardNotice) GetNoticeSubType() string {
	if can.Extensions != nil &&
		can.Extensions.UBLExtension != nil &&
		can.Extensions.UBLExtension.ExtensionContent != nil &&
		can.Extensions.UBLExtension.ExtensionContent.EformsExtension != nil &&
		can.Extensions.UBLExtension.ExtensionContent.EformsExtension.NoticeSubType != nil {
		return can.Extensions.UBLExtension.ExtensionContent.EformsExtension.NoticeSubType.SubTypeCode
	}
	return ""
}

// GetNoticePublicationID returns the notice publication ID from extensions
func (can ContractAwardNotice) GetNoticePublicationID() string {
	pub := can.GetPublicationInfo()
	if pub != nil {
		return pub.NoticePublicationID
	}
	return ""
}

// GetOJSID returns the OJS gazette ID from extensions
func (can ContractAwardNotice) GetOJSID() string {
	pub := can.GetPublicationInfo()
	if pub != nil {
		return pub.GazetteID
	}
	return ""
}

// GetPublicationDate returns the publication date from extensions
func (can ContractAwardNotice) GetPublicationDate() string {
	pub := can.GetPublicationInfo()
	if pub != nil {
		return pub.PublicationDate
	}
	return ""
}

// GetBuyerID returns the buyer organization ID from contracting party
func (can ContractAwardNotice) GetBuyerID() string {
	if can.ContractingParty != nil &&
		can.ContractingParty.Party != nil &&
		can.ContractingParty.Party.PartyIdentification != nil {
		return can.ContractingParty.Party.PartyIdentification.ID
	}
	return ""
}

// GetProcedureCode returns the type of procedure
func (can ContractAwardNotice) GetProcedureCode() string {
	if can.TenderingProcess != nil {
		return can.TenderingProcess.ProcedureCode
	}
	return ""
}

// GetProcurementTitle returns the procurement project title
func (can ContractAwardNotice) GetProcurementTitle() string {
	if can.ProcurementProject != nil {
		return can.ProcurementProject.Name
	}
	return ""
}

// GetProcurementDescription returns the procurement project description
func (can ContractAwardNotice) GetProcurementDescription() string {
	if can.ProcurementProject != nil {
		return can.ProcurementProject.Description
	}
	return ""
}

// GetContractNature returns the main nature of the contract
func (can ContractAwardNotice) GetContractNature() string {
	if can.ProcurementProject != nil {
		return can.ProcurementProject.ProcurementTypeCode
	}
	return ""
}

// GetMainClassification returns the main CPV classification code
func (can ContractAwardNotice) GetMainClassification() string {
	if can.ProcurementProject != nil &&
		can.ProcurementProject.MainCommodityClassification != nil {
		return can.ProcurementProject.MainCommodityClassification.ItemClassificationCode
	}
	return ""
}

// GetTotalAwardValue returns the total award amount and currency
func (can ContractAwardNotice) GetTotalAwardValue() (amount string, currency string) {
	noticeResult := can.GetNoticeResult()
	if noticeResult != nil && noticeResult.TotalAmount != nil {
		return noticeResult.TotalAmount.Text, noticeResult.TotalAmount.CurrencyID
	}
	return "", ""
}

// GetAwardDate returns the tender award date
func (can ContractAwardNotice) GetAwardDate() string {
	if can.TenderResult != nil {
		return can.TenderResult.AwardDate
	}
	return ""
}

// GetOrganizationByID returns an organization by its ID
func (can ContractAwardNotice) GetOrganizationByID(orgID string) *Organization {
	orgs := can.GetOrganizations()
	if orgs == nil {
		return nil
	}

	for _, org := range orgs.Organization {
		if org.Company != nil &&
			org.Company.PartyIdentification != nil &&
			org.Company.PartyIdentification.ID == orgID {
			return &org
		}
	}
	return nil
}
