<?php
if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start();
}

require_once __DIR__ . '/../includes/session_control.php';
require_once __DIR__ . '/../db/db.php';

$autoload = __DIR__ . '/../vendor/autoload.php';
if (file_exists($autoload)) {
    require_once $autoload;
}

$roleId = isset($_SESSION['user']['roleId']) ? (int)$_SESSION['user']['roleId'] : 0;
$isSuper = isset($_SESSION['user']['isSuper']) && (int)$_SESSION['user']['isSuper'] === 1;
$canSeeContabilidad = $isSuper || in_array($roleId, [1, 2, 4], true);

if (!$canSeeContabilidad) {
    http_response_code(403);
    die('No autorizado');
}

function ensureReporteDianTable(mysqli $conn): void
{
    $sql = <<<SQL
CREATE TABLE IF NOT EXISTS tb_reporte_dian (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    fuente ENUM('DIAN', 'SIIGO') NOT NULL,
    archivoOrigen VARCHAR(255) NOT NULL,
    numeroFila INT UNSIGNED NOT NULL,
    documentoClave VARCHAR(190) NOT NULL,
    facturaNormalizada VARCHAR(80) NULL,
    tipoMovimientoNorm VARCHAR(40) NULL,
    llaveNegocio VARCHAR(160) NULL,
    claseDocumento VARCHAR(20) NULL,
    hashUnico CHAR(64) NOT NULL,
    tipoDocumento VARCHAR(120) NULL,
    tipoTransaccion VARCHAR(120) NULL,
    prefijo VARCHAR(30) NULL,
    consecutivo VARCHAR(60) NULL,
    comprobante VARCHAR(60) NULL,
    cufeCude VARCHAR(120) NULL,
    fechaEmision DATETIME NULL,
    fechaAceptacion DATETIME NULL,
    fechaElaboracion DATE NULL,
    nitEmisor VARCHAR(30) NULL,
    nombreEmisor VARCHAR(255) NULL,
    nitReceptor VARCHAR(30) NULL,
    nombreReceptor VARCHAR(255) NULL,
    identificacion VARCHAR(40) NULL,
    sucursal VARCHAR(150) NULL,
    cliente VARCHAR(255) NULL,
    estadoEnvioCorreo VARCHAR(80) NULL,
    divisa VARCHAR(20) NULL,
    formaPago VARCHAR(80) NULL,
    medioPago VARCHAR(80) NULL,
    iva DECIMAL(18,2) NULL,
    ica DECIMAL(18,2) NULL,
    inc DECIMAL(18,2) NULL,
    impuestosTotal DECIMAL(18,2) NULL,
    total DECIMAL(18,2) NULL,
    resultado VARCHAR(120) NULL,
    grupoDocumento VARCHAR(120) NULL,
    datosJson LONGTEXT NOT NULL,
    vecesImportado INT UNSIGNED NOT NULL DEFAULT 1,
    creadoEn DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    actualizadoEn DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE KEY uq_reporte_dian_fuente_doc (fuente, documentoClave),
    UNIQUE KEY uq_reporte_dian_llave_negocio (llaveNegocio),
    UNIQUE KEY uq_reporte_dian_hash (hashUnico),
    KEY idx_reporte_dian_clase_tipo (claseDocumento, tipoMovimientoNorm),
    KEY idx_reporte_dian_fechas (fechaEmision, fechaElaboracion),
    KEY idx_reporte_dian_nit (nitEmisor, nitReceptor),
    KEY idx_reporte_dian_comprobante (comprobante, cufeCude)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL;

    if (!$conn->query($sql)) {
        throw new RuntimeException('No se pudo crear/verificar tb_reporte_dian: ' . $conn->error);
    }

    // Compatibilidad con tablas ya creadas anteriormente.
    $dbNameRes = $conn->query('SELECT DATABASE() AS dbn');
    $dbName = null;
    if ($dbNameRes instanceof mysqli_result) {
        $tmp = $dbNameRes->fetch_assoc();
        $dbName = $tmp['dbn'] ?? null;
        $dbNameRes->free();
    }
    if (!$dbName) {
        throw new RuntimeException('No se pudo detectar la base de datos activa.');
    }

    $columnsToAdd = [
        "ALTER TABLE tb_reporte_dian ADD COLUMN facturaNormalizada VARCHAR(80) NULL AFTER documentoClave",
        "ALTER TABLE tb_reporte_dian ADD COLUMN tipoMovimientoNorm VARCHAR(40) NULL AFTER facturaNormalizada",
        "ALTER TABLE tb_reporte_dian ADD COLUMN llaveNegocio VARCHAR(160) NULL AFTER tipoMovimientoNorm",
        "ALTER TABLE tb_reporte_dian ADD COLUMN claseDocumento VARCHAR(20) NULL AFTER llaveNegocio",
    ];
    foreach ($columnsToAdd as $alterSql) {
        if (strpos($alterSql, 'facturaNormalizada') !== false && !columnExists($conn, $dbName, 'tb_reporte_dian', 'facturaNormalizada')) {
            if (!$conn->query($alterSql)) {
                throw new RuntimeException('No se pudo ajustar tb_reporte_dian: ' . $conn->error);
            }
        }
        if (strpos($alterSql, 'tipoMovimientoNorm') !== false && !columnExists($conn, $dbName, 'tb_reporte_dian', 'tipoMovimientoNorm')) {
            if (!$conn->query($alterSql)) {
                throw new RuntimeException('No se pudo ajustar tb_reporte_dian: ' . $conn->error);
            }
        }
        if (strpos($alterSql, 'llaveNegocio') !== false && !columnExists($conn, $dbName, 'tb_reporte_dian', 'llaveNegocio')) {
            if (!$conn->query($alterSql)) {
                throw new RuntimeException('No se pudo ajustar tb_reporte_dian: ' . $conn->error);
            }
        }
        if (strpos($alterSql, 'claseDocumento') !== false && !columnExists($conn, $dbName, 'tb_reporte_dian', 'claseDocumento')) {
            if (!$conn->query($alterSql)) {
                throw new RuntimeException('No se pudo ajustar tb_reporte_dian: ' . $conn->error);
            }
        }
    }

    if (!indexExists($conn, $dbName, 'tb_reporte_dian', 'uq_reporte_dian_llave_negocio')) {
        // Si había duplicados históricos, conservar el registro más antiguo.
        $dedupSql = "
            DELETE t1
            FROM tb_reporte_dian t1
            INNER JOIN tb_reporte_dian t2
                ON t1.llaveNegocio = t2.llaveNegocio
               AND t1.id > t2.id
            WHERE t1.llaveNegocio IS NOT NULL
              AND t1.llaveNegocio <> ''
        ";
        $conn->query($dedupSql);

        if (!$conn->query("ALTER TABLE tb_reporte_dian ADD UNIQUE KEY uq_reporte_dian_llave_negocio (llaveNegocio)")) {
            throw new RuntimeException('No se pudo crear índice de llaveNegocio: ' . $conn->error);
        }
    }

    if (!indexExists($conn, $dbName, 'tb_reporte_dian', 'idx_reporte_dian_clase_tipo')) {
        $conn->query("ALTER TABLE tb_reporte_dian ADD KEY idx_reporte_dian_clase_tipo (claseDocumento, tipoMovimientoNorm)");
    }
}

function columnExists(mysqli $conn, string $dbName, string $tableName, string $columnName): bool
{
    $sql = "SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND COLUMN_NAME = ? LIMIT 1";
    $stmt = $conn->prepare($sql);
    if (!$stmt) return false;
    $stmt->bind_param('sss', $dbName, $tableName, $columnName);
    $stmt->execute();
    $res = $stmt->get_result();
    $ok = $res instanceof mysqli_result && $res->num_rows > 0;
    if ($res instanceof mysqli_result) {
        $res->free();
    }
    $stmt->close();
    return $ok;
}

function indexExists(mysqli $conn, string $dbName, string $tableName, string $indexName): bool
{
    $sql = "SELECT 1 FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND INDEX_NAME = ? LIMIT 1";
    $stmt = $conn->prepare($sql);
    if (!$stmt) return false;
    $stmt->bind_param('sss', $dbName, $tableName, $indexName);
    $stmt->execute();
    $res = $stmt->get_result();
    $ok = $res instanceof mysqli_result && $res->num_rows > 0;
    if ($res instanceof mysqli_result) {
        $res->free();
    }
    $stmt->close();
    return $ok;
}

function normalizeHeader(string $v): string
{
    $v = trim($v);
    $v = mb_strtolower($v, 'UTF-8');
    $iconv = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $v);
    if (is_string($iconv) && $iconv !== '') {
        $v = mb_strtolower($iconv, 'UTF-8');
    }
    $v = preg_replace('/[^a-z0-9]+/u', '_', $v);
    $v = trim($v, '_');
    return $v;
}

