import { CIIBaseValidator } from '../cii.validator.js';
import { ValidationLevel } from '../../../interfaces/common.js';
import type { ValidationResult } from '../../../interfaces/common.js';

/**
 * Validator for Factur-X invoice format
 * Implements validation rules according to EN16931 and Factur-X specification
 */
export class FacturXValidator extends CIIBaseValidator {
  /**
   * Validates structure of the Factur-X XML document
   * @returns True if structure validation passed
   */
  protected validateStructure(): boolean {
    if (!this.doc) return false;

    let valid = true;

    // Check for required main sections
    const sections = [
      'rsm:ExchangedDocumentContext',
      'rsm:ExchangedDocument',
      'rsm:SupplyChainTradeTransaction'
    ];

    for (const section of sections) {
      if (!this.exists(section)) {
        this.addError('FX-STRUCT-1', `Required section ${section} is missing`, '/rsm:CrossIndustryInvoice');
        valid = false;
      }
    }

    // Check for SupplyChainTradeTransaction sections
    if (this.exists('rsm:SupplyChainTradeTransaction')) {
      const tradeSubsections = [
        'ram:ApplicableHeaderTradeAgreement',
        'ram:ApplicableHeaderTradeDelivery',
        'ram:ApplicableHeaderTradeSettlement'
      ];

      for (const subsection of tradeSubsections) {
        if (!this.exists(`rsm:SupplyChainTradeTransaction/${subsection}`)) {
          this.addError('FX-STRUCT-2', `Required subsection ${subsection} is missing`,
            '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction');
          valid = false;
        }
      }
    }

    return valid;
  }

  /**
   * Validates business rules
   * @returns True if business rule validation passed
   */
  protected validateBusinessRules(): boolean {
    if (!this.doc) return false;

    let valid = true;

    // BR-16: Amount due for payment (BT-115) = Invoice total amount with VAT (BT-112) - Paid amount (BT-113)
    valid = this.validateAmounts() && valid;

    // BR-CO-3: Value added tax point date (BT-7) and Value added tax point date code (BT-8) are mutually exclusive
    valid = this.validateMutuallyExclusiveFields() && valid;

    // BR-S-1: An Invoice that contains a line (BG-25) where the Invoiced item VAT category code (BT-151) is "Standard rated"
    // shall contain the Seller VAT Identifier (BT-31), the Seller tax registration identifier (BT-32)
    // and/or the Seller tax representative VAT identifier (BT-63).
    valid = this.validateSellerVatIdentifier() && valid;

    return valid;
  }

  /**
   * Validates amount calculations in the invoice
   * @returns True if amount validation passed
   */
  private validateAmounts(): boolean {
    if (!this.doc) return false;

    try {
      // Extract amounts
      const totalAmount = this.getNumber(
        '//ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:GrandTotalAmount'
      );

      const paidAmount = this.getNumber(
        '//ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:TotalPrepaidAmount'
      ) || 0;

      const dueAmount = this.getNumber(
        '//ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:DuePayableAmount'
      );

      // Calculate expected due amount
      const expectedDueAmount = totalAmount - paidAmount;

      // Compare with a small tolerance for rounding errors
      if (Math.abs(dueAmount - expectedDueAmount) > 0.01) {
        this.addError(
          'BR-16',
          `Amount due for payment (${dueAmount}) must equal Invoice total amount with VAT (${totalAmount}) - Paid amount (${paidAmount})`,
          '//ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation'
        );
        return false;
      }

      return true;
    } catch (error) {
      this.addError('FX-AMOUNT', `Error validating amounts: ${error}`, '/');
      return false;
    }
  }

  /**
   * Validates mutually exclusive fields
   * @returns True if validation passed
   */
  private validateMutuallyExclusiveFields(): boolean {
    if (!this.doc) return false;

    try {
      // Check for VAT point date and code (BR-CO-3)
      const vatPointDate = this.exists('//ram:ApplicableHeaderTradeSettlement/ram:ApplicableTradeTax/ram:TaxPointDate');
      const vatPointDateCode = this.exists('//ram:ApplicableHeaderTradeSettlement/ram:ApplicableTradeTax/ram:DueDateTypeCode');

      if (vatPointDate && vatPointDateCode) {
        this.addError(
          'BR-CO-3',
          'Value added tax point date and Value added tax point date code are mutually exclusive',
          '//ram:ApplicableHeaderTradeSettlement/ram:ApplicableTradeTax'
        );
        return false;
      }

      return true;
    } catch (error) {
      this.addError('FX-MUTUAL', `Error validating mutually exclusive fields: ${error}`, '/');
      return false;
    }
  }

  /**
   * Validates seller VAT identifier requirements
   * @returns True if validation passed
   */
  private validateSellerVatIdentifier(): boolean {
    if (!this.doc) return false;

    try {
      // Check if there are any standard rated line items
      const standardRatedItems = this.exists(
        '//ram:SpecifiedLineTradeSettlement/ram:ApplicableTradeTax/ram:CategoryCode[text()="S"]'
      );

      if (standardRatedItems) {
        // Check for seller VAT identifier
        const sellerVatId = this.exists('//ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID="VA"]');
        const sellerTaxId = this.exists('//ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID="FC"]');
        const sellerTaxRepId = this.exists('//ram:ApplicableHeaderTradeAgreement/ram:SellerTaxRepresentativeTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID="VA"]');

        if (!sellerVatId && !sellerTaxId && !sellerTaxRepId) {
          this.addError(
            'BR-S-1',
            'An Invoice with standard rated items must contain the Seller VAT Identifier, Tax registration identifier or Tax representative VAT identifier',
            '//ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty'
          );
          return false;
        }
      }

      return true;
    } catch (error) {
      this.addError('FX-VAT', `Error validating seller VAT identifier: ${error}`, '/');
      return false;
    }
  }
}