<?php
// lib_documentos.php
// Lógica central del "checklist vs. cargado" para una obra.
// Un documento_requerido puede aplicar a la obra completa, a CADA
// titular vinculado (filtrado por su condición), o a CADA relación
// obra-titular específica (filtrado por rol). Esta función expande
// el catálogo en "slots" concretos para una obra dada, y cruza cada
// slot contra lo realmente cargado.

function _cumpleCondicion(array $dr, array $entidad): bool {
    if (!$dr['condicion_campo']) return true;
    $campo = $dr['condicion_campo'];
    if (!array_key_exists($campo, $entidad)) return false;
    return (string)$entidad[$campo] === (string)$dr['condicion_valor'];
}

function calcularSlotsDocumentales(PDO $pdo, int $obraId): array {
    $requeridos = $pdo->query("SELECT * FROM documentos_requeridos WHERE activo = 1 ORDER BY orden")->fetchAll();

    $stmt = $pdo->prepare("
        SELECT ot.id AS relacion_id, ot.rol, ot.titular_id, ot.porcentaje_reparto,
               t.tipo_persona, t.nombres_completos, t.identificacion, t.es_causahabiente
        FROM obra_titulares ot
        JOIN titulares t ON t.id = ot.titular_id
        WHERE ot.obra_id = ?
    ");
    $stmt->execute([$obraId]);
    $obraTitulares = $stmt->fetchAll();

    // Titulares únicos vinculados a la obra (para los documentos_requeridos
    // que aplican por titular, no por cada rol que tenga en la obra).
    $titularesUnicos = [];
    foreach ($obraTitulares as $ot) {
        $titularesUnicos[$ot['titular_id']] = $ot;
    }

    $slots = [];
    foreach ($requeridos as $dr) {
        if ($dr['aplica_a'] === 'obra') {
            $slots[] = ['dr' => $dr, 'entidad_tipo' => 'obra', 'entidad_id' => $obraId, 'etiqueta' => null];
        } elseif ($dr['aplica_a'] === 'titular') {
            foreach ($titularesUnicos as $tid => $t) {
                if (_cumpleCondicion($dr, $t)) {
                    $slots[] = ['dr' => $dr, 'entidad_tipo' => 'titular', 'entidad_id' => $tid, 'etiqueta' => $t['nombres_completos']];
                }
            }
        } elseif ($dr['aplica_a'] === 'relacion') {
            foreach ($obraTitulares as $ot) {
                if (_cumpleCondicion($dr, $ot)) {
                    $slots[] = [
                        'dr' => $dr, 'entidad_tipo' => 'relacion', 'entidad_id' => $ot['relacion_id'],
                        'etiqueta' => $ot['nombres_completos'] . ' (' . $ot['rol'] . ')',
                    ];
                }
            }
        }
    }

    $stmtDocs = $pdo->prepare("
        SELECT * FROM documentos
        WHERE documento_requerido_id = ? AND entidad_tipo = ? AND entidad_id = ?
        ORDER BY fecha_carga DESC
    ");

    $cargados = [];
    $pendientes = [];
    $obligatoriosTotales = 0;
    $obligatoriosCompletos = 0;

    foreach ($slots as $slot) {
        $dr = $slot['dr'];
        $stmtDocs->execute([$dr['id'], $slot['entidad_tipo'], $slot['entidad_id']]);
        $archivos = $stmtDocs->fetchAll();

        // Dos cosas distintas:
        // - $tieneValido: cuenta para "obligatorios completos" y para poder
        //   finalizar la obra. Solo cumplido/aprobado cuenta como resuelto.
        // - $tieneOcupante: determina si el slot sigue apareciendo en el
        //   select de "pendientes". Un documento en revisión YA ocupa el
        //   slot (no se permite cargar dos veces la misma categoría
        //   mientras se espera revisión) — pero uno rechazado NO ocupa,
        //   así que vuelve a aparecer como pendiente para poder corregirlo.
        //   EXCEPCIÓN: si dr.permite_multiples = 1 (ej. "Aceptación"),
        //   el slot NUNCA se considera ocupado — siempre se puede agregar
        //   otro archivo/registro más, porque puede haber varias piezas
        //   de evidencia independientes.
        $tieneValido = false;
        $tieneOcupante = false;
        foreach ($archivos as $a) {
            if (in_array($a['estado'], ['cumplido', 'aprobado'], true)) {
                $tieneValido = true;
                $tieneOcupante = true;
            } elseif ($a['estado'] === 'pendiente_revision') {
                $tieneOcupante = true;
            }
        }
        if ($dr['permite_multiples']) {
            $tieneOcupante = false;
        }

        if ($dr['obligatorio']) {
            $obligatoriosTotales++;
            if ($tieneValido) $obligatoriosCompletos++;
        }

        if (!empty($archivos)) {
            $cargados[] = $slot + ['archivos' => $archivos, 'cumplido' => $tieneValido];
        }
        if (!$tieneOcupante) {
            $pendientes[] = $slot;
        }
    }

    return [
        'cargados' => $cargados,
        'pendientes' => $pendientes,
        'obligatorios_totales' => $obligatoriosTotales,
        'obligatorios_completos' => $obligatoriosCompletos,
    ];
}

// Código de VERIFICACIÓN PÚBLICA — deliberadamente aleatorio, no
// correlativo. numero_caso es secuencial (RE202600000001, 02, 03...)
// y por eso NUNCA debe usarse como clave de una página pública: alguien
// podría recorrer todos los números y consultar cada obra del sistema.
// Este código de 16 caracteres no permite esa enumeración.
function generarCodigoVerificacion(PDO $pdo): string {
    do {
        $codigo = strtoupper(bin2hex(random_bytes(8)));
        $stmt = $pdo->prepare("SELECT 1 FROM obras WHERE codigo_verificacion = ?");
        $stmt->execute([$codigo]);
    } while ($stmt->fetchColumn()); // prácticamente nunca se repite, pero se verifica igual
    return $codigo;
}

// Dado un documento, resuelve a qué obra pertenece (directa o
// indirectamente) y una etiqueta legible — usado por el módulo Revisor
// para mostrar contexto sin necesitar tres consultas distintas en cada
// vista. Un documento de TITULAR puede no pertenecer a una sola obra
// (la persona puede estar en varias); en ese caso se muestra la más
// reciente como referencia.
function contextoDocumento(PDO $pdo, array $doc): array {
    if ($doc['entidad_tipo'] === 'obra') {
        $stmt = $pdo->prepare("SELECT id, titulo, numero_caso FROM obras WHERE id = ?");
        $stmt->execute([$doc['entidad_id']]);
        $o = $stmt->fetch();
        return [
            'obra_id'     => $o['id'] ?? null,
            'obra_titulo' => $o['titulo'] ?? '(obra no encontrada)',
            'numero_caso' => $o['numero_caso'] ?? null,
            'etiqueta'    => null,
        ];
    }
    if ($doc['entidad_tipo'] === 'relacion') {
        $stmt = $pdo->prepare("
            SELECT o.id, o.titulo, o.numero_caso, t.nombres_completos, ot.rol
            FROM obra_titulares ot
            JOIN obras o ON o.id = ot.obra_id
            JOIN titulares t ON t.id = ot.titular_id
            WHERE ot.id = ?
        ");
        $stmt->execute([$doc['entidad_id']]);
        $r = $stmt->fetch();
        return [
            'obra_id'     => $r['id'] ?? null,
            'obra_titulo' => $r['titulo'] ?? '(obra no encontrada)',
            'numero_caso' => $r['numero_caso'] ?? null,
            'etiqueta'    => $r ? $r['nombres_completos'] . ' (' . $r['rol'] . ')' : null,
        ];
    }
    if ($doc['entidad_tipo'] === 'titular') {
        $stmt = $pdo->prepare("SELECT nombres_completos FROM titulares WHERE id = ?");
        $stmt->execute([$doc['entidad_id']]);
        $t = $stmt->fetch();

        $stmt2 = $pdo->prepare("
            SELECT o.id, o.titulo, o.numero_caso
            FROM obra_titulares ot JOIN obras o ON o.id = ot.obra_id
            WHERE ot.titular_id = ? ORDER BY o.creado_en DESC LIMIT 1
        ");
        $stmt2->execute([$doc['entidad_id']]);
        $o = $stmt2->fetch();
        return [
            'obra_id'     => $o['id'] ?? null,
            'obra_titulo' => $o['titulo'] ?? '(sin obra asociada)',
            'numero_caso' => $o['numero_caso'] ?? null,
            'etiqueta'    => $t['nombres_completos'] ?? null,
        ];
    }
    return ['obra_id' => null, 'obra_titulo' => '—', 'numero_caso' => null, 'etiqueta' => null];
}

// Recolecta los correos de "todos los interesados" de una obra: quien
// la creó, más cada titular vinculado que tenga correo registrado.
// Usado para notificaciones de transparencia (ej. cuando un admin
// elimina un documento de una obra ya finalizada).
function correosInteresadosObra(PDO $pdo, int $obraId): array {
    $correos = [];

    $stmt = $pdo->prepare("SELECT u.correo FROM obras o JOIN usuarios u ON u.id = o.creado_por WHERE o.id = ?");
    $stmt->execute([$obraId]);
    $c = $stmt->fetchColumn();
    if ($c) $correos[] = $c;

    $stmt = $pdo->prepare("
        SELECT DISTINCT t.correo FROM obra_titulares ot JOIN titulares t ON t.id = ot.titular_id
        WHERE ot.obra_id = ? AND t.correo IS NOT NULL AND t.correo != ''
    ");
    $stmt->execute([$obraId]);
    foreach ($stmt->fetchAll(PDO::FETCH_COLUMN) as $c) $correos[] = $c;

    return array_values(array_unique($correos));
}

// Verifica si el usuario puede VER un documento cargado — usado por
// ver_archivo.php antes de entregar cualquier archivo. A diferencia de
// documentoPerteneceAObra() (que verifica contra una obra puntual ya
// confirmada), esta función parte solo del documento y determina de
// cuál obra depende, sin importar si es a nivel de obra, titular o
// relación.
function usuarioPuedeVerDocumento(PDO $pdo, array $doc, array $u): bool {
    if ($u['rol'] === 'admin' || $u['rol'] === 'revisor') return true;

    if ($doc['entidad_tipo'] === 'obra') {
        $stmt = $pdo->prepare("SELECT 1 FROM obras WHERE id = ? AND creado_por = ?");
        $stmt->execute([$doc['entidad_id'], $u['id']]);
        return (bool)$stmt->fetchColumn();
    }
    if ($doc['entidad_tipo'] === 'relacion') {
        $stmt = $pdo->prepare("
            SELECT 1 FROM obra_titulares ot JOIN obras o ON o.id = ot.obra_id
            WHERE ot.id = ? AND o.creado_por = ?
        ");
        $stmt->execute([$doc['entidad_id'], $u['id']]);
        return (bool)$stmt->fetchColumn();
    }
    if ($doc['entidad_tipo'] === 'titular') {
        // Un documento de titular (RUT, formulario...) no pertenece a una
        // sola obra — se permite verlo si el titular participa en AL MENOS
        // una obra de este usuario.
        $stmt = $pdo->prepare("
            SELECT 1 FROM obra_titulares ot JOIN obras o ON o.id = ot.obra_id
            WHERE ot.titular_id = ? AND o.creado_por = ?
        ");
        $stmt->execute([$doc['entidad_id'], $u['id']]);
        return (bool)$stmt->fetchColumn();
    }
    return false;
}

// Verifica que un documento cargado (fila de `documentos`) de verdad
// pertenece a esta obra — directamente (entidad_tipo=obra), a uno de
// sus titulares, o a una de sus relaciones obra_titulares — antes de
// dejar editarlo/eliminarlo. Evita que alguien manipule el formulario
// para tocar documentos de otra obra ajena.
function documentoPerteneceAObra(PDO $pdo, int $documentoId, int $obraId): ?array {
    $stmt = $pdo->prepare("SELECT * FROM documentos WHERE id = ?");
    $stmt->execute([$documentoId]);
    $doc = $stmt->fetch();
    if (!$doc) return null;

    if ($doc['entidad_tipo'] === 'obra') {
        return $doc['entidad_id'] == $obraId ? $doc : null;
    }
    if ($doc['entidad_tipo'] === 'titular') {
        $stmt = $pdo->prepare("SELECT 1 FROM obra_titulares WHERE obra_id = ? AND titular_id = ?");
        $stmt->execute([$obraId, $doc['entidad_id']]);
        return $stmt->fetchColumn() ? $doc : null;
    }
    if ($doc['entidad_tipo'] === 'relacion') {
        $stmt = $pdo->prepare("SELECT 1 FROM obra_titulares WHERE id = ? AND obra_id = ?");
        $stmt->execute([$doc['entidad_id'], $obraId]);
        return $stmt->fetchColumn() ? $doc : null;
    }
    return null;
}

// Codifica un slot en un valor único para el <select>, ej "14|obra|7"
function codificarSlot(array $slot): string {
    return $slot['dr']['id'] . '|' . $slot['entidad_tipo'] . '|' . $slot['entidad_id'];
}

function decodificarSlot(string $valor): ?array {
    $partes = explode('|', $valor);
    if (count($partes) !== 3) return null;
    return ['documento_requerido_id' => (int)$partes[0], 'entidad_tipo' => $partes[1], 'entidad_id' => (int)$partes[2]];
}