function normalizeDocKeyPart(?string $v): string
{
    $v = trim((string)$v);
    $v = mb_strtoupper($v, 'UTF-8');
    $v = preg_replace('/\s+/', '', $v);
    return preg_replace('/[^A-Z0-9\-_:]/', '', $v);
}

function parseMoney($value): ?string
{
    if ($value === null) return null;
    $raw = trim((string)$value);
    if ($raw === '') return null;

    $raw = str_replace([' ', "\xc2\xa0"], '', $raw);
    $raw = preg_replace('/[^0-9,.\-]/', '', $raw);
    if ($raw === '' || $raw === '-' || $raw === '-.' || $raw === '-,') return null;

    $commaPos = strrpos($raw, ',');
    $dotPos = strrpos($raw, '.');
    if ($commaPos !== false && $dotPos !== false) {
        if ($commaPos > $dotPos) {
            $raw = str_replace('.', '', $raw);
            $raw = str_replace(',', '.', $raw);
        } else {
            $raw = str_replace(',', '', $raw);
        }
    } elseif ($commaPos !== false) {
        $raw = str_replace('.', '', $raw);
        $raw = str_replace(',', '.', $raw);
    }

    if (!is_numeric($raw)) return null;
    return number_format((float)$raw, 2, '.', '');
}

function parseDateFlexible($value, bool $onlyDate = false): ?string
{
    if ($value === null) return null;
    $raw = trim((string)$value);
    if ($raw === '') return null;

    if (is_numeric($raw)) {
        $serial = (float)$raw;
        if ($serial > 20000 && $serial < 80000) {
            $unix = (int)(($serial - 25569) * 86400);
            return gmdate($onlyDate ? 'Y-m-d' : 'Y-m-d H:i:s', $unix);
        }
    }

    $raw = str_replace('T', ' ', $raw);
    $formats = $onlyDate
        ? ['Y-m-d', 'd/m/Y', 'd-m-Y', 'm/d/Y']
        : ['Y-m-d H:i:s', 'Y-m-d H:i', 'd/m/Y H:i:s', 'd/m/Y H:i', 'd-m-Y H:i:s', 'd-m-Y H:i'];

    foreach ($formats as $fmt) {
        $dt = DateTime::createFromFormat($fmt, $raw);
        if ($dt instanceof DateTime) {
            return $dt->format($onlyDate ? 'Y-m-d' : 'Y-m-d H:i:s');
        }
    }

    try {
        $dt = new DateTime($raw);
        return $dt->format($onlyDate ? 'Y-m-d' : 'Y-m-d H:i:s');
    } catch (Exception $e) {
        return null;
    }
}

