<?php

namespace App\Core;

/**
 * JoFotara (Jordan E-Invoicing) Integration Core
 * Handles UBL 2.1 XML Generation, Cryptography, and API Communication
 */
class JoFotara
{
    private string $baseUrl = 'https://backend.jofotara.gov.jo/core/invoices/';

    /**
     * 1. Generate UBL 2.1 XML for an invoice
     */
    public function generateXML(array $invoice, array $company): string
    {
        $issueDate = $invoice['invoice_date'] ?? date('Y-m-d');
        $issueTime = date('H:i:s');
        $typeCode  = $invoice['ubl_type_code'] ?? '388';
        $category  = $invoice['invoice_category'] ?? 'simplified';

        // Prepare data outside heredoc for clean interpolation
        $buyerName = $this->xmlEscape($invoice['buyer_name'] ?: 'عميل نقدي');
        $buyerId   = $invoice['buyer_tin'] ?: $invoice['buyer_national_id'] ?: '000000000';
        $payMethod = $invoice['payment_method_code'] ?: '013';
        $supplierName = $this->xmlEscape($company['name']);
        $supplierAddress = $this->xmlEscape($company['address'] ?? '');

        $xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
         xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
         xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">

    <cbc:UBLVersionID>2.1</cbc:UBLVersionID>
    <cbc:CustomizationID>urn:www.cen.eu:en16931:2017#compliant#urn:www.josefotara.jo:trns:ubl:3.0</cbc:CustomizationID>
    <cbc:ProfileID>reporting:1.0</cbc:ProfileID>
    <cbc:ID>{$invoice['invoice_number']}</cbc:ID>
    <cbc:IssueDate>{$issueDate}</cbc:IssueDate>
    <cbc:IssueTime>{$issueTime}</cbc:IssueTime>
    <cbc:InvoiceTypeCode name="{$category}">{$typeCode}</cbc:InvoiceTypeCode>
    <cbc:DocumentCurrencyCode>JOD</cbc:DocumentCurrencyCode>
    <cbc:TaxCurrencyCode>JOD</cbc:TaxCurrencyCode>

    <cac:AccountingSupplierParty>
        <cac:Party>
            <cac:PartyName><cbc:Name>{$supplierName}</cbc:Name></cac:PartyName>
            <cac:PostalAddress>
                <cbc:StreetName>{$supplierAddress}</cbc:StreetName>
                <cac:Country><cbc:IdentificationCode>JO</cbc:IdentificationCode></cac:Country>
            </cac:PostalAddress>
            <cac:PartyTaxScheme>
                <cbc:CompanyID>{$company['tax_identification_number']}</cbc:CompanyID>
                <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
            </cac:PartyTaxScheme>
            <cac:PartyLegalEntity>
                <cbc:RegistrationName>{$supplierName}</cbc:RegistrationName>
            </cac:PartyLegalEntity>
        </cac:Party>
    </cac:AccountingSupplierParty>

    <cac:AccountingCustomerParty>
        <cac:Party>
            <cac:PartyName><cbc:Name>{$buyerName}</cbc:Name></cac:PartyName>
            <cac:PartyTaxScheme>
                <cbc:CompanyID>{$buyerId}</cbc:CompanyID>
                <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
            </cac:PartyTaxScheme>
        </cac:Party>
    </cac:AccountingCustomerParty>

    <cac:PaymentMeans>
        <cbc:PaymentMeansCode>{$payMethod}</cbc:PaymentMeansCode>
    </cac:PaymentMeans>

    <cac:TaxTotal>
        <cbc:TaxAmount currencyID="JOD">{$this->fmt($invoice['tax_amount'])}</cbc:TaxAmount>
        <cac:TaxSubtotal>
            <cbc:TaxableAmount currencyID="JOD">{$this->fmt($invoice['subtotal'] - $invoice['discount_total'])}</cbc:TaxableAmount>
            <cbc:TaxAmount currencyID="JOD">{$this->fmt($invoice['tax_amount'])}</cbc:TaxAmount>
            <cac:TaxCategory>
                <cbc:ID>S</cbc:ID>
                <cbc:Percent>16.000</cbc:Percent>
                <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
            </cac:TaxCategory>
        </cac:TaxSubtotal>
    </cac:TaxTotal>

    <cac:LegalMonetaryTotal>
        <cbc:LineExtensionAmount currencyID="JOD">{$this->fmt($invoice['subtotal'])}</cbc:LineExtensionAmount>
        <cbc:TaxExclusiveAmount currencyID="JOD">{$this->fmt($invoice['subtotal'] - $invoice['discount_total'])}</cbc:TaxExclusiveAmount>
        <cbc:TaxInclusiveAmount currencyID="JOD">{$this->fmt($invoice['grand_total'])}</cbc:TaxInclusiveAmount>
        <cbc:AllowanceTotalAmount currencyID="JOD">{$this->fmt($invoice['discount_total'])}</cbc:AllowanceTotalAmount>
        <cbc:PayableAmount currencyID="JOD">{$this->fmt($invoice['grand_total'])}</cbc:PayableAmount>
    </cac:LegalMonetaryTotal>

    {$this->buildInvoiceLines($invoice['items'])}
</Invoice>
XML;
        return $xml;
    }

