<?php
declare(strict_types=1);
ob_start();
session_start();
require __DIR__ . '/../../config/auth.php';
require __DIR__ . '/../../../../../config/db2.php';
require __DIR__ . '/../../lib/helpers.php';
ob_end_clean();

header('Content-Type: application/json');

function jsonErr(string $msg): void { echo json_encode(['ok'=>false,'error'=>$msg]); exit; }

try {
    $aa_id    = (int)($_POST['aa_id']   ?? 0);
    $jornadas = max(1, (int)($_POST['jornadas']  ?? 1));
    $extras   = max(0, (int)($_POST['extras']    ?? 0));
    $pre      = max(0, (int)($_POST['pre']       ?? 0));

    if (!$aa_id) jsonErr('AA inválido');

    // ── Datos del AA ─────────────────────────────────────────────────────────────
    $stmt = $pdo->prepare("SELECT juez_aa_id, tipo_tribunal, duplicidad_plazos FROM agj_autos_apertura WHERE id=?");
    $stmt->execute([$aa_id]);
    $aa_data = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$aa_data) jsonErr('AA no encontrado');

    $esUnipersonal = stripos($aa_data['tipo_tribunal'] ?? '', 'unipersonal') !== false;
    $juecesNec     = $esUnipersonal ? 1 : 3;
    $duplicidad    = (bool)$aa_data['duplicidad_plazos'];

    // ── Plazos desde DB (RN2, RN6, RN7) ─────────────────────────────────────────
    $dv_base = (int)get_param($pdo, 'dias_habiles_veredicto',   '2');
    $df_base = (int)get_param($pdo, 'dias_habiles_fundamentos', '5');

    // RN6: mínimo de fundamentos para Unipersonal según duración total del debate
    $total_debate_dias = $jornadas + $extras + $pre;
    if ($esUnipersonal) {
        $min_fund = $total_debate_dias <= 3 ? 3 : ($total_debate_dias === 4 ? 4 : 5);
        $df_base  = max($df_base, $min_fund);
    }

    // RN7: duplicar plazos si corresponde
    $dv = $duplicidad ? $dv_base * 2 : $dv_base;
    $df = $duplicidad ? $df_base * 2 : $df_base;

    // ── Jueces inhabilitados: IPP + juez instructor (RN8) ────────────────────────
    $stmt_ji = $pdo->prepare("SELECT juez_id FROM agj_aa_jueces_ipp WHERE aa_id=?");
    $stmt_ji->execute([$aa_id]);
    $inhab_ids = array_column($stmt_ji->fetchAll(), 'juez_id');
    if ($aa_data['juez_aa_id']) $inhab_ids[] = $aa_data['juez_aa_id'];
    $inhab_ids = array_unique(array_filter($inhab_ids));

    // ── Coordinador Rosario actual (RN12) ────────────────────────────────────────
    $stmtCoord = $pdo->query("
        SELECT jr.juez_id
        FROM juez_rol jr
        JOIN roles_juez rj ON rj.id = jr.rolJuez_id
        WHERE rj.nombre = 'Coordinador Rosario'
          AND jr.deleted_at IS NULL
          AND CURDATE() BETWEEN jr.fecha_desde AND COALESCE(jr.fecha_hasta, '9999-12-31')
        LIMIT 1
    ");
    $coordinadorId = $stmtCoord->fetchColumn() ?: null;

    // ── Pool de jueces: Rosario, JO vigente, no inhabilitados (RN8) ──────────────
    $juecesPool = $pdo->query("
        SELECT j.juez_id, j.nombre
        FROM mrbs_juez j
        WHERE j.instancia=1 AND j.activo=1
          AND j.colegio = 'Rosario'
          AND j.juez_id NOT IN ('J000','JT00','JC00','JIPP')
          AND EXISTS (
              SELECT 1 FROM mrbs_competencia_jueces cj
              WHERE cj.juez_id = j.juez_id
                AND cj.competencia = 'JO'
                AND CURDATE() BETWEEN cj.desde AND cj.hasta
          )
        ORDER BY j.nombre
    ")->fetchAll(PDO::FETCH_ASSOC);
    $juecesPool = array_values(array_filter($juecesPool,
        fn($j) => !in_array($j['juez_id'], $inhab_ids, true)));

    // ── Litigantes del AA (RN9) ───────────────────────────────────────────────────
    $stmtL = $pdo->prepare("SELECT litigante_id FROM agj_aa_litigantes WHERE aa_id=?");
    $stmtL->execute([$aa_id]);
    $litIds = array_column($stmtL->fetchAll(), 'litigante_id'); // varchar(4), no castear a int

    // ── Rango ─────────────────────────────────────────────────────────────────────
    $today   = date('Y-m-d');
    $horizon = date('Y-m-d', strtotime('+6 months'));

    // ── Pre-cargar feriados en el rango (RN1) ─────────────────────────────────────
    $stmtF = $pdo->prepare("SELECT fecha FROM ogj_feriados WHERE fecha BETWEEN ? AND ?");
    $stmtF->execute([$today, $horizon]);
    $feriadosSet = array_flip(array_column($stmtF->fetchAll(PDO::FETCH_ASSOC), 'fecha'));

    // ── Pre-cargar feriados del año corriente para RN13 ───────────────────────────
    $anioActual  = (int)date('Y');
    $stmtFA = $pdo->prepare("SELECT fecha FROM ogj_feriados WHERE fecha BETWEEN ? AND ?");
    $stmtFA->execute(["$anioActual-01-01", "$anioActual-12-31"]);
    $feriadosAnioSet = array_flip(array_column($stmtFA->fetchAll(PDO::FETCH_ASSOC), 'fecha'));

    // ── Pre-cargar agendamientos activos en el horizonte ──────────────────────────
    $agends = $pdo->query("
        SELECT ag.id, ag.aa_id,
               ag.debate_desde, ag.debate_hasta, ag.fecha_fallo, ag.fecha_fin_bloqueo,
               ag.presidente_id, ag.vocal_1_id, ag.vocal_2_id
        FROM agj_agendamientos ag
        WHERE ag.deleted_at IS NULL
          AND ag.estado NOT IN ('Cancelado')
          AND ag.fecha_fin_bloqueo >= '$today'
          AND ag.debate_desde     <= '$horizon'
    ")->fetchAll(PDO::FETCH_ASSOC);

    // ── Licencias de jueces en el horizonte (RN11) ───────────────────────────────
    $stLic = $pdo->prepare("
        SELECT juez_id,
               DATE(FROM_UNIXTIME(start_time)) AS lic_desde,
               DATE(FROM_UNIXTIME(end_time))   AS lic_hasta
        FROM mrbs_entry
        WHERE tipoAudiencia_id = 'IP62'
          AND juez_id IS NOT NULL AND juez_id != ''
          AND DATE(FROM_UNIXTIME(end_time))   >= ?
          AND DATE(FROM_UNIXTIME(start_time)) <= ?
    ");
    $stLic->execute([$today, $horizon]);
    $licencias = $stLic->fetchAll(PDO::FETCH_ASSOC);

    // ── Litigantes por AA (para chequeo de superposición) ────────────────────────
    $aaIds   = array_values(array_unique(array_filter(array_column($agends, 'aa_id'))));
    $litByAA = [];
    if ($aaIds) {
        $ph   = implode(',', array_fill(0, count($aaIds), '?'));
        $rows = $pdo->prepare("SELECT aa_id, litigante_id FROM agj_aa_litigantes WHERE aa_id IN ($ph)");
        $rows->execute($aaIds);
        foreach ($rows->fetchAll() as $r) {
            $litByAA[(int)$r['aa_id']][] = $r['litigante_id']; // varchar(4), no castear
        }
    }

    // ── CUIJ de cada AA (para detalle de conflicto) ───────────────────────────────
    $cuijByAA = [];
    if ($aaIds) {
        $ph   = implode(',', array_fill(0, count($aaIds), '?'));
        $rows = $pdo->prepare("SELECT id, cuij_principal FROM agj_autos_apertura WHERE id IN ($ph)");
        $rows->execute($aaIds);
        foreach ($rows->fetchAll() as $r) {
            $cuijByAA[(int)$r['id']] = $r['cuij_principal'];
        }
    }

    // ── Nombres de litigantes del AA (para detalle de conflicto) ─────────────────
    $litNames = [];
    if ($litIds) {
        $ph    = implode(',', array_fill(0, count($litIds), '?'));
        $stmtN = $pdo->prepare("SELECT litigante_id, nombre FROM v_litigantes WHERE litigante_id IN ($ph)");
        $stmtN->execute($litIds);
        foreach ($stmtN->fetchAll() as $r) {
            $litNames[$r['litigante_id']] = $r['nombre'];
        }
    }

    // ── Helpers locales ───────────────────────────────────────────────────────────

    // RN1: día hábil usando feriados pre-cargados (sin query por fecha)
    $esHabilAnio = fn(string $f): bool =>
        (int)(new DateTime($f))->format('N') <= 5 && !isset($feriadosAnioSet[$f]);

    // RN13: contar días hábiles entre dos fechas inclusive (usa feriados del año)
    $contarHabiles = function(string $desde, string $hasta) use ($esHabilAnio): int {
        if (!$desde || !$hasta || $desde > $hasta) return 0;
        $d = new DateTime($desde); $h = new DateTime($hasta);
        $n = 0;
        while ($d <= $h) { if ($esHabilAnio($d->format('Y-m-d'))) $n++; $d->modify('+1 day'); }
        return $n;
    };

    // RN13: acumulado de días de debate en el año por juez
    $anio = (string)$anioActual;
    $diasAcum = [];
    foreach ($agends as $ag) {
        if (!$ag['debate_desde'] || substr($ag['debate_desde'], 0, 4) !== $anio) continue;
        $dias = $contarHabiles($ag['debate_desde'], $ag['debate_hasta'] ?: $ag['debate_desde']);
        foreach (['presidente_id','vocal_1_id','vocal_2_id'] as $col) {
            if ($ag[$col]) $diasAcum[$ag[$col]] = ($diasAcum[$ag[$col]] ?? 0) + $dias;
        }
    }

    $esHabil = function(string $fecha) use ($feriadosSet): bool {
        return (int)(new DateTime($fecha))->format('N') <= 5 && !isset($feriadosSet[$fecha]);
    };

    // Avanzar N días hábiles (RN1 aplicado, sin queries adicionales)
    $addHabil = function(string $fecha, int $n) use ($esHabil): string {
        if ($n <= 0) return $fecha;
        $d = new DateTime($fecha);
        $c = 0;
        while ($c < $n) {
            $d->modify('+1 day');
            if ($esHabil($d->format('Y-m-d'))) $c++;
        }
        return $d->format('Y-m-d');
    };

    // RN2: calcular todas las fechas del juicio propuesto
    $diasAdicionales = $jornadas - 1 + $extras + $pre;
    $calcFechas = function(string $desde) use ($addHabil, $diasAdicionales, $dv, $df): array {
        $hasta   = $diasAdicionales > 0 ? $addHabil($desde, $diasAdicionales) : $desde;
        $fallo   = $addHabil($hasta, $dv);
        $bloqueo = $addHabil($fallo, $df);
        return [
            'debate_desde'      => $desde,
            'debate_hasta'      => $hasta,
            'fecha_fallo'       => $fallo,
            'fecha_fin_bloqueo' => $bloqueo,
        ];
    };

    // RN4/RN5/RN11: evaluar disponibilidad del tribunal para un juicio propuesto
    // RN4  — Presidente: bloqueado durante todo el período [desde..fin_bloqueo]
    // RN5  — Vocal:      bloqueado solo durante [desde..fecha_fallo]
    // RN11 — Licencia:   bloqueado si la licencia solapa con [desde..fin_bloqueo]
    $evalTribunal = function(array $f) use ($agends, $juecesPool, $juecesNec, $licencias, $diasAcum): array {
        $ocupados = [];
        foreach ($agends as $ag) {
            // RN4: presidente bloqueado si solapa con [propuesta.desde..propuesta.fin_bloqueo]
            if ($ag['presidente_id']
                && $ag['debate_desde']      <= $f['fecha_fin_bloqueo']
                && $ag['fecha_fin_bloqueo'] >= $f['debate_desde']) {
                $ocupados[$ag['presidente_id']] = true;
            }
            // RN5: vocales bloqueados si solapa con [propuesta.desde..propuesta.fecha_fallo]
            if ($ag['debate_desde']  <= $f['fecha_fallo']
                && $ag['fecha_fallo'] >= $f['debate_desde']) {
                if ($ag['vocal_1_id']) $ocupados[$ag['vocal_1_id']] = true;
                if ($ag['vocal_2_id']) $ocupados[$ag['vocal_2_id']] = true;
            }
        }
        // RN11: jueces de licencia que solapan con [debate_desde..fecha_fin_bloqueo]
        foreach ($licencias as $lic) {
            if ($lic['lic_desde'] <= $f['fecha_fin_bloqueo']
                && $lic['lic_hasta'] >= $f['debate_desde']) {
                $ocupados[$lic['juez_id']] = true;
            }
        }
        $libres = array_values(array_filter($juecesPool, fn($j) => !isset($ocupados[$j['juez_id']])));
        // RN13: ordenar por días hábiles acumulados en el año (menor carga primero)
        usort($libres, fn($a, $b) => ($diasAcum[$a['juez_id']] ?? 0) <=> ($diasAcum[$b['juez_id']] ?? 0));
        return $libres;
    };

    // RN9: partes superpuestas con detalle (nombre, CUIJ, fechas del debate conflictivo)
    // Detección usa período completo [debate_desde..fecha_fin_bloqueo] igual que verificar_superposicion
    $evalPartes = function(array $f) use ($agends, $litIds, $litByAA, $cuijByAA, $litNames): array {
        if (!$litIds) return [];
        $superpuestas = [];
        foreach ($agends as $ag) {
            if ($ag['debate_desde'] > $f['fecha_fin_bloqueo'] || $ag['fecha_fin_bloqueo'] < $f['debate_desde']) continue;
            $agHasta = $ag['debate_hasta'] ?: $ag['fecha_fallo'];
            $confl = array_intersect($litIds, $litByAA[(int)$ag['aa_id']] ?? []);
            foreach ($confl as $lid) {
                if (!isset($superpuestas[$lid])) {
                    $superpuestas[$lid] = [
                        'litigante_id' => $lid,
                        'nombre'       => $litNames[$lid] ?? $lid,
                        'cuij'         => $cuijByAA[(int)$ag['aa_id']] ?? '—',
                        'debate_desde' => $ag['debate_desde'],
                        'debate_hasta' => $agHasta,
                    ];
                }
            }
        }
        return array_values($superpuestas);
    };

    // Construir objeto opción
    $buildOpcion = function(string $tipo, array $f, array $libres, array $superp) use ($juecesNec, $coordinadorId): array {
        // RN12: en pluripersonal, mover el Coordinador Rosario al final para que no quede de Presidente
        if ($juecesNec === 3 && $coordinadorId) {
            $coordIdx = null;
            foreach ($libres as $i => $j) {
                if ($j['juez_id'] === $coordinadorId) { $coordIdx = $i; break; }
            }
            if ($coordIdx !== null && $coordIdx === 0 && count($libres) > 1) {
                $coord = array_splice($libres, $coordIdx, 1);
                $libres = array_merge($libres, $coord);
            }
        }
        $sugeridos = array_slice($libres, 0, $juecesNec);
        $dfd  = (new DateTime($f['debate_desde']))->format('d/m/Y');
        $dfb  = (new DateTime($f['fecha_fin_bloqueo']))->format('d/m/Y');
        $desc = count($superp) === 0
            ? 'Partes sin superposición'
            : count($superp) . ' parte(s) con superposición de debate';
        return [
            'tipo'                => $tipo,
            'fecha'               => $f['debate_desde'],
            'label'               => "$dfd — bloqueo hasta $dfb",
            'desc'                => $desc . ' · ' . count($libres) . ' juez/jueces libres',
            'jueces'              => array_column($sugeridos, 'nombre'),
            'juez_ids'            => array_column($sugeridos, 'juez_id'),
            'litc'                => count($superp),
            'partes_superpuestas' => $superp,
        ];
    };

    // ── Fecha mínima: hoy + 10 días corridos, primer día hábil (RN10) ────────────
    $minDate = new DateTime($today);
    $minDate->modify('+10 days');
    while (!$esHabil($minDate->format('Y-m-d'))) $minDate->modify('+1 day');
    $maxDate = new DateTime($horizon);

    // ── Fase 1: FechaA — primer fecha con tribunal disponible ────────────────────
    $fechaA  = null;
    $libresA = [];
    $d = clone $minDate;
    for (; $d <= $maxDate; $d->modify('+1 day')) {
        $ds = $d->format('Y-m-d');
        if (!$esHabil($ds)) continue;
        $f      = $calcFechas($ds);
        $libres = $evalTribunal($f);
        if (count($libres) >= $juecesNec) {
            $fechaA  = $f;
            $libresA = $libres;
            $d->modify('+1 day');
            break;
        }
    }

    if ($fechaA === null) {
        jsonErr('No hay tribunal disponible en los próximos 6 meses.');
    }

    // ── Fase 2: evaluar partes en FechaA ─────────────────────────────────────────
    $superpA = $evalPartes($fechaA);

    if (empty($superpA)) {
        // FechaA = FechaB: solo una opción, sin conflicto de partes
        echo json_encode(['ok' => true, 'opciones' => [$buildOpcion('fechaA', $fechaA, $libresA, [])]]);
        exit;
    }

    // ── Fase 3: FechaB — primer fecha con tribunal + partes sin superposición ─────
    $fechaB  = null;
    $libresB = [];
    for (; $d <= $maxDate; $d->modify('+1 day')) {
        $ds = $d->format('Y-m-d');
        if (!$esHabil($ds)) continue;
        $f      = $calcFechas($ds);
        $libres = $evalTribunal($f);
        if (count($libres) >= $juecesNec && empty($evalPartes($f))) {
            $fechaB  = $f;
            $libresB = $libres;
            break;
        }
    }

    $opA = $buildOpcion('fechaA', $fechaA, $libresA, $superpA);

    if ($fechaB === null) {
        echo json_encode([
            'ok'      => true,
            'opciones' => [$opA],
            'alerta'  => 'No se encontró una fecha con tribunal disponible y partes sin superposición dentro de los 6 meses siguientes.',
        ]);
        exit;
    }

    echo json_encode(['ok' => true, 'opciones' => [$opA, $buildOpcion('fechaB', $fechaB, $libresB, [])]]);

} catch (Throwable $e) {
    jsonErr('Error interno: ' . $e->getMessage());
}