function pick(array $map, array $aliases): ?string
{
    foreach ($aliases as $a) {
        if (array_key_exists($a, $map)) {
            $v = trim((string)$map[$a]);
            if ($v !== '') return $v;
        }
    }
    return null;
}

function detectCsvDelimiter(string $path): string
{
    $line = '';
    $fh = fopen($path, 'rb');
    if ($fh !== false) {
        $line = (string)fgets($fh);
        fclose($fh);
    }
    $candidates = [',', ';', "\t", '|'];
    $best = ',';
    $max = -1;
    foreach ($candidates as $d) {
        $count = substr_count($line, $d);
        if ($count > $max) {
            $max = $count;
            $best = $d;
        }
    }
    return $best;
}

function loadRowsFromFile(string $path, string $ext): array
{
    $ext = strtolower($ext);
    if ($ext === 'csv' || $ext === 'txt') {
        $delimiter = detectCsvDelimiter($path);
        $rows = [];
        $fh = fopen($path, 'rb');
        if ($fh === false) {
            throw new RuntimeException('No se pudo abrir el CSV.');
        }
        while (($row = fgetcsv($fh, 0, $delimiter)) !== false) {
            $rows[] = array_map(static function ($v) {
                return is_string($v) ? trim($v) : $v;
            }, $row);
        }
        fclose($fh);
        return $rows;
    }

    if (!class_exists('\PhpOffice\PhpSpreadsheet\IOFactory')) {
        throw new RuntimeException('Para importar XLS/XLSX falta PhpSpreadsheet en /vendor.');
    }

    $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($path);
    $sheet = $spreadsheet->getActiveSheet();
    return $sheet->toArray('', true, true, false);
}

function detectHeaderRowIndex(array $rows, string $fuente): int
{
    $targets = $fuente === 'DIAN'
        ? ['tipo_de_documento', 'cufe_cude', 'nit_emisor', 'nombre_receptor', 'total']
        : ['tipo_de_transaccion', 'comprobante', 'fecha_elaboracion', 'identificacion', 'cliente', 'total'];

    $bestIdx = 0;
    $bestScore = -1;
    $maxScan = min(count($rows), 30);
    for ($i = 0; $i < $maxScan; $i++) {
        if (!is_array($rows[$i])) continue;
        $normalizedCells = array_map(static function ($v) {
            return normalizeHeader((string)$v);
        }, $rows[$i]);
        $score = 0;
        foreach ($targets as $t) {
            if (in_array($t, $normalizedCells, true)) {
                $score++;
            }
        }
        if ($score > $bestScore) {
            $bestScore = $score;
            $bestIdx = $i;
        }
    }

    return $bestScore >= 2 ? $bestIdx : 0;
}

function buildDocumentoClave(array $norm, string $fuente): string
{
    if ($fuente === 'DIAN') {
        $cufe = pick($norm, ['cufe_cude', 'cufe', 'cude']);
        if ($cufe) return 'CUFE:' . normalizeDocKeyPart($cufe);

        $prefijo = pick($norm, ['prefijo']) ?? '';
        $consec = pick($norm, ['consecutivo']) ?? '';
        $nit = pick($norm, ['nit_emisor']) ?? '';
        $base = 'DOC:' . normalizeDocKeyPart($prefijo . $consec) . '|NIT:' . normalizeDocKeyPart($nit);
        if ($base !== 'DOC:|NIT:') return $base;
    } else {
        $comp = pick($norm, ['comprobante']);
        $ident = pick($norm, ['identificacion']);
        if ($comp) return 'COMP:' . normalizeDocKeyPart($comp) . '|ID:' . normalizeDocKeyPart((string)$ident);

        $tipo = pick($norm, ['tipo_de_transaccion', 'tipo_transaccion']) ?? '';
        $fecha = pick($norm, ['fecha_elaboracion']) ?? '';
        $total = pick($norm, ['total']) ?? '';
        $base = 'TX:' . normalizeDocKeyPart($tipo) . '|F:' . normalizeDocKeyPart($fecha) . '|T:' . normalizeDocKeyPart($total);
        if ($base !== 'TX:|F:|T:') return $base;
    }

    return 'ROW:' . strtoupper(hash('sha256', json_encode($norm, JSON_UNESCAPED_UNICODE)));
}

function normalizeFactura(?string $value): ?string
{
    $value = trim((string)$value);
    if ($value === '') return null;
    $value = mb_strtoupper($value, 'UTF-8');
    $value = preg_replace('/[^A-Z0-9]/', '', $value);
    return $value !== '' ? $value : null;
}

function normalizeTipoMovimiento(?string $value): string
{
    $v = normalizeHeader((string)$value);
    if ($v === '') return 'OTRO';

    // Prioridad: no confundir notas.
    if (strpos($v, 'nota_credito') !== false || strpos($v, 'credit_note') !== false) return 'NC';
    if (strpos($v, 'nota_debito') !== false || strpos($v, 'debit_note') !== false) return 'ND';

    // SIIGO: "Factura de venta / Ingresos"
    if (strpos($v, 'factura_de_venta') !== false) return 'FV';
    if (strpos($v, 'factura') !== false && strpos($v, 'ingresos') !== false) return 'FV';
    if (strpos($v, 'factura') !== false || strpos($v, 'invoice') !== false || strpos($v, 'factura_electronica') !== false) return 'FV';

    return 'OTRO';
}

