<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
ini_set('memory_limit', '512M');
ini_set('max_execution_time', 300);
session_start();
$_SESSION['progress'] = 0;

// Verificar permisos de directorio temporal
if (!is_writable(sys_get_temp_dir())) {
    die("Error: El directorio temporal no tiene permisos de escritura");
}

require 'conexion_db.php';
require 'vendor/autoload.php';

use GuzzleHttp\Client;

if (!isset($_SESSION['id_empresa'])) {
    http_response_code(401);
    exit("No autorizado");
}
$id_empresa = $_SESSION['id_empresa'];


// Validar fechas
$fecha_inicio = $_POST['fecha_inicio'] ?? date('Y-m-d');
$fecha_fin = $_POST['fecha_fin'] ?? date('Y-m-d');
$sucursal_filtro = $_POST['sucursal'] ?? '';
$tipo_filtro = $_POST['tipo_comprobante'] ?? '';

// Obtener nombre de empresa
$stmt = $conexion->prepare("SELECT nombre_empresa FROM empresas WHERE id_empresa = ?");
$stmt->bind_param("i", $id_empresa);
$stmt->execute();
$empresaRow = $stmt->get_result()->fetch_assoc();

if (!$empresaRow) {
    error_log("Empresa no encontrada para ID: $id_empresa");
    exit("Empresa no encontrada");
}

$empresaNombre = preg_replace('/\s+/', '_', $empresaRow['nombre_empresa']);
$companyDb = strtolower(str_replace(' ', '_', $empresaRow['nombre_empresa']));

// Conectar a BD de la empresa
$db = new mysqli("localhost", "root", "Nicole_07", $companyDb);
if ($db->connect_error) {
    error_log("Error de conexión a BD empresa: " . $db->connect_error);
    die("Error BD empresa: " . $db->connect_error);
}

$mapa = [
    "01" => "Factura",
    "03" => "Comprobante_de_credito_fiscal",
    "04" => "Nota_de_remision",
    "05" => "Nota_de_Credito",
    "06" => "Nota_de_Debito",
    "07" => "Comprobante_de_retencion",
    "08" => "Comprobante_de_liquidacion",
    "09" => "Documento_contable_de_liquidacion",
    "11" => "Facturas_de_exportacion",
    "14" => "Factura_de_sujeto_excluido",
    "15" => "Comprobante_de_donacion",
];

// Preparar directorio temporal
$tmpBase = sys_get_temp_dir() . "/dl_" . session_id() . "_all";
if (!is_dir($tmpBase)) {
    if (!mkdir($tmpBase, 0777, true)) {
        error_log("Error creando directorio temporal: $tmpBase");
        die("Error creando directorio temporal");
    }
}

// Verificar permisos en el directorio temporal
if (!is_writable($tmpBase)) {
    die("Error: El directorio $tmpBase no tiene permisos de escritura");
}

// 1. USAR LA MISMA LÓGICA DE CONSULTA QUE EN EL REPORTE INDIVIDUAL
$sql_common = " AND (f.factura = ? OR ? = 'Todos') 
                AND (f.sucursal = ? OR ? = '') 
                AND f.estado IN ('Activo','nulo','Invalidado')";

$sql = "SELECT f.id_factura, f.sucursal, f.factura, f.archivoPDF, f.archivoJSON 
        FROM facturas f
        WHERE DATE(f.fecha_creacion) BETWEEN ? AND ?
        $sql_common";

// Parámetros
$params = [
    $fecha_inicio,
    $fecha_fin,
    $tipo_filtro,
    $tipo_filtro,
    $sucursal_filtro,
    $sucursal_filtro
];
$types = "ssssss";

error_log("SQL: $sql");
error_log("Params: " . print_r($params, true));

$stmt = $db->prepare($sql);
if (!$stmt) {
    error_log("Error SQL: " . $db->error);
    die("Error en consulta SQL");
}

$stmt->bind_param($types, ...$params);
if (!$stmt->execute()) {
    error_log("Error ejecutando consulta: " . $stmt->error);
    die("Error ejecutando consulta");
}

$result = $stmt->get_result();
$rows = $result->fetch_all(MYSQLI_ASSOC);

if (empty($rows)) {
    // Consulta de diagnóstico
    $diag_sql = "SELECT COUNT(*) AS total FROM facturas 
                 WHERE DATE(fecha_creacion) BETWEEN ? AND ?
                 AND estado IN ('Activo','nulo','Invalidado')";
    $diag_stmt = $db->prepare($diag_sql);
    $diag_stmt->bind_param("ss", $fecha_inicio, $fecha_fin);
    $diag_stmt->execute();
    $diag_result = $diag_stmt->get_result()->fetch_assoc();
    
    error_log("No se encontraron registros para el rango: $fecha_inicio - $fecha_fin");
    error_log("Total registros en rango (sin filtros): " . ($diag_result['total'] ?? 0));
    
    exit("No se encontraron registros en la base de datos para ese rango.");
}

error_log("Registros encontrados: " . count($rows));


// Agrupar resultados por sucursal y tipo
$grupos = [];
foreach ($rows as $row) {
    $key = $row['sucursal'] . '_' . $row['factura'];
    $grupos[$key][] = $row;
}

$http = new Client([
    'timeout' => 60,
    'verify' => false,
    'http_errors' => false
]);

