<?php
// procesar_facturas.php

// 1) CONFIGURACIÓN
$baseDir = __DIR__;
$zipDir  = "$baseDir/zipFacturas";
$outDir  = "$baseDir/archivoDigital";
require "$baseDir/db/db.php";  // tu conexión MySQLi en $conn

// 2) Helpers
$conn->set_charset('utf8mb4');

function rrmdir(string $dir)
{
    if (!is_dir($dir)) return;
    foreach (scandir($dir) as $f) {
        if ($f === '.' || $f === '..') continue;
        $path = "$dir/$f";
        is_dir($path) ? rrmdir($path) : unlink($path);
    }
    rmdir($dir);
}

function xpathFirst($xml, $expr)
{
    $n = $xml->xpath($expr);
    return ($n && isset($n[0])) ? (string)$n[0] : '';
}
function xpathFirstFloat($xml, $expr)
{
    $v = xpathFirst($xml, $expr);
    return $v !== '' ? (float)$v : 0.0;
}

// 3) Limpieza inicial: en zipFacturas, borrar todo lo que NO sea .zip
foreach (scandir($zipDir) as $item) {
    if ($item === '.' || $item === '..') continue;
    $path = "$zipDir/$item";
    if (is_file($path)) {
        if (strtolower(pathinfo($path, PATHINFO_EXTENSION)) !== 'zip') {
            unlink($path);
        }
    } elseif (is_dir($path)) {
        // directorio residual
        rrmdir($path);
    }
}

