<?php
if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * UAE FTA VAT compliance helpers.
 *
 * Handles:
 * - TRN validation (15-digit UAE Tax Registration Number)
 * - Standard vs. Simplified invoice determination (AED 10,000 threshold)
 * - VAT calculation and AED conversion
 * - QR code data string (FTA-style)
 * - PINT AE XML generation
 */
class PBUAIV_FTA_Compliance {

    // AED 10,000 threshold: below = simplified, at or above = standard
    const SIMPLIFIED_THRESHOLD_AED = 10000;
    const UAE_VAT_RATE              = 5.0;
    const UAE_CURRENCY              = 'AED';

    /**
     * Validate a UAE TRN (Tax Registration Number).
     * Format: 15 digits, starting with 1 (for individuals) or 3 (for entities).
     */
    public static function validate_trn( string $trn ) : bool {
        $trn = preg_replace( '/\s+/', '', $trn );
        if ( ! preg_match( '/^\d{15}$/', $trn ) ) return false;
        // UAE TRN starts with 1 or 3
        return in_array( $trn[0], [ '1', '3' ], true );
    }

    /**
     * Determine invoice type based on order total in AED.
     * Returns 'standard' or 'simplified'.
     */
    public static function invoice_type( float $total_aed, string $customer_type = 'b2c' ) : string {
        if ( $customer_type === 'b2b' ) return 'standard';
        return $total_aed >= self::SIMPLIFIED_THRESHOLD_AED ? 'standard' : 'simplified';
    }

    /**
     * Convert order total to AED using the configured exchange rate.
     */
    public static function to_aed( float $amount, string $currency ) : float {
        if ( $currency === 'AED' ) return $amount;
        $rate = (float) get_option( 'pbuaiv_currency_aed_rate', 1 );
        // If a rate table is configured, look it up
        $rates = get_option( 'pbuaiv_exchange_rates', [] );
        if ( ! empty( $rates[ $currency ] ) ) {
            $rate = (float) $rates[ $currency ];
        }
        return round( $amount * $rate, 2 );
    }

    /**
     * Format VAT amount for display.
     * The FTA requires the VAT amount to always be shown in AED.
     *
     * @return array [ 'original' => float, 'aed' => float, 'formatted' => string ]
     */
    public static function format_vat_amount( float $vat_amount, string $order_currency ) : array {
        $aed = self::to_aed( $vat_amount, $order_currency );
        return [
            'original'  => round( $vat_amount, 2 ),
            'aed'       => $aed,
            'formatted' => 'AED ' . number_format( $aed, 2 ),
        ];
    }

    /**
     * Build the QR code data string for FTA-style invoice QR codes.
     * Format: TLV (Tag-Length-Value) encoded, Base64.
     *
     * Tags:
     *  1 = Seller name
     *  2 = TRN
     *  3 = Invoice date/time
     *  4 = Invoice total (incl. VAT)
     *  5 = VAT amount
     */
    public static function build_qr_data( string $seller_name, string $trn, string $date, float $total, float $vat ) : string {
        $tlv = '';
        $fields = [
            1 => $seller_name,
            2 => $trn,
            3 => $date,
            4 => number_format( $total, 2, '.', '' ),
            5 => number_format( $vat,   2, '.', '' ),
        ];
        foreach ( $fields as $tag => $value ) {
            $encoded = mb_convert_encoding( $value, 'UTF-8' );
            $len     = strlen( $encoded );
            $tlv    .= chr( $tag ) . chr( $len ) . $encoded;
        }
        return base64_encode( $tlv );
    }


    /**
     * Generate a local SVG data URI for the FTA invoice QR area.
     *
     * This intentionally avoids remote QR services and unmaintained bundled QR
     * libraries, so invoice data never leaves the WordPress site. The pattern is
     * generated locally from the FTA TLV payload and embedded as an SVG data URI.
     *
     * @param string $data The TLV Base64 string to encode visually.
     * @param int    $size Output image size in pixels (square).
     * @return string data:image/svg+xml;base64,... URI ready for use in <img src>.
     */
    /**
     * Generate an ISO/IEC 18004-compliant QR code as an SVG data URI.
     * Delegates to PBUAIV_QR_Code which implements byte-mode encoding
     * with ECC level M and proper Reed-Solomon error correction.
     */
    public static function qr_svg_data_uri( string $data, int $size = 90 ) : string {
        if ( empty( $data ) ) {
            return '';
        }
        return PBUAIV_QR_Code::svg_data_uri( $data, absint( $size ) );
    }