    private function buildInvoiceLines(array $items): string
    {
        $result = '';
        foreach ($items as $item) {
            $taxAmount = round($item['line_total'] * $item['tax_rate'], 3);
            $taxCategory = $item['tax_rate'] > 0 ? 'S' : 'Z';

            $result .= <<<XML
    <cac:InvoiceLine>
        <cbc:ID>{$item['line_number']}</cbc:ID>
        <cbc:InvoicedQuantity unitCode="PCE">{$this->fmt($item['quantity'])}</cbc:InvoicedQuantity>
        <cbc:LineExtensionAmount currencyID="JOD">{$this->fmt($item['line_total'])}</cbc:LineExtensionAmount>
        <cac:TaxTotal>
            <cbc:TaxAmount currencyID="JOD">{$this->fmt($taxAmount)}</cbc:TaxAmount>
            <cac:TaxSubtotal>
                <cbc:TaxableAmount currencyID="JOD">{$this->fmt($item['line_total'])}</cbc:TaxableAmount>
                <cbc:TaxAmount currencyID="JOD">{$this->fmt($taxAmount)}</cbc:TaxAmount>
                <cac:TaxCategory>
                    <cbc:ID>{$taxCategory}</cbc:ID>
                    <cbc:Percent>{$this->fmt($item['tax_rate'] * 100)}</cbc:Percent>
                    <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
                </cac:TaxCategory>
            </cac:TaxSubtotal>
        </cac:TaxTotal>
        <cac:Item>
            <cbc:Description>{$this->xmlEscape($item['description'])}</cbc:Description>
        </cac:Item>
        <cac:Price>
            <cbc:PriceAmount currencyID="JOD">{$this->fmt($item['unit_price'])}</cbc:PriceAmount>
        </cac:Price>
    </cac:InvoiceLine>
XML;
        }
        return $result;
    }

    private function fmt(float $val): string { return number_format($val, 3, '.', ''); }
    private function xmlEscape(string $str): string { return htmlspecialchars($str, ENT_XML1, 'UTF-8'); }

    /**
     * 2. Generate Base64 TLV QR Code (Local Fallback)
     */
    public function generateQRCode(array $invoiceData): string
    {
        $sellerName = $invoiceData['supplier_name'] ?? '';
        $taxNumber  = $invoiceData['supplier_tin'] ?? '';
        $timestamp  = date('Y-m-d\TH:i:s\Z', strtotime($invoiceData['invoice_date'] ?? 'now'));
        $total      = number_format($invoiceData['grand_total'] ?? 0, 3, '.', '');
        $vat        = number_format($invoiceData['tax_amount'] ?? 0, 3, '.', '');

        $tlv = $this->toTLV(1, $sellerName) .
               $this->toTLV(2, $taxNumber) .
               $this->toTLV(3, $timestamp) .
               $this->toTLV(4, $total) .
               $this->toTLV(5, $vat);

        return base64_encode($tlv);
    }

    private function toTLV(int $tag, string $value): string
    {
        return chr($tag) . chr(strlen($value)) . $value;
    }

    /**
     * 3. Submit Invoice to JoFotara API
     */
    public function submitInvoice(string $xmlContent, string $clientId, string $secretKey): array
    {
        // For production, we must encode XML in Base64 and wrap in JSON
        $payload = json_encode([
            'invoice' => base64_encode($xmlContent)
        ]);

        $ch = curl_init($this->baseUrl);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $payload,
            CURLOPT_HTTPHEADER     => [
                'Content-Type: application/json',
                "ClientId: $clientId",
                "SecretKey: $secretKey"
            ],
            CURLOPT_TIMEOUT => 30
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $decoded = json_decode($response, true) ?? [];
        $decoded['_http_code'] = $httpCode;

        if ($httpCode === 200) {
            return [
                'success' => true,
                'uuid' => $decoded['invoiceUUID'] ?? $decoded['uuid'] ?? 'mock-' . uniqid(),
                'qrCode' => $decoded['qrCode'] ?? $decoded['QRCode'] ?? null,
                'raw' => $decoded
            ];
        }

        return [
            'success' => false,
            'error' => $decoded['errorMessage'] ?? 'API Connection Failed',
            'raw' => $decoded
        ];
    }
}