// 4) Procesar cada ZIP
foreach (glob("$zipDir/*.zip") as $zipPath) {
    $zipName = basename($zipPath);

    // 4.1) ¿Ya procesado?
    $chk = $conn->prepare("SELECT COUNT(*) FROM tb_archivo_digital WHERE nombreArchivo = ?");
    $chk->bind_param('s', $zipName);
    $chk->execute();
    $chk->bind_result($cnt);
    $chk->fetch();
    $chk->close();
    if ($cnt > 0) continue;

    // 4.2) Descomprimir
    $tmpDir = "$zipDir/tmp_" . pathinfo($zipName, PATHINFO_FILENAME);
    @mkdir($tmpDir, 0755, true);
    $zip = new ZipArchive;
    if ($zip->open($zipPath) !== true) {
        echo "Error abriendo $zipName\n";
        continue;
    }
    $zip->extractTo($tmpDir);
    $zip->close();

    // 4.3) Localizar PDF y XML
    $pdfs = glob("$tmpDir/*.pdf");
    $xmls = glob("$tmpDir/*.xml");
    if (empty($pdfs) || empty($xmls)) {
        rrmdir($tmpDir);
        continue;
    }
    $pdfFile = $pdfs[0];
    $xmlFile = $xmls[0];

    // 4.4) Cargar el XML
    $xml = simplexml_load_file($xmlFile);
    $xml->registerXPathNamespace('cac', 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2');
    $xml->registerXPathNamespace('cbc', 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2');

    // 4.5) Detectar qué tenemos: Invoice/ CreditNote directo o dentro de AttachedDocument
    $root = $xml->getName();
    if ($root === 'Invoice' || $root === 'CreditNote') {
        $inv = $xml;
    } else {
        // buscar CDATA con <Invoice> o <CreditNote>
        $found = '';
        foreach ($xml->xpath('//cac:Attachment/cac:ExternalReference/cbc:Description') as $node) {
            $txt = trim((string)$node);
            if (strpos($txt, '<Invoice') !== false || strpos($txt, '<CreditNote') !== false) {
                $found = $txt;
                break;
            }
        }
        if ($found === '') {
            rrmdir($tmpDir);
            throw new Exception("No encontré ni <Invoice> ni <CreditNote> embebido en $xmlFile");
        }
        $inv = simplexml_load_string($found);
    }

    // 4.6) Registrar namespaces en la factura/nota
    $inv->registerXPathNamespace('cac', 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2');
    $inv->registerXPathNamespace('cbc', 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2');

    // 5) Cabecera común
    $noFac  = xpathFirst($inv, '//cbc:ID');
    // REEMPLAZA POR:
    $cufe = xpathFirst($inv, '//cbc:UUID[@schemeName="CUFE-SHA384"]');
    $fFact  = xpathFirst($inv, '//cbc:IssueDate') . ' ' . xpathFirst($inv, '//cbc:IssueTime');
    $prov   = xpathFirst($inv, '//cac:AccountingSupplierParty//cbc:RegistrationName');
    $nit    = xpathFirst($inv, '//cac:AccountingSupplierParty//cbc:CompanyID');
    $ben    = xpathFirst($inv, '//cac:AccountingCustomerParty//cbc:RegistrationName');
    $nitBen = xpathFirst($inv, '//cac:AccountingCustomerParty//cbc:CompanyID');
    $fVenc  = xpathFirst($inv, '//cbc:DueDate') ?: null;
    $subt   = xpathFirstFloat($inv, '//cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount');
    $imp    = xpathFirstFloat($inv, '//cac:TaxTotal/cbc:TaxAmount');
    $tot    = xpathFirstFloat($inv, '//cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount');
    $notes  = $inv->xpath('//cbc:Note') ?: [];
    $obs    = implode("\n", array_map('strval', $notes));

    // 6) Mover PDF+XML a carpeta por NIT
    $destDir = "$outDir/$nit";
    @mkdir($destDir, 0755, true);
    rename($pdfFile, "$destDir/$noFac.pdf");
    rename($xmlFile, "$destDir/$noFac.xml");

    // 7) Insertar cabecera en tb_archivo_digital
    $conn->begin_transaction();
    $ins = $conn->prepare(
        "INSERT INTO tb_archivo_digital
         (cufe,nombreArchivo,fechaFactura,noFactura,proveedor,nit,
          beneficiario,nitBeneficiario,fechaVencimiento,subtotal,impuestos,total,observaciones)
         VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"
    );
    $ins->bind_param(
        'sssssssssddds',
        $cufe,
        $zipName,
        $fFact,
        $noFac,
        $prov,
        $nit,
        $ben,
        $nitBen,
        $fVenc,
        $subt,
        $imp,
        $tot,
        $obs
    );
    $ins->execute();
    $idArch = $conn->insert_id;
    $ins->close();

    // 8) Detalle: líneas InvoiceLine o CreditNoteLine según corresponda
    $lineTag   = ($inv->getName() === 'CreditNote') ? 'CreditNoteLine' : 'InvoiceLine';
    $qtyExpr   = ($inv->getName() === 'CreditNote') ? './/cbc:CreditedQuantity' : './/cbc:InvoicedQuantity';

    $det = $conn->prepare(
        "INSERT INTO tb_archivo_digital_detalle
         (idArchivo,referencia,descripcion,cantidad,unidad,
          precioUnitario,descuentos,subtotal,impuesto,total)
         VALUES (?,?,?,?,?,?,?,?,?,?)"
    );
    $det->bind_param(
        'issdsddddd',
        $idArch,
        $ref,
        $descL,
        $cant,
        $unit,
        $price,
        $disc,
        $subL,
        $impL,
        $totL
    );

    foreach ($inv->xpath("//cac:$lineTag") as $ln) {
        $ref   = xpathFirst($ln, ".//cac:SellersItemIdentification/cbc:ID");
        $descL = xpathFirst($ln, ".//cac:Item/cbc:Description");
        $cant  = xpathFirstFloat($ln, $qtyExpr);
        $unit  = (string)$ln->xpath($qtyExpr)[0]->attributes()->unitCode;
        $price = xpathFirstFloat($ln, './/cac:Price/cbc:PriceAmount');
        $disc  = $ln->xpath('.//cac:AllowanceCharge')
            ? xpathFirstFloat($ln, './/cac:AllowanceCharge/cbc:Amount')
            : 0.0;
        $subL  = xpathFirstFloat($ln, './/cbc:LineExtensionAmount');
        $impL  = xpathFirstFloat($ln, './/cac:TaxTotal/cbc:TaxAmount');
        $totL  = $subL + $impL;
        $det->execute();
    }
    $det->close();
    $conn->commit();

    // 9) Limpieza temporal
    rrmdir($tmpDir);

    echo "Procesado: $zipName → documento $noFac\n";
}