    /**
     * Get VAT category label for a rate.
     */
    public static function vat_category( float $rate ) : string {
        if ( $rate === 0.0 ) return __( 'Zero-Rated (0%)', 'pb-invoicing-system' );
        if ( $rate === 5.0 ) return __( 'Standard Rate (5%)', 'pb-invoicing-system' );
        return __( 'Exempt', 'pb-invoicing-system' );
    }

    /**
     * Check all FTA mandatory fields are present for a standard invoice.
     *
     * @return array List of missing field labels (empty = all present)
     */
    public static function validate_mandatory_fields( array $data ) : array {
        $required = [
            'supplier_name'    => __( 'Supplier Name', 'pb-invoicing-system' ),
            'supplier_address' => __( 'Supplier Address', 'pb-invoicing-system' ),
            'supplier_trn'     => __( 'Supplier TRN', 'pb-invoicing-system' ),
            'doc_number'       => __( 'Invoice Number', 'pb-invoicing-system' ),
            'doc_date'         => __( 'Invoice Date', 'pb-invoicing-system' ),
            'supply_date'      => __( 'Date of Supply', 'pb-invoicing-system' ),
            'line_items'       => __( 'Line Items', 'pb-invoicing-system' ),
            'vat_amount'       => __( 'VAT Amount (AED)', 'pb-invoicing-system' ),
            'total_amount'     => __( 'Total Amount', 'pb-invoicing-system' ),
        ];
        $missing = [];
        foreach ( $required as $key => $label ) {
            if ( empty( $data[ $key ] ) ) $missing[] = $label;
        }
        return $missing;
    }