function inferTipoMovimientoByRefs(?string $comprobante, ?string $prefijo, ?string $consecutivo, ?string $documentoClave): string
{
    $parts = [
        strtoupper(trim((string)$comprobante)),
        strtoupper(trim((string)$prefijo)),
        strtoupper(trim((string)$consecutivo)),
        strtoupper(trim((string)$documentoClave)),
    ];
    $joined = trim(implode(' ', array_filter($parts, static function ($v) {
        return $v !== '';
    })));
    if ($joined === '') return 'OTRO';

    $alnum = preg_replace('/[^A-Z0-9]/', '', $joined);

    if (
        preg_match('/\bNC\b/', $joined) ||
        strpos($joined, 'NOTA CREDITO') !== false ||
        strpos($joined, 'NOTACREDITO') !== false ||
        strpos($joined, 'CREDIT NOTE') !== false ||
        preg_match('/^NC[0-9]/', $alnum)
    ) {
        return 'NC';
    }

    if (
        preg_match('/\bND\b/', $joined) ||
        strpos($joined, 'NOTA DEBITO') !== false ||
        strpos($joined, 'NOTADEBITO') !== false ||
        strpos($joined, 'DEBIT NOTE') !== false ||
        preg_match('/^ND[0-9]/', $alnum)
    ) {
        return 'ND';
    }

    if (
        preg_match('/\bFV\b/', $joined) ||
        strpos($joined, 'FACTURA') !== false ||
        strpos($joined, 'INVOICE') !== false ||
        strpos($joined, 'INGRESO') !== false ||
        preg_match('/^FV[0-9]/', $alnum)
    ) {
        return 'FV';
    }

    return 'OTRO';
}

function reclassifyTiposHistoricos(mysqli $conn): void
{
    $q = $conn->query(
        "SELECT id, tipoDocumento, tipoTransaccion, comprobante, prefijo, consecutivo, documentoClave
         FROM tb_reporte_dian
         WHERE tipoMovimientoNorm IS NULL OR tipoMovimientoNorm = 'OTRO'
         LIMIT 2000"
    );
    if (!($q instanceof mysqli_result)) {
        return;
    }

    $upd = $conn->prepare("UPDATE tb_reporte_dian SET tipoMovimientoNorm = ? WHERE id = ?");
    if (!$upd) {
        $q->free();
        return;
    }

    while ($r = $q->fetch_assoc()) {
        $rawTipo = trim((string)($r['tipoDocumento'] ?? ''));
        if ($rawTipo === '') {
            $rawTipo = trim((string)($r['tipoTransaccion'] ?? ''));
        }
        $tipo = normalizeTipoMovimiento($rawTipo);
        if ($tipo === 'OTRO') {
            $tipo = inferTipoMovimientoByRefs(
                $r['comprobante'] ?? '',
                $r['prefijo'] ?? '',
                $r['consecutivo'] ?? '',
                $r['documentoClave'] ?? ''
            );
        }
        if ($tipo === 'OTRO') continue;

        $id = (int)$r['id'];
        $upd->bind_param('si', $tipo, $id);
        $upd->execute();
    }
    $upd->close();
    $q->free();
}

function normalizeNit(?string $value): string
{
    $v = trim((string)$value);
    if ($v === '') return '';
    $v = mb_strtoupper($v, 'UTF-8');
    return preg_replace('/[^A-Z0-9]/', '', $v);
}

function loadEmpresasNitSet(mysqli $conn): array
{
    $set = [];
    $col = null;
    $res = $conn->query("SHOW COLUMNS FROM tb_empresas");
    if ($res instanceof mysqli_result) {
        while ($r = $res->fetch_assoc()) {
            $f = mb_strtolower((string)($r['Field'] ?? ''), 'UTF-8');
            if (in_array($f, ['nit', 'nitempresa', 'no_documento', 'nodocumento'], true)) {
                $col = $r['Field'];
                break;
            }
        }
        $res->free();
    }
    if (!$col) return $set;

    $q = $conn->query("SELECT `{$col}` AS nit FROM tb_empresas WHERE `{$col}` IS NOT NULL AND `{$col}` <> ''");
    if ($q instanceof mysqli_result) {
        while ($r = $q->fetch_assoc()) {
            $n = normalizeNit($r['nit'] ?? '');
            if ($n !== '') $set[$n] = true;
        }
        $q->free();
    }
    return $set;
}

$status = null;
$errors = [];
$preview = [];
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$perPage = 100;
$offset = ($page - 1) * $perPage;
$totalRows = 0;
$totalPages = 1;
$empresaNits = [];

$filterFactura = trim((string)($_GET['f_factura'] ?? ''));
$filterTipo = strtoupper(trim((string)($_GET['f_tipo'] ?? '')));
$filterTipo = in_array($filterTipo, ['FV', 'NC', 'ND', 'OTRO'], true) ? $filterTipo : '';
$filterClase = strtoupper(trim((string)($_GET['f_clase'] ?? '')));
$filterClase = in_array($filterClase, ['VENTA', 'COMPRA', 'SIN_CLASIFICAR'], true) ? $filterClase : '';
$filterNombre = trim((string)($_GET['f_nombre'] ?? ''));

