<?php
/*
 * Paginación automática de diarios - componente independiente.
 * NO modifica ni utiliza el OCR interactivo de Noticias.
 */
require_once __DIR__ . '/gestor_archivos.php';
require_once __DIR__ . '/optimizador_multimedia.php';

if (!function_exists('ec_paginacion_preparar_esquema')) {
function ec_paginacion_preparar_esquema(mysqli $conn): void {
    ec_gestor_preparar_esquema($conn);

    $cols = [];
    if ($rs = $conn->query("SHOW COLUMNS FROM archivos_clasificacion")) {
        while ($r = $rs->fetch_assoc()) $cols[$r['Field']] = true;
        $rs->free();
    }
    $adds = [
        'pagina_editorial' => "ALTER TABLE archivos_clasificacion ADD COLUMN pagina_editorial INT NULL AFTER consecutivo",
        'lote_carga'       => "ALTER TABLE archivos_clasificacion ADD COLUMN lote_carga VARCHAR(80) NULL AFTER pagina_editorial",
        'posicion_lote'    => "ALTER TABLE archivos_clasificacion ADD COLUMN posicion_lote INT NULL AFTER lote_carga",
        'pagina_edicion'   => "ALTER TABLE archivos_clasificacion ADD COLUMN pagina_edicion INT NULL AFTER posicion_lote",
        'tipo_pagina'      => "ALTER TABLE archivos_clasificacion ADD COLUMN tipo_pagina VARCHAR(20) NULL AFTER pagina_edicion",
        'lote_origen'      => "ALTER TABLE archivos_clasificacion ADD COLUMN lote_origen VARCHAR(64) NULL AFTER tipo_pagina",
        'fuente_hash'      => "ALTER TABLE archivos_clasificacion ADD COLUMN fuente_hash CHAR(64) NULL AFTER lote_origen",
    ];
    foreach ($adds as $c => $sql) {
        if (!isset($cols[$c])) $conn->query($sql);
    }

    /* El mismo número de página se repite cada día: nombre_tecnico NO puede ser UNIQUE. */
    if ($rs = $conn->query("SHOW INDEX FROM archivos_clasificacion WHERE Key_name='uq_nombre_tecnico'")) {
        if ($rs->num_rows > 0) $conn->query("ALTER TABLE archivos_clasificacion DROP INDEX uq_nombre_tecnico");
        $rs->free();
    }
    if ($rs = $conn->query("SHOW INDEX FROM archivos_clasificacion WHERE Key_name='idx_nombre_tecnico'")) {
        if ($rs->num_rows === 0) $conn->query("CREATE INDEX idx_nombre_tecnico ON archivos_clasificacion(nombre_tecnico)");
        $rs->free();
    }

    $conn->query("CREATE TABLE IF NOT EXISTS archivos_lotes_pdf (
        hash_pdf CHAR(64) NOT NULL PRIMARY KEY,
        nombre_original VARCHAR(255) NOT NULL,
        medio_id INT NOT NULL,
        paginas INT NOT NULL DEFAULT 0,
        usuario_id INT NOT NULL,
        creado_en DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
}

function ec_paginacion_url(): string {
    $f = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'paginacion_config' . DIRECTORY_SEPARATOR . 'paginacion_url.txt';
    if (!is_file($f) || !is_readable($f)) return '';

    $u = rtrim(trim((string)file_get_contents($f)), '/');
    if ($u === '') return '';

    /*
     * PRUEBA LOCALHOST:
     * PHP (Laragon) y PAGINACION_SERVER están en la misma PC.
     * Se permite 127.0.0.1:8010 únicamente cuando la propia
     * plataforma también se está ejecutando en localhost.
     */
    $host = strtolower((string)($_SERVER['HTTP_HOST'] ?? ''));
    $esLocal = (
        $host === 'localhost' ||
        strpos($host, 'localhost:') === 0 ||
        $host === '127.0.0.1' ||
        strpos($host, '127.0.0.1:') === 0
    );

    if ($esLocal && preg_match('~^http://(?:127\.0\.0\.1|localhost):8010$~i', $u)) {
        return $u;
    }

    /*
     * PRODUCCIÓN:
     * se conserva exclusivamente la URL HTTPS de Cloudflare.
     */
    if (preg_match('~^https://[a-z0-9-]+\.trycloudflare\.com$~i', $u)) {
        return $u;
    }

    return '';
}

function ec_paginacion_carpeta_usuario(mysqli $conn, int $usuarioId, string $baseDir): array {
    $rol = 'Usuario';
    $login = 'usuario_' . $usuarioId;
    $st = $conn->prepare("SELECT u.usuario, u.rol_id, r.nombre AS rol_nombre FROM usuarios u LEFT JOIN roles r ON r.id=u.rol_id WHERE u.id=? LIMIT 1");
    if ($st) {
        $st->bind_param('i', $usuarioId); $st->execute();
        if ($u = $st->get_result()->fetch_assoc()) {
            $login = (string)($u['usuario'] ?: $login);
            $rid = (int)($u['rol_id'] ?? 0);
            if ($rid === 1) $rol = 'Superadministrador';
            elseif ($rid === 2) $rol = 'Administrador';
            elseif ($rid === 3) $rol = 'Editor';
            elseif (!empty($u['rol_nombre'])) $rol = (string)$u['rol_nombre'];
        }
        $st->close();
    }
    $limpiar = static function(string $v): string {
        $v = trim($v);
        $v = preg_replace('/[^A-Za-z0-9._-]+/u', '_', $v);
        return trim((string)$v, '._-') ?: 'usuario';
    };
    $rel = $limpiar($rol) . '/' . $limpiar($login) . '/' . date('Y') . '/' . date('m') . '/' . date('d') . '/';
    $dir = rtrim($baseDir, '/\\') . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $rel);
    if (!is_dir($dir) && !mkdir($dir, 0755, true) && !is_dir($dir)) throw new RuntimeException('No se pudo crear la carpeta de destino.');
    return ['dir' => rtrim($dir, '/\\') . DIRECTORY_SEPARATOR, 'rel' => $rel];
}

function ec_paginacion_datos_clasificacion(mysqli $conn, string $region, string $tipo, int $medioId): array {
    $codigoTipo = ec_gestor_codigo_tipo($tipo);
    if ($codigoTipo !== 'DR') throw new RuntimeException('La paginación automática solo se aplica al tipo Diario/Prensa.');
    $st = $conn->prepare("SELECT codigo FROM regiones_codigos WHERE region=? LIMIT 1");
    $st->bind_param('s', $region); $st->execute();
    $codigoRegion = (string)($st->get_result()->fetch_assoc()['codigo'] ?? ''); $st->close();
    if ($codigoRegion === '') throw new RuntimeException('La región seleccionada no tiene código.');
    $st = $conn->prepare("SELECT id,nombre_medio FROM medios WHERE id=? AND estado='activo' LIMIT 1");
    $st->bind_param('i', $medioId); $st->execute(); $medio = $st->get_result()->fetch_assoc(); $st->close();
    if (!$medio) throw new RuntimeException('El medio no existe o está inactivo.');
    return [
        'codigo_tipo' => $codigoTipo,
        'codigo_region' => $codigoRegion,
        'medio_nombre' => (string)$medio['nombre_medio'],
        'slug' => ec_gestor_slug_medio((string)$medio['nombre_medio'], $codigoTipo),
    ];
}

function ec_paginacion_registrar_jpg(mysqli $conn, int $usuarioId, string $baseDir, array $clasif, string $region, string $tipo, int $medioId, string $original, string $jpgBytes, int $pagina, string $tipoPagina, string $lote, int $posicion, string $fuenteHash=''): array {
    ec_paginacion_preparar_esquema($conn);
    if ($jpgBytes === '') throw new RuntimeException('La página procesada llegó vacía.');

    $hash = hash('sha256', $jpgBytes);
    $st = $conn->prepare("SELECT ac.nombre_tecnico FROM archivos_clasificacion ac INNER JOIN archivos a ON a.id=ac.archivo_id WHERE ac.hash_sha256=? LIMIT 1");
    $st->bind_param('s', $hash); $st->execute(); $dup = $st->get_result()->fetch_assoc(); $st->close();
    if ($dup) return ['ok'=>false, 'duplicado'=>true, 'mensaje'=>'Página duplicada: ' . $dup['nombre_tecnico']];

    $numero = str_pad((string)max(0, $pagina), 4, '0', STR_PAD_LEFT);
    $sufijo = $numero;
    if ($tipoPagina === 'PORTADA') $sufijo = '0000_PORTADA';
    elseif ($tipoPagina === 'CONTRAPORTADA') $sufijo = $numero . '_CONTRAPORTADA';

    $nombreBase = $clasif['codigo_region'] . '_DR_' . $clasif['slug'] . '_' . $sufijo;
    $nombreTecnico = $nombreBase . '.JPG';

    $up = ec_paginacion_carpeta_usuario($conn, $usuarioId, $baseDir);
    $ruta = $up['dir'] . $nombreTecnico;
    $relativo = $up['rel'] . $nombreTecnico;

    if (is_file($ruta)) throw new RuntimeException('Ya existe ' . $nombreTecnico . ' en la carpeta de hoy.');
    if (file_put_contents($ruta, $jpgBytes, LOCK_EX) === false) throw new RuntimeException('No se pudo guardar la página JPG.');

    /* El reconocimiento se hizo ANTES. Aquí sólo se aplica el optimizador existente. */
    if (function_exists('ec_optimizar_archivo_subido')) ec_optimizar_archivo_subido($ruta, $original);

    $hashFinal = hash_file('sha256', $ruta);
    $fecha = date('Y-m-d');
    $descripcion = 'Página de diario procesada automáticamente.';
    $paginaEdicion = $pagina;
    $consecutivo = max(0, $pagina);
    $loteOrigen = substr(hash('sha256', $lote . '|' . $original), 0, 64);

    $conn->begin_transaction();
    try {
        $st = $conn->prepare("INSERT INTO archivos(usuario_id,nota_origen_id,titulo,descripcion,archivo,tipo_archivo,fecha_archivo,estado) VALUES(?,NULL,?,?,?,?,?,'activo')");
        $tipoArchivo = 'imagen';
        $st->bind_param('isssss', $usuarioId, $nombreBase, $descripcion, $relativo, $tipoArchivo, $fecha);
        $st->execute(); $archivoId = (int)$conn->insert_id; $st->close();

        $medioNombre = $clasif['medio_nombre'];
        $codigoRegion = $clasif['codigo_region']; $codigoTipo = 'DR';
        $fuenteHash = trim($fuenteHash);
        $st = $conn->prepare("INSERT INTO archivos_clasificacion(archivo_id,nombre_original,nombre_tecnico,hash_sha256,region,codigo_region,tipo_medio,codigo_tipo,medio_id,medio_nombre,consecutivo,pagina_editorial,lote_carga,posicion_lote,pagina_edicion,tipo_pagina,lote_origen,fuente_hash,usuario_id) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
        $st->bind_param('isssssssisiiiisissi', $archivoId, $original, $nombreTecnico, $hashFinal, $region, $codigoRegion, $tipo, $codigoTipo, $medioId, $medioNombre, $consecutivo, $pagina, $lote, $posicion, $paginaEdicion, $tipoPagina, $loteOrigen, $fuenteHash, $usuarioId);
        $st->execute(); $st->close();
        $conn->commit();
        return ['ok'=>true,'id'=>$archivoId,'nombre_tecnico'=>$nombreTecnico,'archivo'=>$relativo,'pagina'=>$pagina,'tipo_pagina'=>$tipoPagina];
    } catch (Throwable $e) {
        $conn->rollback(); @unlink($ruta); throw $e;
    }
}

function ec_paginacion_numero_nombre(string $nombre): int {
    $base = pathinfo($nombre, PATHINFO_FILENAME);
    $patrones = [
        '~(?:page|pagina|pag|pg)[\s_-]*0*(\d{1,3})(?:\D|$)~i',
        '~[-_\s]0*(\d{1,3})$~',
        '~^0*(\d{1,3})$~'
    ];
    foreach ($patrones as $rx) {
        if (preg_match($rx,$base,$m)) {
            $n=(int)$m[1];
            if($n>=1 && $n<=199) return $n;
        }
    }
    return 0;
}

function ec_paginacion_asignar_imagenes(array $paginas): array {
    $n=count($paginas); if($n===0)return [];
    $asignadas=array_fill(0,$n,null); $conf=array_fill(0,$n,0.0);

    foreach($paginas as $i=>$p){
        $ocr=(int)($p['detectada']??0);
        $ocrConf=(float)($p['confianza']??0);
        $nom=ec_paginacion_numero_nombre((string)($p['nombre_original']??''));

        if($ocr>0 && $ocr<200 && $ocrConf>=0.72){
            $asignadas[$i]=$ocr; $conf[$i]=$ocrConf;
        } elseif($nom>0){
            $asignadas[$i]=$nom; $conf[$i]=0.90;
        } elseif($ocr>0 && $ocr<200 && $ocrConf>=0.55){
            $asignadas[$i]=$ocr; $conf[$i]=$ocrConf;
        }
    }

    $mejor=[];
    foreach($asignadas as $i=>$num){
        if($num===null)continue;
        if(!isset($mejor[$num]) || $conf[$i]>$conf[$mejor[$num]])$mejor[$num]=$i;
    }
    foreach($asignadas as $i=>$num)
        if($num!==null && ($mejor[$num]??$i)!==$i)$asignadas[$i]=null;

    $anchors=[];
    foreach($asignadas as $i=>$num)if($num!==null)$anchors[]=[$i,$num];
    for($a=0;$a<count($anchors)-1;$a++){
        [$li,$ln]=$anchors[$a];[$ri,$rn]=$anchors[$a+1];
        if(($rn-$ln)===($ri-$li) && $rn>$ln)
            for($j=$li+1;$j<$ri;$j++)if($asignadas[$j]===null)$asignadas[$j]=$ln+($j-$li);
    }

    $anchors2=[];
    foreach($asignadas as $i=>$num)if($num!==null)$anchors2[]=[$i,$num];
    if($anchors2){
        [$fi,$fn]=$anchors2[0];
        for($j=$fi-1;$j>=0;$j--){$v=$fn-($fi-$j);if($v>0&&$asignadas[$j]===null)$asignadas[$j]=$v;}
        [$li,$ln]=$anchors2[count($anchors2)-1];
        for($j=$li+1;$j<$n;$j++)if($asignadas[$j]===null)$asignadas[$j]=$ln+($j-$li);
    }else{
        for($i=0;$i<$n;$i++)$asignadas[$i]=$i+1;
    }
    return $asignadas;
}
}
