<?php
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../../vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\IOFactory;

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['excel_file'])) {
    $fileTmpPath = $_FILES['excel_file']['tmp_name'];

    // Usar un ReadFilter para procesar el archivo en chunks y evitar cargar todo en memoria
    class ChunkReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter {
        private $startRow = 0;
        private $endRow = 0;

        public function setRows(int $startRow, int $chunkSize): void {
            $this->startRow = $startRow;
            $this->endRow = $startRow + $chunkSize - 1;
        }

        // Firma compatible con PhpOffice\PhpSpreadsheet\Reader\IReadFilter
        public function readCell(string $columnAddress, int $row, string $worksheetName = ''): bool {
            return ($row >= $this->startRow && $row <= $this->endRow);
        }
    }

    $reader = IOFactory::createReaderForFile($fileTmpPath);
    $reader->setReadDataOnly(true);
    // Obtener cantidad total de filas sin cargar todo el libro
    $sheetInfo = $reader->listWorksheetInfo($fileTmpPath);
    $totalRowsInFile = isset($sheetInfo[0]['totalRows']) ? (int)$sheetInfo[0]['totalRows'] : 0;

    // Leer header (fila 1)
    $filter = new ChunkReadFilter();
    $filter->setRows(1, 1);
    $reader->setReadFilter($filter);
    $spreadsheet = $reader->load($fileTmpPath);
    $sheet = $spreadsheet->getActiveSheet();
    $rowsHeader = $sheet->toArray(null, true, true, true);
    $rows = $rowsHeader; // header usado para construir índices más abajo

    // Mapeo de columnas
    $map = [
        'Nombre completo' => 'Nombre_Completo',
        'Fecha' => 'Fecha',
        'Tacloud' => 'Tacloud',
        'Horario' => 'Horario',
        'Resultado' => 'Resultado',
        'Incidencia' => 'Incidencia',
        'Departamento interno' => 'Departamento_interno',
        'Región' => 'Region'
    ];

    // Obtener los índices de las columnas (header)
    $header = reset($rows);
    $colIndex = [];
    foreach ($header as $colLetter => $colName) {
        foreach ($map as $excelCol => $dbCol) {
            if (trim($colName) === $excelCol) {
                $colIndex[$dbCol] = $colLetter;
            }
        }
    }
    // String de comparación para evitar procesar la fila header por contenido
    $headerCompare = implode('|', array_map('trim', $header));

    // Aumentar tiempo de ejecución para procesos largos
    if (function_exists('set_time_limit')) set_time_limit(0);

    // Conexión a la base de datos usando PDO
    $db = new Database();
    $conn = $db->connect();

    $inserted = 0;
    $blockSize = 100;
    $totalRows = $totalRowsInFile; // usar total de archivo

    // Helper para normalizar fechas (Excel serial o string)
    $normalizeDate = function($value) {
        if ($value === null || $value === '') return null;
        // Si es numérico, puede ser fecha Excel
        if (is_numeric($value)) {
            try {
                $dt = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);
                return $dt->format('Y-m-d');
            } catch (Exception $e) {
                // caemos a parseo por strtotime
            }
        }
        // Intentar parsear string
        $ts = strtotime($value);
        if ($ts !== false) return date('Y-m-d', $ts);
        return null;
    };

    for ($start = 2; $start <= $totalRows; $start += $blockSize) {
        $currentChunkSize = min($blockSize, $totalRows - $start + 1);
        $filter->setRows($start, $currentChunkSize);
        $reader->setReadFilter($filter);
        $spreadsheet = $reader->load($fileTmpPath);
        $sheet = $spreadsheet->getActiveSheet();
        $chunkRows = $sheet->toArray(null, true, true, true);

        // Construir map de filas del bloque evitando duplicados internos
        $batchRows = [];
        foreach ($chunkRows as $i => $row) {
            // Evitar procesar la fila 1 (header) por número
            if ((int)$i === 1) continue;
            // Evitar procesar la fila si su contenido coincide con el header (por seguridad)
            $rowCompare = implode('|', array_map('trim', $row));
            if ($rowCompare === $headerCompare) continue;
            // $i es la fila en el chunk, usar directamente
            $data = [];
            foreach ($map as $excelCol => $dbCol) {
                $colLetter = $colIndex[$dbCol] ?? null;
                $data[$dbCol] = $colLetter && isset($row[$colLetter]) ? $row[$colLetter] : null;
            }
            // Normalizar fecha
            $data['Fecha'] = $normalizeDate($data['Fecha']);
            // Saltar si no hay nombre o fecha
            if (empty($data['Nombre_Completo']) || empty($data['Fecha'])) continue;
            $key = $data['Nombre_Completo'] . '|' . $data['Fecha'];
            if (!isset($batchRows[$key])) {
                $batchRows[$key] = $data;
            }
        }

        if (empty($batchRows)) continue;

        // Intentar crear un índice UNIQUE para Nombre_Completo+Fecha (solo la primera vez mejora rendimiento)
        static $triedCreateIndex = false;
        if (!$triedCreateIndex) {
            $triedCreateIndex = true;
            try {
                // usar prefijo en caso de utf8mb4 y longitudes
                $conn->exec("ALTER TABLE PreNominaIncidencias ADD UNIQUE INDEX uniq_nombre_fecha (Nombre_Completo(191), Fecha)");
            } catch (Exception $e) {
                // si falla, continuar sin índice (posible que ya exista o length issue)
            }
        }

        // Preparar datos a insertar (todos los que no estén duplicados dentro del mismo bloque)
        $toInsert = array_values($batchRows);

        if (empty($toInsert)) continue;

        // Insert masivo por bloque usando INSERT IGNORE para que la DB descarte duplicados (mucho más rápido que SELECT por fila)
        try {
            $conn->beginTransaction();
            $placeholders = array_fill(0, count($toInsert), '(?, ?, ?, ?, ?, ?, ?, ?)');
            $insertSql = 'INSERT IGNORE INTO PreNominaIncidencias (Nombre_Completo, Fecha, Tacloud, Horario, Resultado, Incidencia, Departamento_interno, Region) VALUES ' . implode(', ', $placeholders);
            $flatParams = [];
            foreach ($toInsert as $rowData) {
                $flatParams[] = $rowData['Nombre_Completo'];
                $flatParams[] = $rowData['Fecha'];
                $flatParams[] = $rowData['Tacloud'];
                $flatParams[] = $rowData['Horario'];
                $flatParams[] = $rowData['Resultado'];
                $flatParams[] = $rowData['Incidencia'];
                $flatParams[] = $rowData['Departamento_interno'];
                $flatParams[] = $rowData['Region'];
            }
            $insertStmt = $conn->prepare($insertSql);
            $insertedNow = 0;
            if ($insertStmt->execute($flatParams)) {
                // contar filas afectadas (puede ser 0 si todas eran duplicados)
                $insertedNow = $insertStmt->rowCount();
            }
            $conn->commit();
            $inserted += $insertedNow;
        } catch (Exception $e) {
            if ($conn->inTransaction()) $conn->rollBack();
            // Registrar error pero continuar con siguientes bloques
            error_log('Incidencias upload error: ' . $e->getMessage());
        }
    // Liberar memoria del chunk
    unset($spreadsheet, $sheet, $chunkRows);
    }
    echo json_encode(['success' => true, 'inserted' => $inserted]);
} else {
    echo json_encode(['success' => false, 'message' => 'No se recibió archivo.']);
}