$partials = [];
$archivosEncontrados = false;
$totalGroups = count($grupos);
$processed   = 0;
foreach ($grupos as $key => $grupo) {
    list($suc, $tip) = explode('_', $key, 2);
    
    $desc = $mapa[$tip] ?? preg_replace('/\s+/', '_', $tip);
    $partialName = "{$empresaNombre}_{$fecha_inicio}_{$fecha_fin}_{$desc}_{$suc}.zip";
    $partialPath = "$tmpBase/$partialName";

    $zip = new ZipArchive();
    $zipStatus = $zip->open($partialPath, ZipArchive::CREATE | ZipArchive::OVERWRITE);
    
    if ($zipStatus !== true) {
        error_log("Error abriendo ZIP ($zipStatus): $partialPath");
        continue;
    }

    $archivosEnGrupo = false;
    $archivosTemporales = []; // Almacenar archivos temporales para limpiar después

    foreach ($grupo as $row) {
        $archivosAgregados = false;
        
        foreach (['archivoPDF','archivoJSON'] as $col) {
            if (empty($row[$col])) {
                error_log("Registro ID {$row['id']} tiene $col vacío");
                continue;
            }
            
            $url = $row[$col];
            
            // Generar nombre de archivo seguro
            $fileName = basename(parse_url($url, PHP_URL_PATH));
            if (!$fileName) {
                $fileName = $col . '_' . $row['id'] . '.bin';
            }
            
            $tmpFile = "$tmpBase/$fileName";
            
            try {
                $res = $http->get($url);
                
                if ($res->getStatusCode() !== 200) {
                    error_log("HTTP {$res->getStatusCode()} para $url");
                    continue;
                }
                
                file_put_contents($tmpFile, $res->getBody());
                
                if (!file_exists($tmpFile)) {
                    error_log("Error creando temporal: $tmpFile");
                    continue;
                }
                
                if ($zip->addFile($tmpFile, $fileName)) {
                    $archivosAgregados = true;
                    $archivosEncontrados = true;
                    $archivosEnGrupo = true;
                    $archivosTemporales[] = $tmpFile; // Guardar para limpiar después
                } else {
                    error_log("Error agregando $fileName al ZIP");
                }
                
            } catch (Exception $e) {
                error_log("Excepción: " . $e->getMessage());
            }
        }
    }
    
    // CERRAR PRIMERO EL ZIP ANTES DE MANIPULAR ARCHIVOS
    if (!$zip->close()) {
        error_log("Error cerrando ZIP parcial: $partialPath");
        // Limpiar archivos temporales si falla
        foreach ($archivosTemporales as $tmp) {
            @unlink($tmp);
        }
        continue;
    }
    
    // Solo agregar si hay archivos en el ZIP
    if ($archivosEnGrupo && file_exists($partialPath) && filesize($partialPath) > 0) {
        $partials[] = $partialPath;
    } else {
        @unlink($partialPath);
        error_log("ZIP parcial $partialPath está vacío o no se creó");
    }
    
    // Limpiar archivos temporales DESPUÉS de cerrar el ZIP
    foreach ($archivosTemporales as $tmp) {
        if (file_exists($tmp)) @unlink($tmp);
    }

    $processed++;
$progress = intval(($processed / $totalGroups) * 100);
$_SESSION['progress'] = $progress;
session_write_close();
}


$_SESSION['progress'] = 100;    // ← marcar completo
session_write_close(); 
// Manejo de errores final
if (!$archivosEncontrados) {
    error_log("No se encontraron archivos válidos para descargar");
    exit("No se encontraron archivos válidos para descargar.");
}

if (empty($partials)) {
    error_log("No se crearon archivos ZIP parciales válidos");
    exit("No se pudieron crear archivos ZIP parciales.");
}

$masterName = "{$empresaNombre}_{$fecha_inicio}_{$fecha_fin}_ALL.zip";
$masterPath = sys_get_temp_dir() . "/" . $masterName;
$zip = new ZipArchive();

if ($zip->open($masterPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
    error_log("Error creando ZIP maestro: " . $masterPath);
    exit("Error al crear ZIP maestro.");
}

foreach ($partials as $part) {
    if (!file_exists($part)) {
        error_log("Archivo parcial no encontrado: $part");
        continue;
    }
    $zip->addFile($part, basename($part));
}

if (!$zip->close()) {
    error_log("Error cerrando ZIP maestro: " . $zip->getStatusString());
    exit("Error finalizando ZIP maestro: " . $zip->getStatusString());
}

// Verificar que el archivo maestro existe
if (!file_exists($masterPath)) {
    error_log("Archivo maestro no creado: $masterPath");
    exit("Error: Archivo maestro no se creó correctamente.");
}

// Envío al cliente
header('Content-Type: application/zip');
header("Content-Disposition: attachment; filename=\"$masterName\"");
header('Content-Length: ' . filesize($masterPath));
readfile($masterPath);

// Limpieza final (ejecutar en segundo plano para no retrasar la descarga)
register_shutdown_function(function() use ($masterPath, $partials, $tmpBase) {
    if (file_exists($masterPath)) @unlink($masterPath);
    foreach ($partials as $part) {
        if (file_exists($part)) @unlink($part);
    }
    if (is_dir($tmpBase)) {
        array_map('unlink', glob("$tmpBase/*"));
        @rmdir($tmpBase);
    }
});

exit;