    /**
     * Generate PINT AE XML for e-invoicing mandate compliance.
     * (UAE e-invoicing mandatory from Jan 2027 for ≥AED 50M revenue businesses)
     */
    public static function generate_xml( array $invoice_data ) : string {
        $xml  = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
        $xml .= '<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"' . "\n";
        $xml .= '         xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"' . "\n";
        $xml .= '         xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">' . "\n";

        // Header
        $xml .= '  <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0#conformant#urn:fdc:peppol.eu:2017:poacc:billing:UAE#1.0</cbc:CustomizationID>' . "\n";
        $xml .= '  <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>' . "\n";
        $xml .= '  <cbc:ID>' . self::esc_xml( $invoice_data['doc_number'] ) . '</cbc:ID>' . "\n";
        $xml .= '  <cbc:IssueDate>' . self::esc_xml( $invoice_data['doc_date'] ) . '</cbc:IssueDate>' . "\n";
        $xml .= '  <cbc:TaxPointDate>' . self::esc_xml( $invoice_data['supply_date'] ?? $invoice_data['doc_date'] ) . '</cbc:TaxPointDate>' . "\n";
        $xml .= '  <cbc:InvoiceTypeCode>' . ( $invoice_data['invoice_type'] === 'credit_note' ? '381' : '380' ) . '</cbc:InvoiceTypeCode>' . "\n";
        $xml .= '  <cbc:DocumentCurrencyCode>' . self::esc_xml( $invoice_data['currency'] ?? 'AED' ) . '</cbc:DocumentCurrencyCode>' . "\n";
        $xml .= '  <cbc:TaxCurrencyCode>AED</cbc:TaxCurrencyCode>' . "\n";

        // Supplier
        $xml .= '  <cac:AccountingSupplierParty>' . "\n";
        $xml .= '    <cac:Party>' . "\n";
        $xml .= '      <cac:PartyTaxScheme>' . "\n";
        $xml .= '        <cbc:CompanyID>' . self::esc_xml( $invoice_data['supplier_trn'] ) . '</cbc:CompanyID>' . "\n";
        $xml .= '        <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>' . "\n";
        $xml .= '      </cac:PartyTaxScheme>' . "\n";
        $xml .= '      <cac:PartyLegalEntity>' . "\n";
        $xml .= '        <cbc:RegistrationName>' . self::esc_xml( $invoice_data['supplier_name'] ) . '</cbc:RegistrationName>' . "\n";
        $xml .= '      </cac:PartyLegalEntity>' . "\n";
        $xml .= '    </cac:Party>' . "\n";
        $xml .= '  </cac:AccountingSupplierParty>' . "\n";

        // Buyer
        $xml .= '  <cac:AccountingCustomerParty>' . "\n";
        $xml .= '    <cac:Party>' . "\n";
        if ( ! empty( $invoice_data['buyer_trn'] ) ) {
            $xml .= '      <cac:PartyTaxScheme>' . "\n";
            $xml .= '        <cbc:CompanyID>' . self::esc_xml( $invoice_data['buyer_trn'] ) . '</cbc:CompanyID>' . "\n";
            $xml .= '        <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>' . "\n";
            $xml .= '      </cac:PartyTaxScheme>' . "\n";
        }
        $xml .= '      <cac:PartyLegalEntity>' . "\n";
        $xml .= '        <cbc:RegistrationName>' . self::esc_xml( $invoice_data['buyer_name'] ) . '</cbc:RegistrationName>' . "\n";
        $xml .= '      </cac:PartyLegalEntity>' . "\n";
        $xml .= '    </cac:Party>' . "\n";
        $xml .= '  </cac:AccountingCustomerParty>' . "\n";

        // Tax total
        $xml .= '  <cac:TaxTotal>' . "\n";
        $xml .= '    <cbc:TaxAmount currencyID="AED">' . number_format( (float)$invoice_data['vat_amount_aed'], 2, '.', '' ) . '</cbc:TaxAmount>' . "\n";
        $xml .= '  </cac:TaxTotal>' . "\n";

        // Legal monetary total
        $xml .= '  <cac:LegalMonetaryTotal>' . "\n";
        $xml .= '    <cbc:LineExtensionAmount currencyID="' . self::esc_xml( $invoice_data['currency'] ?? 'AED' ) . '">' . number_format( (float)$invoice_data['subtotal'], 2, '.', '' ) . '</cbc:LineExtensionAmount>' . "\n";
        $xml .= '    <cbc:TaxInclusiveAmount currencyID="' . self::esc_xml( $invoice_data['currency'] ?? 'AED' ) . '">' . number_format( (float)$invoice_data['total'], 2, '.', '' ) . '</cbc:TaxInclusiveAmount>' . "\n";
        $xml .= '    <cbc:PayableAmount currencyID="' . self::esc_xml( $invoice_data['currency'] ?? 'AED' ) . '">' . number_format( (float)$invoice_data['total'], 2, '.', '' ) . '</cbc:PayableAmount>' . "\n";
        $xml .= '  </cac:LegalMonetaryTotal>' . "\n";

        // Line items
        if ( ! empty( $invoice_data['line_items'] ) ) {
            foreach ( $invoice_data['line_items'] as $i => $item ) {
                $xml .= '  <cac:InvoiceLine>' . "\n";
                $xml .= '    <cbc:ID>' . ( $i + 1 ) . '</cbc:ID>' . "\n";
                $xml .= '    <cbc:InvoicedQuantity unitCode="C62">' . (float)$item['qty'] . '</cbc:InvoicedQuantity>' . "\n";
                $xml .= '    <cbc:LineExtensionAmount currencyID="' . self::esc_xml( $invoice_data['currency'] ?? 'AED' ) . '">' . number_format( (float)$item['subtotal'], 2, '.', '' ) . '</cbc:LineExtensionAmount>' . "\n";
                $xml .= '    <cac:Item><cbc:Name>' . self::esc_xml( $item['name'] ) . '</cbc:Name></cac:Item>' . "\n";
                $xml .= '    <cac:Price><cbc:PriceAmount currencyID="' . self::esc_xml( $invoice_data['currency'] ?? 'AED' ) . '">' . number_format( (float)$item['price'], 2, '.', '' ) . '</cbc:PriceAmount></cac:Price>' . "\n";
                $xml .= '  </cac:InvoiceLine>' . "\n";
            }
        }

        $xml .= '</Invoice>';
        return $xml;
    }

    /**
     * Helper: escape XML special characters.
     */
    private static function esc_xml( string $str ) : string {
        return htmlspecialchars( $str, ENT_XML1 | ENT_QUOTES, 'UTF-8' );
    }
}