try {
    ensureReporteDianTable($conn);
    $empresaNits = loadEmpresasNitSet($conn);
    reclassifyTiposHistoricos($conn);
} catch (Throwable $e) {
    $errors[] = $e->getMessage();
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($errors)) {
    $fuente = strtoupper(trim((string)($_POST['fuente'] ?? '')));
    $fuente = in_array($fuente, ['DIAN', 'SIIGO'], true) ? $fuente : '';

    if ($fuente === '') {
        $errors[] = 'Debe seleccionar la fuente del reporte.';
    }

    if (!isset($_FILES['archivo']) || !is_array($_FILES['archivo'])) {
        $errors[] = 'Debe adjuntar un archivo.';
    } elseif ((int)($_FILES['archivo']['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
        $errors[] = 'Error de carga en el archivo.';
    }

    if (empty($errors)) {
        $tmpPath = (string)$_FILES['archivo']['tmp_name'];
        $fileName = basename((string)$_FILES['archivo']['name']);
        $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        if (!in_array($ext, ['csv', 'txt', 'xls', 'xlsx'], true)) {
            $errors[] = 'Formato no soportado. Use CSV, XLS o XLSX.';
        } else {
            $inTx = false;
            try {
                $rows = loadRowsFromFile($tmpPath, $ext);
                if (count($rows) < 2) {
                    throw new RuntimeException('El archivo no trae suficientes filas.');
                }

                $headerIdx = detectHeaderRowIndex($rows, $fuente);
                $header = array_map(static function ($v) {
                    return trim((string)$v);
                }, $rows[$headerIdx]);

                $inserted = 0;
                $duplicates = 0;
                $rowErrors = 0;
                $sql = <<<SQL
INSERT INTO tb_reporte_dian (
    fuente, archivoOrigen, numeroFila, documentoClave, hashUnico,
    facturaNormalizada, tipoMovimientoNorm, llaveNegocio, claseDocumento,
    tipoDocumento, tipoTransaccion, prefijo, consecutivo, comprobante, cufeCude,
    fechaEmision, fechaAceptacion, fechaElaboracion,
    nitEmisor, nombreEmisor, nitReceptor, nombreReceptor,
    identificacion, sucursal, cliente, estadoEnvioCorreo,
    divisa, formaPago, medioPago,
    iva, ica, inc, impuestosTotal, total,
    resultado, grupoDocumento, datosJson
) VALUES (
    ?, ?, ?, ?, ?,
    ?, ?, ?, ?,
    ?, ?, ?, ?, ?, ?,
    ?, ?, ?,
    ?, ?, ?, ?,
    ?, ?, ?, ?,
    ?, ?, ?,
    ?, ?, ?, ?, ?,
    ?, ?, ?
)
ON DUPLICATE KEY UPDATE
    archivoOrigen = VALUES(archivoOrigen),
    numeroFila = VALUES(numeroFila),
    claseDocumento = COALESCE(tb_reporte_dian.claseDocumento, VALUES(claseDocumento)),
    tipoDocumento = COALESCE(tb_reporte_dian.tipoDocumento, VALUES(tipoDocumento)),
    tipoTransaccion = COALESCE(tb_reporte_dian.tipoTransaccion, VALUES(tipoTransaccion)),
    prefijo = COALESCE(tb_reporte_dian.prefijo, VALUES(prefijo)),
    consecutivo = COALESCE(tb_reporte_dian.consecutivo, VALUES(consecutivo)),
    comprobante = COALESCE(tb_reporte_dian.comprobante, VALUES(comprobante)),
    cufeCude = COALESCE(tb_reporte_dian.cufeCude, VALUES(cufeCude)),
    fechaEmision = COALESCE(tb_reporte_dian.fechaEmision, VALUES(fechaEmision)),
    fechaAceptacion = COALESCE(tb_reporte_dian.fechaAceptacion, VALUES(fechaAceptacion)),
    fechaElaboracion = COALESCE(tb_reporte_dian.fechaElaboracion, VALUES(fechaElaboracion)),
    nitEmisor = COALESCE(tb_reporte_dian.nitEmisor, VALUES(nitEmisor)),
    nombreEmisor = COALESCE(tb_reporte_dian.nombreEmisor, VALUES(nombreEmisor)),
    nitReceptor = COALESCE(tb_reporte_dian.nitReceptor, VALUES(nitReceptor)),
    nombreReceptor = COALESCE(tb_reporte_dian.nombreReceptor, VALUES(nombreReceptor)),
    identificacion = COALESCE(tb_reporte_dian.identificacion, VALUES(identificacion)),
    sucursal = COALESCE(tb_reporte_dian.sucursal, VALUES(sucursal)),
    cliente = COALESCE(tb_reporte_dian.cliente, VALUES(cliente)),
    estadoEnvioCorreo = COALESCE(tb_reporte_dian.estadoEnvioCorreo, VALUES(estadoEnvioCorreo)),
    divisa = COALESCE(tb_reporte_dian.divisa, VALUES(divisa)),
    formaPago = COALESCE(tb_reporte_dian.formaPago, VALUES(formaPago)),
    medioPago = COALESCE(tb_reporte_dian.medioPago, VALUES(medioPago)),
    iva = COALESCE(tb_reporte_dian.iva, VALUES(iva)),
    ica = COALESCE(tb_reporte_dian.ica, VALUES(ica)),
    inc = COALESCE(tb_reporte_dian.inc, VALUES(inc)),
    impuestosTotal = COALESCE(tb_reporte_dian.impuestosTotal, VALUES(impuestosTotal)),
    total = COALESCE(tb_reporte_dian.total, VALUES(total)),
    resultado = COALESCE(tb_reporte_dian.resultado, VALUES(resultado)),
    grupoDocumento = COALESCE(tb_reporte_dian.grupoDocumento, VALUES(grupoDocumento)),
    datosJson = VALUES(datosJson),
    vecesImportado = vecesImportado + 1,
    actualizadoEn = NOW()
SQL;

                $stmt = $conn->prepare($sql);
                if (!$stmt) {
                    throw new RuntimeException('No se pudo preparar inserción: ' . $conn->error);
                }

                $conn->begin_transaction();
                $inTx = true;

                for ($i = $headerIdx + 1; $i < count($rows); $i++) {
                    $row = $rows[$i];
                    if (!is_array($row)) continue;

                    $isEmpty = true;
                    foreach ($row as $v) {
                        if (trim((string)$v) !== '') {
                            $isEmpty = false;
                            break;
                        }
                    }
                    if ($isEmpty) continue;

                    $norm = [];
                    $payload = [];
                    foreach ($header as $idx => $rawKey) {
                        $rawKey = $rawKey !== '' ? $rawKey : ('Columna_' . ($idx + 1));
                        $value = isset($row[$idx]) ? trim((string)$row[$idx]) : '';
                        $payload[$rawKey] = $value;

                        $k = normalizeHeader($rawKey);
                        if ($k === '') {
                            $k = 'columna_' . ($idx + 1);
                        }
                        if (!array_key_exists($k, $norm)) {
                            $norm[$k] = $value;
                        }
                    }

                    $tipoDocumento = pick($norm, ['tipo_de_documento']);
                    $tipoTransaccion = pick($norm, ['tipo_de_transaccion', 'tipo_transaccion']);
                    $prefijo = pick($norm, ['prefijo']);
                    $consecutivo = pick($norm, ['consecutivo', 'folio']);
                    $comprobante = pick($norm, ['comprobante']);
                    $cufeCude = pick($norm, ['cufe_cude', 'cufe', 'cude']);
                    $tipoMovRaw = $tipoDocumento ?: $tipoTransaccion;
                    $tipoMovimientoNorm = normalizeTipoMovimiento($tipoMovRaw);
                    $facturaRaw = $comprobante ?: (($prefijo ?? '') . ($consecutivo ?? ''));
                    $facturaNormalizada = normalizeFactura($facturaRaw);
                    $documentoClave = buildDocumentoClave($norm, $fuente);
                    if ($tipoMovimientoNorm === 'OTRO') {
                        $tipoMovimientoNorm = inferTipoMovimientoByRefs(
                            $comprobante,
                            $prefijo,
                            $consecutivo,
                            $documentoClave
                        );
                    }
                    if ($facturaNormalizada) {
                        $llaveNegocio = $tipoMovimientoNorm . '|' . $facturaNormalizada;
                    } elseif ($cufeCude) {
                        $llaveNegocio = $tipoMovimientoNorm . '|CUFE|' . normalizeFactura($cufeCude);
                    } else {
                        $llaveNegocio = null;
                    }
                    // hash de fila de la fuente (auditoría); la no duplicación real está en llaveNegocio.
                    $hashUnico = hash('sha256', $fuente . '|' . $documentoClave);
                    $nitEmisor = pick($norm, ['nit_emisor']);
                    $nitEmisorNorm = normalizeNit($nitEmisor);
                    if ($nitEmisorNorm !== '') {
                        $claseDocumento = isset($empresaNits[$nitEmisorNorm]) ? 'VENTA' : 'COMPRA';
                    } else {
                        $claseDocumento = 'SIN_CLASIFICAR';
                    }
                    $fechaEmision = parseDateFlexible(pick($norm, ['fecha_emision', 'fecha_de_emision']), false);
                    $fechaAceptacion = parseDateFlexible(pick($norm, ['fecha_aceptacion']), false);
                    $fechaElaboracion = parseDateFlexible(pick($norm, ['fecha_elaboracion']), true);
                    $nombreEmisor = pick($norm, ['nombre_emisor']);
                    $nitReceptor = pick($norm, ['nit_receptor']);
                    $nombreReceptor = pick($norm, ['nombre_receptor']);
                    $identificacion = pick($norm, ['identificacion']);
                    $sucursal = pick($norm, ['sucursal']);
                    $cliente = pick($norm, ['cliente', 'nombre_receptor']);
                    $estadoEnvioCorreo = pick($norm, ['estado_envio_de_correo', 'estado_envio_correo']);
                    $divisa = pick($norm, ['divisa']);
                    $formaPago = pick($norm, ['forma_de_pago', 'forma_pago']);
                    $medioPago = pick($norm, ['medio_de_pago', 'medio_pago']);
                    $iva = parseMoney(pick($norm, ['iva']));
                    $ica = parseMoney(pick($norm, ['ica']));
                    $inc = parseMoney(pick($norm, ['inc']));
                    $total = parseMoney(pick($norm, ['total']));
                    $impuestosTotal = null;
                    if ($iva !== null || $ica !== null || $inc !== null) {
                        $impuestosTotal = number_format((float)($iva ?? 0) + (float)($ica ?? 0) + (float)($inc ?? 0), 2, '.', '');
                    }
                    $resultado = pick($norm, ['resultado', 'estado']);
                    $grupoDocumento = pick($norm, ['grupo']);
                    $datosJson = json_encode([
                        'headers' => $header,
                        'row' => $payload,
                        'fuente' => $fuente,
                    ], JSON_UNESCAPED_UNICODE);
                    if ($datosJson === false) {
                        $datosJson = '{}';
                    }

                    $numeroFila = $i + 1;
                    $types = 'ssi' . str_repeat('s', 34);
                    $stmt->bind_param(
                        $types,
                        $fuente,
                        $fileName,
                        $numeroFila,
                        $documentoClave,
                        $hashUnico,
                        $facturaNormalizada,
                        $tipoMovimientoNorm,
                        $llaveNegocio,
                        $claseDocumento,
                        $tipoDocumento,
                        $tipoTransaccion,
                        $prefijo,
                        $consecutivo,
                        $comprobante,
                        $cufeCude,
                        $fechaEmision,
                        $fechaAceptacion,
                        $fechaElaboracion,
                        $nitEmisor,
                        $nombreEmisor,
                        $nitReceptor,
                        $nombreReceptor,
                        $identificacion,
                        $sucursal,
                        $cliente,
                        $estadoEnvioCorreo,
                        $divisa,
                        $formaPago,
                        $medioPago,
                        $iva,
                        $ica,
                        $inc,
                        $impuestosTotal,
                        $total,
                        $resultado,
                        $grupoDocumento,
                        $datosJson
                    );

                    if (!$stmt->execute()) {
                        $rowErrors++;
                        continue;
                    }

                    if ($stmt->affected_rows === 1) {
                        $inserted++;
                    } else {
                        $duplicates++;
                    }
                }

                $conn->commit();
                $inTx = false;
                $stmt->close();

                $status = [
                    'ok' => true,
                    'inserted' => $inserted,
                    'duplicates' => $duplicates,
                    'rowErrors' => $rowErrors,
                ];
            } catch (Throwable $e) {
                if (!empty($inTx)) {
                    $conn->rollback();
                }
                $errors[] = $e->getMessage();
            }
        }
    }
}

if (empty($errors)) {
    $where = [];
    if ($filterFactura !== '') {
        $safe = $conn->real_escape_string(normalizeFactura($filterFactura) ?? $filterFactura);
        $where[] = "facturaNormalizada LIKE '%{$safe}%'";
    }
    if ($filterTipo !== '') {
        $safe = $conn->real_escape_string($filterTipo);
        $where[] = "tipoMovimientoNorm = '{$safe}'";
    }
    if ($filterClase !== '') {
        $safe = $conn->real_escape_string($filterClase);
        $where[] = "claseDocumento = '{$safe}'";
    }
    if ($filterNombre !== '') {
        $safe = $conn->real_escape_string($filterNombre);
        $where[] = "(nombreEmisor LIKE '%{$safe}%' OR nombreReceptor LIKE '%{$safe}%')";
    }
    $whereSql = count($where) ? (' WHERE ' . implode(' AND ', $where)) : '';

    $countRes = $conn->query("SELECT COUNT(*) AS cnt FROM tb_reporte_dian {$whereSql}");
    if ($countRes instanceof mysqli_result) {
        $tmp = $countRes->fetch_assoc();
        $totalRows = (int)($tmp['cnt'] ?? 0);
        $countRes->free();
    }
    $totalPages = max(1, (int)ceil($totalRows / $perPage));
    if ($page > $totalPages) {
        $page = $totalPages;
        $offset = ($page - 1) * $perPage;
    }

    $q = $conn->query(
        "SELECT id, fuente, archivoOrigen, claseDocumento, tipoMovimientoNorm, facturaNormalizada, documentoClave, nombreEmisor, nombreReceptor, total, vecesImportado, creadoEn, actualizadoEn
         FROM tb_reporte_dian {$whereSql}
         ORDER BY id DESC
         LIMIT {$offset}, {$perPage}"
    );
    if ($q instanceof mysqli_result) {
        while ($r = $q->fetch_assoc()) {
            $preview[] = $r;
        }
        $q->free();
    }
}

function esc($v): string
{
    return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8');
}

function pageUrl(array $overrides = []): string
{
    $params = $_GET;
    foreach ($overrides as $k => $v) {
        $params[$k] = $v;
    }
    return '?' . http_build_query($params);
}
?>

<?php include __DIR__ . '/../templates/header.php'; ?>

<div class="d-flex align-items-center justify-content-between mb-3">
    <h1 class="h3 text-gray-800 mb-0">Reportes DIAN</h1>
    <span class="badge badge-info">DIAN / SIIGO</span>
</div>

<p class="text-muted mb-4">
    Importe archivos CSV/XLS/XLSX de DIAN o SIIGO. El sistema evita duplicados por <strong>tipo de movimiento + factura normalizada</strong>.
</p>

<?php if (!empty($errors)): ?>
    <div class="alert alert-danger">
        <strong>No se pudo completar la importación.</strong>
        <ul class="mb-0 mt-2">
            <?php foreach ($errors as $e): ?>
                <li><?= esc($e) ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
<?php endif; ?>

<?php if (is_array($status) && !empty($status['ok'])): ?>
    <div class="alert alert-success">
        <strong>Importación finalizada.</strong>
        Insertados: <?= (int)$status['inserted'] ?> |
        Duplicados ignorados: <?= (int)$status['duplicates'] ?> |
        Filas con error: <?= (int)$status['rowErrors'] ?>
    </div>
<?php endif; ?>

<div class="card shadow mb-4">
    <div class="card-header py-3">
        <h6 class="m-0 font-weight-bold text-primary">Importar reporte</h6>
    </div>
    <div class="card-body">
        <form method="post" enctype="multipart/form-data">
            <div class="form-row">
                <div class="form-group col-md-3">
                    <label for="fuente">Fuente</label>
                    <select class="form-control" id="fuente" name="fuente" required>
                        <option value="">Seleccione...</option>
                        <option value="DIAN">DIAN</option>
                        <option value="SIIGO">SIIGO</option>
                    </select>
                </div>
                <div class="form-group col-md-9">
                    <label for="archivo">Archivo</label>
                    <input type="file" class="form-control-file" id="archivo" name="archivo" accept=".csv,.txt,.xls,.xlsx" required>
                    <small class="form-text text-muted">
                        Se conservan todas las columnas originales en JSON y además se indexan campos clave.
                    </small>
                </div>
            </div>
            <button class="btn btn-primary" type="submit">
                <i class="fas fa-upload mr-1"></i>Importar
            </button>
        </form>
    </div>
</div>

<div class="card shadow">
    <div class="card-header py-3">
        <h6 class="m-0 font-weight-bold text-primary">
            Registros importados (<?= (int)$totalRows ?>) - Página <?= (int)$page ?> de <?= (int)$totalPages ?>
        </h6>
    </div>
    <div class="card-body">
        <form class="form-row mb-3" method="get">
            <div class="col-md-2 mb-2">
                <input type="text" class="form-control" name="f_factura" placeholder="Factura" value="<?= esc($filterFactura) ?>">
            </div>
            <div class="col-md-2 mb-2">
                <select class="form-control" name="f_tipo">
                    <option value="">Tipo (todos)</option>
                    <option value="FV" <?= $filterTipo === 'FV' ? 'selected' : '' ?>>FV</option>
                    <option value="NC" <?= $filterTipo === 'NC' ? 'selected' : '' ?>>NC</option>
                    <option value="ND" <?= $filterTipo === 'ND' ? 'selected' : '' ?>>ND</option>
                    <option value="OTRO" <?= $filterTipo === 'OTRO' ? 'selected' : '' ?>>OTRO</option>
                </select>
            </div>
            <div class="col-md-2 mb-2">
                <select class="form-control" name="f_clase">
                    <option value="">Clase (todas)</option>
                    <option value="VENTA" <?= $filterClase === 'VENTA' ? 'selected' : '' ?>>VENTA</option>
                    <option value="COMPRA" <?= $filterClase === 'COMPRA' ? 'selected' : '' ?>>COMPRA</option>
                    <option value="SIN_CLASIFICAR" <?= $filterClase === 'SIN_CLASIFICAR' ? 'selected' : '' ?>>SIN_CLASIFICAR</option>
                </select>
            </div>
            <div class="col-md-3 mb-2">
                <input type="text" class="form-control" name="f_nombre" placeholder="Nombre emisor/receptor" value="<?= esc($filterNombre) ?>">
            </div>
            <div class="col-md-3 mb-2">
                <button class="btn btn-primary" type="submit">Filtrar</button>
                <a class="btn btn-secondary" href="/informes/reportes_dian.php">Limpiar</a>
            </div>
        </form>

        <div class="table-responsive">
            <table class="table table-sm table-bordered mb-0">
                <thead class="thead-light">
                    <tr>
                        <th>ID</th>
                        <th>Fuente</th>
                        <th>Archivo</th>
                        <th>Clase</th>
                        <th>Tipo</th>
                        <th>Factura Norm.</th>
                        <th>Nombre Emisor</th>
                        <th>Nombre Receptor</th>
                        <th>Llave documento</th>
                        <th class="text-right">Total</th>
                        <th class="text-center">Veces importado</th>
                        <th>Creado</th>
                        <th>Actualizado</th>
                    </tr>
                </thead>
                <tbody>
                    <?php if (empty($preview)): ?>
                        <tr>
                            <td colspan="13" class="text-center text-muted">Sin datos</td>
                        </tr>
                    <?php else: ?>
                        <?php foreach ($preview as $r): ?>
                            <tr>
                                <td><?= (int)$r['id'] ?></td>
                                <td><span class="badge badge-secondary"><?= esc($r['fuente']) ?></span></td>
                                <td><?= esc($r['archivoOrigen']) ?></td>
                                <td><span class="badge badge-<?= ($r['claseDocumento'] ?? '') === 'VENTA' ? 'success' : (($r['claseDocumento'] ?? '') === 'COMPRA' ? 'warning' : 'secondary') ?>"><?= esc($r['claseDocumento'] ?? '-') ?></span></td>
                                <td><?= esc($r['tipoMovimientoNorm'] ?? '-') ?></td>
                                <td><code><?= esc($r['facturaNormalizada'] ?? '-') ?></code></td>
                                <td><?= esc($r['nombreEmisor'] ?? '-') ?></td>
                                <td><?= esc($r['nombreReceptor'] ?? '-') ?></td>
                                <td><code><?= esc($r['documentoClave']) ?></code></td>
                                <td class="text-right"><?= esc($r['total'] ?? '-') ?></td>
                                <td class="text-center"><?= (int)$r['vecesImportado'] ?></td>
                                <td><?= esc($r['creadoEn']) ?></td>
                                <td><?= esc($r['actualizadoEn']) ?></td>
                            </tr>
                        <?php endforeach; ?>
                    <?php endif; ?>
                </tbody>
            </table>
        </div>

        <?php if ($totalPages > 1): ?>
            <?php
            $window = 2;
            $start = max(1, $page - $window);
            $end = min($totalPages, $page + $window);
            ?>
            <nav class="mt-3">
                <ul class="pagination pagination-sm mb-0">
                    <?php if ($page > 1): ?>
                        <li class="page-item">
                            <a class="page-link" href="<?= esc(pageUrl(['page' => 1])) ?>">&laquo;</a>
                        </li>
                        <li class="page-item">
                            <a class="page-link" href="<?= esc(pageUrl(['page' => (int)($page - 1)])) ?>">&lsaquo;</a>
                        </li>
                    <?php endif; ?>

                    <?php for ($p = $start; $p <= $end; $p++): ?>
                        <li class="page-item <?= $p === $page ? 'active' : '' ?>">
                            <a class="page-link" href="<?= esc(pageUrl(['page' => (int)$p])) ?>"><?= (int)$p ?></a>
                        </li>
                    <?php endfor; ?>

                    <?php if ($page < $totalPages): ?>
                        <li class="page-item">
                            <a class="page-link" href="<?= esc(pageUrl(['page' => (int)($page + 1)])) ?>">&rsaquo;</a>
                        </li>
                        <li class="page-item">
                            <a class="page-link" href="<?= esc(pageUrl(['page' => (int)$totalPages])) ?>">&raquo;</a>
                        </li>
                    <?php endif; ?>
                </ul>
            </nav>
        <?php endif; ?>
    </div>
</div>

<?php include __DIR__ . '/../templates/footer.php'; ?>
