<?php
/* Gestor único de archivos: clasificación, nomenclatura, consecutivos y duplicados. */
if (!function_exists('ec_gestor_preparar_esquema')) {
function ec_gestor_preparar_esquema(mysqli $conn): void {
    static $preparado = false;
    if ($preparado) return;
    $preparado = true;
    $conn->query("CREATE TABLE IF NOT EXISTS regiones_codigos (
        id INT AUTO_INCREMENT PRIMARY KEY,
        region VARCHAR(100) NOT NULL,
        codigo CHAR(3) NOT NULL,
        orden INT NOT NULL DEFAULT 0,
        activo TINYINT(1) NOT NULL DEFAULT 1,
        UNIQUE KEY uq_region (region),
        KEY idx_codigo (codigo),
        KEY idx_orden_activo (activo, orden, region)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

    /* Compatibilidad con instalaciones donde la tabla ya existía. */
    $columnas = [];
    if ($rs = $conn->query("SHOW COLUMNS FROM regiones_codigos")) {
        while ($fila = $rs->fetch_assoc()) $columnas[$fila['Field']] = true;
        $rs->free();
    }
    if (!isset($columnas['orden'])) $conn->query("ALTER TABLE regiones_codigos ADD COLUMN orden INT NOT NULL DEFAULT 0 AFTER codigo");
    if (!isset($columnas['activo'])) $conn->query("ALTER TABLE regiones_codigos ADD COLUMN activo TINYINT(1) NOT NULL DEFAULT 1 AFTER orden");

    /* El código LIM es compartido por Lima y Callao (Lima): no puede ser UNIQUE. */
    if ($rs = $conn->query("SHOW INDEX FROM regiones_codigos WHERE Key_name='uq_codigo'")) {
        if ($rs->num_rows > 0) $conn->query("ALTER TABLE regiones_codigos DROP INDEX uq_codigo");
        $rs->free();
    }
    if ($rs = $conn->query("SHOW INDEX FROM regiones_codigos WHERE Key_name='idx_codigo'")) {
        if ($rs->num_rows === 0) $conn->query("CREATE INDEX idx_codigo ON regiones_codigos(codigo)");
        $rs->free();
    }
    if ($rs = $conn->query("SHOW INDEX FROM regiones_codigos WHERE Key_name='idx_orden_activo'")) {
        if ($rs->num_rows === 0) $conn->query("CREATE INDEX idx_orden_activo ON regiones_codigos(activo, orden, region)");
        $rs->free();
    }

    $map = [
      ['Amazonas','AMA',1], ['Áncash','ATA',2], ['Apurímac','APU',3],
      ['Arequipa','AQP',4], ['Ayacucho','AYP',5], ['Cajamarca','CAJ',6],
      ['Callao (Lima)','LIM',7], ['Cusco','CUZ',8], ['Huancavelica','HVC',9],
      ['Huánuco','HUA',10], ['Ica','ICA',11], ['Junín','JAU',12],
      ['La Libertad','TRU',13], ['Lambayeque','CIX',14], ['Lima','LIM',15],
      ['Loreto','IQT',16], ['Madre de Dios','MDD',17], ['Moquegua','MOQ',18],
      ['Pasco','PAS',19], ['Piura','PIU',20], ['Puno','PUN',21],
      ['San Martín','TPP',22], ['Tacna','TAC',23], ['Tumbes','TUM',24],
      ['Ucayali','UCA',25]
    ];
    $st=$conn->prepare("INSERT INTO regiones_codigos(region,codigo,orden,activo) VALUES(?,?,?,1) ON DUPLICATE KEY UPDATE codigo=VALUES(codigo), orden=VALUES(orden), activo=1");
    if($st){
        foreach($map as $item){
            [$r,$c,$o] = $item;
            $st->bind_param('ssi',$r,$c,$o);
            $st->execute();
        }
        $st->close();
    }
    $conn->query("CREATE TABLE IF NOT EXISTS archivos_clasificacion (
        archivo_id INT NOT NULL PRIMARY KEY,
        nombre_original VARCHAR(255) NOT NULL,
        nombre_tecnico VARCHAR(255) NOT NULL,
        hash_sha256 CHAR(64) NOT NULL,
        region VARCHAR(100) NOT NULL,
        codigo_region CHAR(3) NOT NULL,
        tipo_medio VARCHAR(50) NOT NULL,
        codigo_tipo CHAR(2) NOT NULL,
        medio_id INT NOT NULL,
        medio_nombre VARCHAR(255) NOT NULL,
        consecutivo INT NOT NULL,
        usuario_id INT NOT NULL,
        creado_en DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        UNIQUE KEY uq_hash (hash_sha256),
        UNIQUE KEY uq_nombre_tecnico (nombre_tecnico),
        KEY idx_busqueda (codigo_region,codigo_tipo,medio_id,consecutivo)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
    $conn->query("CREATE TABLE IF NOT EXISTS archivos_secuencias (
        codigo_region CHAR(3) NOT NULL,
        codigo_tipo CHAR(2) NOT NULL,
        medio_id INT NOT NULL,
        ultimo INT NOT NULL DEFAULT 0,
        PRIMARY KEY(codigo_region,codigo_tipo,medio_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
}

function ec_gestor_obtener_regiones(mysqli $conn): array {
    ec_gestor_preparar_esquema($conn);
    $regiones = [];
    $sql = "SELECT region, codigo FROM regiones_codigos WHERE activo=1 ORDER BY CASE WHEN orden>0 THEN orden ELSE 9999 END ASC, region ASC";
    if ($rs = $conn->query($sql)) {
        while ($fila = $rs->fetch_assoc()) $regiones[] = $fila;
        $rs->free();
    }
    return $regiones;
}

function ec_gestor_opciones_regiones(mysqli $conn, string $seleccionada=''): string {
    $html = '<option value="">Seleccionar región</option>';
    foreach (ec_gestor_obtener_regiones($conn) as $fila) {
        $region = (string)$fila['region'];
        $sel = ($region === $seleccionada) ? ' selected' : '';
        $html .= '<option value="'.htmlspecialchars($region, ENT_QUOTES, 'UTF-8').'"'.$sel.'>'.htmlspecialchars($region, ENT_QUOTES, 'UTF-8').'</option>';
    }
    return $html;
}

function ec_gestor_liberar_archivo(mysqli $conn, int $archivoId): bool {
    if ($archivoId <= 0) return false;

    /*
     * Si el archivo fue generado desde un PDF por el paginador,
     * conservamos el hash del PDF mientras exista al menos una de sus páginas.
     * Cuando se elimina la ÚLTIMA página del PDF, se libera también hash_pdf
     * para permitir volver a cargar exactamente ese PDF.
     *
     * Para archivos normales el comportamiento anterior no cambia.
     */
    $fuenteHash = '';
    $tieneFuenteHash = false;

    if ($rs = $conn->query("SHOW COLUMNS FROM archivos_clasificacion LIKE 'fuente_hash'")) {
        $tieneFuenteHash = ($rs->num_rows > 0);
        $rs->free();
    }

    if ($tieneFuenteHash) {
        $st = $conn->prepare("SELECT fuente_hash FROM archivos_clasificacion WHERE archivo_id=? LIMIT 1");
        if ($st) {
            $st->bind_param('i', $archivoId);
            $st->execute();
            $fila = $st->get_result()->fetch_assoc();
            $st->close();
            $fuenteHash = trim((string)($fila['fuente_hash'] ?? ''));
        }
    }

    $st = $conn->prepare("DELETE FROM archivos_clasificacion WHERE archivo_id=?");
    if (!$st) return false;
    $st->bind_param('i', $archivoId);
    $ok = $st->execute();
    $st->close();

    if (!$ok) return false;

    if ($fuenteHash !== '') {
        $st = $conn->prepare("SELECT COUNT(*) AS total FROM archivos_clasificacion WHERE fuente_hash=?");
        if ($st) {
            $st->bind_param('s', $fuenteHash);
            $st->execute();
            $restantes = (int)($st->get_result()->fetch_assoc()['total'] ?? 0);
            $st->close();

            if ($restantes === 0) {
                $st = $conn->prepare("DELETE FROM archivos_lotes_pdf WHERE hash_pdf=?");
                if ($st) {
                    $st->bind_param('s', $fuenteHash);
                    $st->execute();
                    $st->close();
                }
            }
        }
    }

    return true;
}
function ec_gestor_codigo_tipo(string $tipo): string {
    $t=mb_strtolower(trim($tipo),'UTF-8');
    if(strpos($t,'diario')!==false || strpos($t,'prensa')!==false) return 'DR';
    if(strpos($t,'radio')!==false) return 'RD';
    if(strpos($t,'tele')!==false) return 'TV';
    if(strpos($t,'red')!==false) return 'RS';
    if(strpos($t,'web')!==false || strpos($t,'página')!==false || strpos($t,'pagina')!==false) return 'PW';
    return '';
}
function ec_gestor_slug_medio(string $nombre, string $codigoTipo): string {
    $s=mb_strtoupper(trim($nombre),'UTF-8');
    $s=str_replace(['Á','É','Í','Ó','Ú','Ü','Ñ'],['A','E','I','O','U','U','N'],$s);
    $s=preg_replace('/\b(DIARIO|RADIO|TELEVISION|TELEVISIÓN|TV|EMISORA|PAGINA WEB|PÁGINA WEB|REDES SOCIALES)\b/u',' ',$s);
    $s=preg_replace('/[^A-Z0-9]+/','_',$s);
    $s=trim($s,'_');
    return $s!=='' ? substr($s,0,100) : 'MEDIO';
}
function ec_gestor_subir(mysqli $conn, array $file, int $usuarioId, string $baseDir, string $descripcion='Archivo cargado al repositorio'): array {
    ec_gestor_preparar_esquema($conn);
    if(empty($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) return ['ok'=>false,'mensaje'=>'No se recibió un archivo válido.'];
    $region=trim((string)($_POST['region_clasificacion']??''));
    $tipo=trim((string)($_POST['tipo_medio_clasificacion']??''));
    $medioId=(int)($_POST['medio_id_clasificacion']??0);
    if($region===''||$tipo===''||$medioId<=0) return ['ok'=>false,'mensaje'=>'Región, tipo de medio y medio son obligatorios.'];
    $codigoTipo=ec_gestor_codigo_tipo($tipo); if($codigoTipo==='') return ['ok'=>false,'mensaje'=>'Tipo de medio no válido.'];
    $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==='') return ['ok'=>false,'mensaje'=>'La región seleccionada no tiene código registrado.'];
    $st=$conn->prepare("SELECT id,nombre_medio,region,tipo_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) return ['ok'=>false,'mensaje'=>'El medio seleccionado no existe o está inactivo.'];
    $hash=hash_file('sha256',$file['tmp_name']);
    /* Limpia bloqueos huérfanos de archivos que ya fueron eliminados del repositorio. */
    $st=$conn->prepare("DELETE ac FROM archivos_clasificacion ac LEFT JOIN archivos a ON a.id=ac.archivo_id WHERE ac.hash_sha256=? AND a.id IS NULL");
    if($st){ $st->bind_param('s',$hash); $st->execute(); $st->close(); }
    $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'=>"Este archivo ya se encuentra registrado en el sistema.\n".$dup['nombre_tecnico']];
    $original=basename((string)$file['name']); $ext=strtolower(pathinfo($original,PATHINFO_EXTENSION));
    $conn->begin_transaction();
    try {
      $st=$conn->prepare("INSERT INTO archivos_secuencias(codigo_region,codigo_tipo,medio_id,ultimo) VALUES(?,?,?,LAST_INSERT_ID(1)) ON DUPLICATE KEY UPDATE ultimo=LAST_INSERT_ID(ultimo+1)");
      $st->bind_param('ssi',$codigoRegion,$codigoTipo,$medioId); $st->execute(); $seq=(int)$conn->insert_id; $st->close(); if($seq<1){$seq=1;}
      $slug=ec_gestor_slug_medio((string)$medio['nombre_medio'],$codigoTipo);
      $nombreBase=$codigoRegion.'_'.$codigoTipo.'_'.$slug.'_'.str_pad((string)$seq,3,'0',STR_PAD_LEFT);
      $nombreTecnico=$nombreBase.'.'.strtoupper($ext ?: 'BIN');
      if(!function_exists('crearCarpetaUploadUsuario')) throw new Exception('No está disponible el gestor de carpetas de usuario.');
      $up=crearCarpetaUploadUsuario($conn,$usuarioId,$baseDir); $dir=rtrim($up['dir'],'/').'/'; $rel=$up['rel'];
      if(!is_dir($dir) && !mkdir($dir,0755,true)) throw new Exception('No se pudo crear la carpeta de destino.');
      $ruta=$dir.$nombreTecnico; $relativo=$rel.$nombreTecnico;
      if(!move_uploaded_file($file['tmp_name'],$ruta)) throw new Exception('No se pudo mover el archivo al servidor.');
      if(function_exists('ec_optimizar_archivo_subido')) ec_optimizar_archivo_subido($ruta,$original);
      $extFinal=strtolower(pathinfo($ruta,PATHINFO_EXTENSION));
      $tipoArchivo='documento'; if(in_array($extFinal,['mp3','wav','aac','ogg','m4a'],true))$tipoArchivo='audio'; elseif(in_array($extFinal,['jpg','jpeg','png','gif','webp'],true))$tipoArchivo='imagen'; elseif(in_array($extFinal,['mp4','webm','mov','avi','mkv'],true))$tipoArchivo='video'; elseif($extFinal==='pdf')$tipoArchivo='pdf';
      $titulo=$nombreBase; $fecha=date('Y-m-d');
      $st=$conn->prepare("INSERT INTO archivos(usuario_id,nota_origen_id,titulo,descripcion,archivo,tipo_archivo,fecha_archivo,estado) VALUES(?,NULL,?,?,?,?,?,'activo')");
      $st->bind_param('isssss',$usuarioId,$titulo,$descripcion,$relativo,$tipoArchivo,$fecha); $st->execute(); $archivoId=(int)$conn->insert_id; $st->close();
      $medioNombre=(string)$medio['nombre_medio'];
      $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,usuario_id) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)");
      $st->bind_param('isssssssisii',$archivoId,$original,$nombreTecnico,$hash,$region,$codigoRegion,$tipo,$codigoTipo,$medioId,$medioNombre,$seq,$usuarioId); $st->execute(); $st->close();
      $conn->commit();
      return ['ok'=>true,'mensaje'=>'Archivo cargado correctamente.','id'=>$archivoId,'archivo'=>$relativo,'titulo'=>$titulo,'nombre_tecnico'=>$nombreTecnico];
    } catch(Throwable $e){ $conn->rollback(); if(isset($ruta)&&is_file($ruta))@unlink($ruta); return ['ok'=>false,'mensaje'=>'No se pudo registrar el archivo: '.$e->getMessage()]; }
}
}
