<?php
include('conexion.php');
include_once('nomina_helpers.php');
include_once('nomina_vacaciones_master_helpers.php');
if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }
if (!isset($_SESSION['usuario'])) { header('Location: login.php'); exit; }

nomina_vac_v8_ensure_schema($conexion);
if (function_exists('nomina_ensure_cargos_schema')) { nomina_ensure_cargos_schema($conexion); }
$bcvInfo = function_exists('nomina_bcv_auto_refresh') ? nomina_bcv_auto_refresh($conexion, isset($_GET['refresh_bcv']) && (int)$_GET['refresh_bcv'] === 1) : ['latest'=>null,'message'=>''];
$bcvLatest = $bcvInfo['latest'] ?? null;
$fechaCorte = nomina_vac_v8_iso($_REQUEST['fecha_corte'] ?? date('Y-m-d'));
if ($fechaCorte === '') { $fechaCorte = date('Y-m-d'); }
$tasaRef = nomina_vac_v8_decimal($_REQUEST['tasa_bcv_ref'] ?? ($bcvLatest['rate_value'] ?? 1), 1);
if ($tasaRef <= 0) { $tasaRef = 1; }
$periodoSync = (int)($_REQUEST['periodo_sync'] ?? 0);
$selectedPersonaId = (int)($_REQUEST['persona_id'] ?? 0);

$messages = [];
function vac_v8_flash($type, $msg) { $_SESSION['vac_v8_flash'] = ['type'=>$type,'message'=>$msg]; }
function vac_v8_get_flash() { $f = $_SESSION['vac_v8_flash'] ?? null; unset($_SESSION['vac_v8_flash']); return $f; }

$periodos = nomina_vac_v8_fetch_periods($conexion);
$people = nomina_vac_v8_fetch_people($conexion);
$summary = nomina_vac_v8_summary($conexion);
$invalidPeople = nomina_vac_v8_invalid_people($people, $fechaCorte);

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $action = $_POST['accion'] ?? '';
    $personaId = (int)($_POST['persona_id'] ?? 0);
    $persona = nomina_vac_v8_person_by_id($people, $personaId);
    if (!$persona) {
        vac_v8_flash('error', 'Selecciona un trabajador válido.');
        header('Location: nomina_vacaciones.php?fecha_corte='.urlencode($fechaCorte).'&tasa_bcv_ref='.urlencode((string)$tasaRef)); exit;
    }
    if (!nomina_vac_v8_valid_date($persona['fecha_ingreso'] ?? '')) {
        vac_v8_flash('error', 'No se puede registrar vacaciones: el trabajador no tiene fecha de ingreso válida.');
        header('Location: nomina_vacaciones.php?fecha_corte='.urlencode($fechaCorte).'&tasa_bcv_ref='.urlencode((string)$tasaRef).'&persona_id='.$personaId); exit;
    }
    $fechaDocumento = nomina_vac_v8_iso($_POST['fecha_documento'] ?? date('Y-m-d'));
    if ($fechaDocumento === '') { $fechaDocumento = date('Y-m-d'); }
    $obs = trim((string)($_POST['observacion'] ?? ''));
    $soporte = trim((string)($_POST['soporte_referencia'] ?? ''));
    $periodoPost = (int)($_POST['periodo_sync'] ?? 0);
    $bal = nomina_vac_v8_balance($conexion, $persona, $fechaCorte, $tasaRef, $summary[$personaId] ?? []);
    $salary = $bal['salary'];

    if ($action === 'copiar_novedades') {
        $eventId = (int)($_POST['evento_id'] ?? 0);
        mysqli_begin_transaction($conexion);
        $copy = nomina_vac_v8_copy_event_to_novedades($conexion, $eventId, $periodoPost);
        if ($copy['ok']) { mysqli_commit($conexion); vac_v8_flash('success', $copy['message']); }
        else { mysqli_rollback($conexion); vac_v8_flash('error', 'No se pudo copiar a novedades: '.$copy['message']); }
    } elseif ($action === 'registrar') {
        $tipo = strtoupper((string)($_POST['tipo'] ?? 'DISFRUTE'));
        if (!in_array($tipo, ['DISFRUTE','BONO_SOLO','COLECTIVA','FRACCIONADA'], true)) { $tipo = 'DISFRUTE'; }
        $fechaInicio = nomina_vac_v8_iso($_POST['fecha_inicio'] ?? '');
        $fechaFin = nomina_vac_v8_iso($_POST['fecha_fin'] ?? '');
        $diasDisfrute = nomina_vac_v8_decimal($_POST['dias_disfrute'] ?? 0);
        $diasBono = nomina_vac_v8_decimal($_POST['dias_bono'] ?? 0);
        $ciclo = (int)($_POST['ciclo_anual'] ?? $bal['current_cycle']);
        $sugerenciaFin = null;
        if ($tipo !== 'BONO_SOLO' && $fechaInicio !== '' && $diasDisfrute > 0 && function_exists('nomina_vac_v8_suggest_end_date')) {
            $sugerenciaFin = nomina_vac_v8_suggest_end_date($conexion, $persona, $fechaInicio, $diasDisfrute);
            // Blindaje amable: si el operador no llenó fecha fin, se completa con la sugerencia calculada
            // por calendario laboral/turno. Si la llenó manualmente, se respeta.
            if ($fechaFin === '' && !empty($sugerenciaFin['fecha_fin'])) {
                $fechaFin = $sugerenciaFin['fecha_fin'];
            }
        }
        $errors = [];
        if ($bal['completed_years'] < 1) { $errors[] = 'El trabajador aún no cumple un año de servicio para vacaciones legales ordinarias.'; }
        if ($ciclo <= 0 || $ciclo > $bal['completed_years']) { $errors[] = 'Ciclo anual inválido para la antigüedad del trabajador.'; }
        if ($diasDisfrute < 0 || $diasBono < 0) { $errors[] = 'Los días no pueden ser negativos.'; }
        if ($diasDisfrute <= 0 && $diasBono <= 0) { $errors[] = 'Indica días de disfrute o días de bono vacacional.'; }
        if ($diasDisfrute > $bal['pending_days'] || $diasBono > $bal['pending_bonus_days']) { $errors[] = 'Los días exceden el saldo legal pendiente total.'; }
        if ($obs === '' || mb_strlen($obs) < 12) { $errors[] = 'La observación es obligatoria y debe indicar motivo, fecha/soporte o autorización.'; }
        if ($soporte === '' || mb_strlen($soporte) < 12) { $errors[] = 'El soporte/referencia es obligatorio y debe ser formal. Ej: Solicitud firmada por RRHH y trabajador / expediente / autorización.'; }
        if ($tipo !== 'BONO_SOLO' && ($fechaInicio === '' || $fechaFin === '')) { $errors[] = 'Para disfrute/colectiva/fraccionada indica fecha inicio y fecha fin.'; }
        if ($fechaInicio !== '' && $fechaFin !== '' && $fechaFin < $fechaInicio) { $errors[] = 'La fecha fin no puede ser menor que fecha inicio.'; }
        if ($errors) {
            vac_v8_flash('error', implode(' ', $errors));
        } else {
            $montoDisfrute = round($diasDisfrute * (float)$salary['salario_diario_bs'], 2);
            $montoBono = round($diasBono * (float)$salary['salario_diario_bs'], 2);
            $snapshot = [
                'version' => 'V8_VACACIONES_COMPLETAS',
                'persona' => ['id'=>$personaId,'nombre'=>$persona['nombre'] ?? '', 'apellido'=>$persona['apellido'] ?? '', 'cedula'=>$persona['cedula'] ?? '', 'fecha_ingreso'=>$persona['fecha_ingreso'] ?? ''],
                'fecha_corte' => $fechaCorte,
                'balance' => $bal,
                'salario' => $salary,
                'sugerencia_calendario_fin' => $sugerenciaFin,
            ];
            mysqli_begin_transaction($conexion);
            $ins = nomina_vac_v8_insert_event($conexion, [
                'persona_id'=>$personaId,
                'fecha_documento'=>$fechaDocumento,
                'fecha_inicio'=>$fechaInicio,
                'fecha_fin'=>$fechaFin,
                'tipo'=>$tipo,
                'ciclo_anual'=>$ciclo,
                'es_historico'=>0,
                'dias_disfrute'=>$diasDisfrute,
                'dias_bono'=>$diasBono,
                'monto_disfrute_bs'=>$montoDisfrute,
                'monto_bono_bs'=>$montoBono,
                'periodo_id'=>$periodoPost,
                'observacion'=>$obs,
                'fuente_salario'=>$salary['fuente'],
                'salario_mensual_bs'=>$salary['salario_mensual_bs'],
                'salario_diario_bs'=>$salary['salario_diario_bs'],
                'tasa_bcv_usada'=>$salary['tasa_bcv_usada'],
                'salario_moneda'=>$salary['salario_moneda'],
                'salario_monto_original'=>$salary['salario_monto_original'],
                'bono_extra_usd_mensual'=>$salary['bono_extra_usd_mensual'],
                'origen_registro'=>'V8_VACACIONES_COMPLETAS',
                'soporte_referencia'=>$soporte,
                'snapshot_json'=>$snapshot,
            ]);
            $ok = $ins['ok']; $msg = $ins['message'];
            if ($ok && $periodoPost > 0) {
                $sync = nomina_vac_v8_sync_to_novedades($conexion, $periodoPost, $personaId, $montoDisfrute + $montoBono, 'Vacaciones legales v8: '.$obs);
                if (!$sync['ok']) { $ok = false; $msg = $sync['message']; }
            }
            if ($ok) { mysqli_commit($conexion); vac_v8_flash('success', 'Vacaciones registradas correctamente. Monto Bs '.number_format($montoDisfrute+$montoBono, 2, ',', '.').($periodoPost > 0 ? ' · Copiado a novedades del período seleccionado.' : '')); }
            else { mysqli_rollback($conexion); vac_v8_flash('error', 'No se pudo registrar vacaciones: '.$msg); }
        }
    } elseif ($action === 'historico') {
        $diasDisfrute = nomina_vac_v8_decimal($_POST['hist_dias_disfrute'] ?? 0);
        $diasBono = nomina_vac_v8_decimal($_POST['hist_dias_bono'] ?? 0);
        if (($diasDisfrute <= 0 && $diasBono <= 0) || $obs === '' || $soporte === '') {
            vac_v8_flash('error', 'Para ajuste histórico indica días, observación y soporte formal.');
        } else {
            $ins = nomina_vac_v8_insert_event($conexion, [
                'persona_id'=>$personaId,'fecha_documento'=>$fechaDocumento,'fecha_inicio'=>null,'fecha_fin'=>null,
                'tipo'=>'AJUSTE_HISTORICO','ciclo_anual'=>0,'es_historico'=>1,'dias_disfrute'=>$diasDisfrute,'dias_bono'=>$diasBono,
                'monto_disfrute_bs'=>0,'monto_bono_bs'=>0,'periodo_id'=>0,'observacion'=>$obs,
                'fuente_salario'=>'AJUSTE_HISTORICO','salario_mensual_bs'=>0,'salario_diario_bs'=>0,'tasa_bcv_usada'=>0,
                'salario_moneda'=>'VES','salario_monto_original'=>0,'bono_extra_usd_mensual'=>0,'origen_registro'=>'V8_AJUSTE_HISTORICO',
                'soporte_referencia'=>$soporte,'snapshot_json'=>['version'=>'V8_AJUSTE_HISTORICO','fecha_corte'=>$fechaCorte],
            ]);
            vac_v8_flash($ins['ok'] ? 'success' : 'error', $ins['ok'] ? 'Ajuste histórico registrado.' : 'No se pudo registrar ajuste: '.$ins['message']);
        }
    }
    header('Location: nomina_vacaciones.php?fecha_corte='.urlencode($fechaCorte).'&tasa_bcv_ref='.urlencode((string)$tasaRef).'&periodo_sync='.(int)$periodoPost.'&persona_id='.$personaId); exit;
}

$flash = vac_v8_get_flash();
$rows = [];
foreach ($people as $p) {
    if (!nomina_vac_v8_valid_date($p['fecha_ingreso'] ?? '')) { continue; }
    $bal = nomina_vac_v8_balance($conexion, $p, $fechaCorte, $tasaRef, $summary[(int)$p['id']] ?? []);
    $rows[] = ['persona'=>$p, 'balance'=>$bal];
}
usort($rows, function($a,$b){ return $b['balance']['pending_total_bs'] <=> $a['balance']['pending_total_bs']; });
$selectedPersona = $selectedPersonaId ? nomina_vac_v8_person_by_id($people, $selectedPersonaId) : null;
$selectedBalance = $selectedPersona && nomina_vac_v8_valid_date($selectedPersona['fecha_ingreso'] ?? '') ? nomina_vac_v8_balance($conexion, $selectedPersona, $fechaCorte, $tasaRef, $summary[$selectedPersonaId] ?? []) : null;
$stats = nomina_vac_v8_stats($conexion, $people, $fechaCorte, $tasaRef);
$recentEvents = nomina_vac_v8_recent_events($conexion, 25);
?>
<!doctype html>
<html lang="es"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Vacaciones completas v8.3</title>
<style>
body{font-family:Arial,Helvetica,sans-serif;background:#f3f6fa;color:#14233b;margin:0}.wrap{max-width:1480px;margin:0 auto;padding:24px}.card{background:#fff;border:1px solid #dbe5f1;border-radius:18px;padding:20px;margin-bottom:18px;box-shadow:0 8px 24px rgba(15,23,42,.05)}.top{display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap}.btn{display:inline-block;background:#173f9f;color:#fff;text-decoration:none;border:0;border-radius:13px;padding:11px 16px;font-weight:700;cursor:pointer}.btn.secondary{background:#fff;color:#173f9f;border:1px solid #b7c6e3}.btn.ghost{background:#eef3ff;color:#173f9f}.btn.small{font-size:13px;padding:8px 11px}.muted,.mini{color:#62748b}.mini{font-size:12px}.filters{display:grid;grid-template-columns:1fr 1fr 1fr auto auto;gap:14px}.field label{display:block;font-weight:700;margin-bottom:6px}.field input,.field select,.field textarea{width:100%;box-sizing:border-box;border:1px solid #cbd5e1;border-radius:12px;padding:10px 12px;font-size:15px}.field textarea{min-height:84px}.stats{display:grid;grid-template-columns:repeat(6,1fr);gap:12px}.stat{border:1px solid #dbe5f1;border-radius:14px;padding:14px;background:#fbfdff}.stat .v{font-size:26px;font-weight:800}.flash{border-radius:14px;padding:13px 16px;margin-bottom:14px}.flash.success{background:#ecfdf3;color:#166534;border:1px solid #86efac}.flash.error{background:#fff1f2;color:#991b1b;border:1px solid #fecaca}.warn{background:#fff7ed;border:1px solid #fed7aa;color:#92400e;border-radius:14px;padding:14px}.table-wrap{overflow:auto}.table{width:100%;border-collapse:separate;border-spacing:0}.table th,.table td{padding:11px 10px;border-bottom:1px solid #e5edf5;vertical-align:top;text-align:left}.table th{background:#f8fafc;font-size:13px;color:#334e68;position:sticky;top:0}.grid{display:grid;grid-template-columns:1.6fr 1fr;gap:18px}.subcard{border:1px solid #dbe5f1;border-radius:14px;padding:14px;background:#fbfdff}.badge{display:inline-block;border-radius:999px;background:#eef2ff;color:#1e3a8a;font-weight:700;font-size:12px;padding:4px 9px}.good{color:#166534}.bad{color:#991b1b}.tot{font-weight:800}@media(max-width:1100px){.filters,.stats,.grid{grid-template-columns:1fr}}
</style></head><body><div class="wrap">
<div class="card top"><div><h1 style="margin:0 0 4px">Vacaciones completas v8.3</h1><div class="muted">Control legal de vacaciones, bono vacacional, saldos pendientes, historial, soporte formal y copia opcional a novedades del período.</div></div><div><a class="btn secondary" href="nomina_vacaciones_auditoria.php">Auditoría vacaciones</a> <a class="btn secondary" href="novedades_periodo.php">Novedades</a> <a class="btn secondary" href="index.php">Dashboard</a></div></div>
<?php if ($flash): ?><div class="flash <?php echo h($flash['type']); ?>"><?php echo h($flash['message']); ?></div><?php endif; ?>
<div class="card"><form method="get" class="filters"><div class="field"><label>Fecha de corte</label><input type="date" name="fecha_corte" value="<?php echo h($fechaCorte); ?>"></div><div class="field"><label>Tasa BCV referencia</label><input type="text" name="tasa_bcv_ref" value="<?php echo h(number_format($tasaRef,4,'.','')); ?>"><div class="mini">Usada solo si falta historial salarial.</div></div><div class="field"><label>Período para copiar pago a novedades</label><select name="periodo_sync"><option value="0">-- No copiar --</option><?php foreach($periodos as $per): ?><option value="<?php echo (int)$per['id']; ?>" <?php echo $periodoSync===(int)$per['id']?'selected':''; ?>><?php echo h($per['codigo'].' · '.$per['estado']); ?></option><?php endforeach; ?></select></div><div class="field"><label>&nbsp;</label><button class="btn" type="submit">Actualizar</button></div><div class="field"><label>&nbsp;</label><a class="btn ghost" href="nomina_vacaciones.php?fecha_corte=<?php echo h(urlencode($fechaCorte)); ?>&periodo_sync=<?php echo (int)$periodoSync; ?>&refresh_bcv=1">Actualizar BCV</a></div></form><div class="mini" style="margin-top:12px">BCV disponible: <b><?php echo h($bcvLatest ? number_format((float)$bcvLatest['rate_value'],4,',','.') : number_format($tasaRef,4,',','.')); ?></b><?php echo $bcvLatest ? ' · fecha '.$bcvLatest['rate_date'] : ''; ?></div></div>
<div class="card stats"><div class="stat"><div class="v"><?php echo (int)$stats['trabajadores']; ?></div><div>Trabajadores activos</div></div><div class="stat"><div class="v bad"><?php echo (int)$stats['invalidos']; ?></div><div>Sin fecha ingreso válida</div></div><div class="stat"><div class="v"><?php echo (int)$stats['pendientes_trabajadores']; ?></div><div>Con saldo pendiente</div></div><div class="stat"><div class="v"><?php echo number_format($stats['pendientes_dias'],2,',','.'); ?></div><div>Días disfrute pendientes</div></div><div class="stat"><div class="v"><?php echo number_format($stats['pendientes_bono'],2,',','.'); ?></div><div>Días bono pendientes</div></div><div class="stat"><div class="v good"><?php echo (int)$stats['fuente_historial']; ?></div><div>Con historial salarial</div></div></div>
<?php if ($invalidPeople): ?><div class="card warn"><h2 style="margin-top:0">Bloqueo auditor: trabajadores activos sin fecha de ingreso válida</h2><p>Vacaciones no se calculan para estos trabajadores hasta corregir la ficha. La fecha de ingreso define antigüedad, ciclo, días legales y bono vacacional.</p><div class="table-wrap"><table class="table"><thead><tr><th>Trabajador</th><th>Cédula</th><th>Cargo</th><th>Acción</th></tr></thead><tbody><?php foreach($invalidPeople as $p): ?><tr><td><b><?php echo h(trim(($p['apellido']??'').' '.($p['nombre']??''))); ?></b></td><td><?php echo h($p['cedula']??''); ?></td><td><?php echo h($p['cargo']??''); ?></td><td><a class="btn small secondary" href="editar.php?id=<?php echo (int)$p['id']; ?>">Corregir ficha</a></td></tr><?php endforeach; ?></tbody></table></div></div><?php endif; ?>
<div class="grid"><div class="card"><h2 style="margin-top:0">Saldo legal por trabajador</h2><div class="table-wrap"><table class="table"><thead><tr><th>Trabajador</th><th>Ingreso</th><th>Años</th><th>Fuente salario</th><th>Salario diario Bs</th><th>Días pend.</th><th>Bono pend.</th><th>Saldo Bs</th><th></th></tr></thead><tbody><?php foreach($rows as $r): $p=$r['persona']; $b=$r['balance']; ?><tr><td><b><?php echo h(trim(($p['apellido']??'').' '.($p['nombre']??''))); ?></b><div class="mini">CI: <?php echo h($p['cedula']??''); ?> · <?php echo h($p['cargo']??''); ?></div></td><td><?php echo h($p['fecha_ingreso']??''); ?></td><td><?php echo (int)$b['completed_years']; ?></td><td><span class="badge"><?php echo h($b['salary']['fuente']); ?></span></td><td><?php echo number_format($b['daily_bs'],2,',','.'); ?></td><td><?php echo number_format($b['pending_days'],2,',','.'); ?></td><td><?php echo number_format($b['pending_bonus_days'],2,',','.'); ?></td><td class="tot"><?php echo number_format($b['pending_total_bs'],2,',','.'); ?></td><td><a class="btn small secondary" href="nomina_vacaciones.php?fecha_corte=<?php echo h(urlencode($fechaCorte)); ?>&tasa_bcv_ref=<?php echo h(urlencode((string)$tasaRef)); ?>&periodo_sync=<?php echo (int)$periodoSync; ?>&persona_id=<?php echo (int)$p['id']; ?>">Preparar</a></td></tr><?php endforeach; ?></tbody></table></div></div>
<div class="card"><h2 style="margin-top:0">Registrar / controlar vacaciones</h2><?php if(!$selectedPersona || !$selectedBalance): ?><div class="subcard">Selecciona un trabajador de la tabla para preparar disfrute, bono o ajuste histórico.</div><?php else: $p=$selectedPersona; $b=$selectedBalance;
    $vacStartBase = nomina_vac_v8_valid_date($fechaCorte) ? $fechaCorte : date('Y-m-d');
    $vacEndBaseObj = new DateTime($vacStartBase);
    $vacEndBaseObj->modify('+730 days');
    $vacHolidayMap = function_exists('nomina_vac_v8_calendar_holidays') ? nomina_vac_v8_calendar_holidays($conexion, $vacStartBase, $vacEndBaseObj->format('Y-m-d')) : [];
    $vacRestWeekdays = function_exists('nomina_vac_v8_rest_weekdays') ? nomina_vac_v8_rest_weekdays($p) : [0];
?><div class="subcard"><b><?php echo h(trim(($p['apellido']??'').' '.($p['nombre']??''))); ?></b><div class="mini">Ingreso: <?php echo h($p['fecha_ingreso']); ?> · Ciclo actual: <?php echo (int)$b['current_cycle']; ?> · Fuente: <?php echo h($b['salary']['fuente']); ?></div><div class="mini">Pendiente ciclo: <?php echo number_format($b['pending_cycle_days'],2,',','.'); ?> días disfrute / <?php echo number_format($b['pending_cycle_bonus_days'],2,',','.'); ?> bono.</div><div class="mini"><b>v8.2:</b> al colocar fecha de inicio, el sistema puede sugerir fecha fin excluyendo domingos, descansos de turno y feriados del calendario laboral. La fecha sigue siendo editable por RRHH.</div></div><form method="post" style="margin-top:12px" id="vacForm"><input type="hidden" name="accion" value="registrar"><input type="hidden" name="persona_id" value="<?php echo (int)$p['id']; ?>"><input type="hidden" name="periodo_sync" value="<?php echo (int)$periodoSync; ?>"><div class="field"><label>Tipo</label><select name="tipo"><option value="DISFRUTE">Disfrute + bono</option><option value="BONO_SOLO">Solo bono vacacional</option><option value="FRACCIONADA">Vacaciones fraccionadas</option><option value="COLECTIVA">Vacaciones colectivas</option></select></div><div class="field"><label>Ciclo anual</label><input type="number" name="ciclo_anual" value="<?php echo (int)$b['current_cycle']; ?>"></div><div class="field"><label>Fecha documento</label><input type="date" name="fecha_documento" value="<?php echo h($fechaCorte); ?>"></div><div class="field"><label>Fecha inicio disfrute</label><input type="date" name="fecha_inicio" id="vac_fecha_inicio"></div><div class="field"><label>Fecha fin disfrute</label><input type="date" name="fecha_fin" id="vac_fecha_fin"><div class="mini">Sugerida automáticamente por calendario si está activa la opción inferior. Puedes ajustarla manualmente si RRHH lo autoriza.</div></div><div class="field"><label>Días disfrute a registrar</label><input type="text" name="dias_disfrute" id="vac_dias_disfrute" value="<?php echo h(number_format($b['pending_cycle_days'],2,'.','')); ?>"></div><div class="subcard" style="margin:8px 0"><label style="display:flex;gap:8px;align-items:center"><input type="checkbox" id="vac_auto_fin" checked> Calcular fecha fin automáticamente por calendario laboral/turno</label><div class="mini" id="vac_fecha_fin_auditoria">Coloca fecha de inicio para ver la sugerencia.</div></div><div class="field"><label>Días bono vacacional</label><input type="text" name="dias_bono" value="<?php echo h(number_format($b['pending_cycle_bonus_days'],2,'.','')); ?>"></div><div class="field"><label>Soporte/referencia</label><input type="text" name="soporte_referencia" placeholder="Ej: Solicitud firmada por RRHH y trabajador. RRHH-2026-001"></div><div class="field"><label>Observación obligatoria</label><textarea name="observacion" placeholder="Ej: Vacaciones ciclo <?php echo (int)$b['current_cycle']; ?> autorizadas por RRHH. Fechas verificadas y soporte firmado por trabajador."></textarea></div><button class="btn" type="submit">Registrar vacaciones</button></form>
<script>
(function(){
  const holidays = <?php echo json_encode($vacHolidayMap, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?> || {};
  const restWeekdays = <?php echo json_encode($vacRestWeekdays, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?> || [0];
  const startEl = document.getElementById('vac_fecha_inicio');
  const endEl = document.getElementById('vac_fecha_fin');
  const daysEl = document.getElementById('vac_dias_disfrute');
  const autoEl = document.getElementById('vac_auto_fin');
  const auditEl = document.getElementById('vac_fecha_fin_auditoria');
  let manualEndTouched = false;

  function pad(n){ return String(n).padStart(2,'0'); }
  function ymd(d){ return d.getFullYear() + '-' + pad(d.getMonth()+1) + '-' + pad(d.getDate()); }
  function addDays(d, n){ const x = new Date(d.getTime()); x.setDate(x.getDate()+n); return x; }
  function parseNum(v){
    v = String(v || '').replace(',', '.').trim();
    const n = parseFloat(v);
    return isNaN(n) ? 0 : n;
  }
  function isRestDow(dow){ return restWeekdays.map(Number).indexOf(Number(dow)) !== -1 || Number(dow) === 0; }

  function calcEnd(){
    if (!startEl || !endEl || !daysEl || !auditEl) return;
    const startVal = startEl.value;
    const days = Math.ceil(parseNum(daysEl.value));
    if (!startVal || days <= 0) {
      auditEl.textContent = 'Coloca fecha de inicio y días de disfrute para ver la sugerencia.';
      return;
    }
    let d = new Date(startVal + 'T00:00:00');
    if (isNaN(d.getTime())) return;
    let counted = 0, excluded = 0, shown = [], limit = 0, last = '';
    while (limit < 800) {
      const key = ymd(d);
      const dow = d.getDay(); // 0 domingo
      let reason = '';
      if (isRestDow(dow)) reason = (dow === 0) ? 'domingo/feriado laboral LOTTT' : 'descanso de turno';
      if (holidays[key]) reason = holidays[key];
      if (reason) {
        excluded++;
        if (shown.length < 6) shown.push(key + ' no cuenta: ' + reason);
      } else {
        counted++;
        last = key;
        if (counted >= days) break;
      }
      d = addDays(d, 1);
      limit++;
    }
    if (last) {
      if (autoEl && autoEl.checked && !manualEndTouched) endEl.value = last;
      let msg = 'Sugerencia: fecha fin ' + last + '. Cuenta ' + counted + ' días hábiles de disfrute y excluye ' + excluded + ' día(s) por descansos/feriados.';
      if (shown.length) msg += ' Ejemplos: ' + shown.join(' | ');
      auditEl.textContent = msg;
    }
  }

  if (endEl) {
    endEl.addEventListener('input', function(){ manualEndTouched = true; });
  }
  if (autoEl) {
    autoEl.addEventListener('change', function(){
      if (autoEl.checked) { manualEndTouched = false; calcEnd(); }
    });
  }
  ['input','change'].forEach(function(ev){
    if (startEl) startEl.addEventListener(ev, function(){ manualEndTouched = false; calcEnd(); });
    if (daysEl) daysEl.addEventListener(ev, function(){ manualEndTouched = false; calcEnd(); });
  });
  calcEnd();
})();
</script><hr><form method="post"><input type="hidden" name="accion" value="historico"><input type="hidden" name="persona_id" value="<?php echo (int)$p['id']; ?>"><div class="field"><label>Ajuste histórico días disfrute</label><input type="text" name="hist_dias_disfrute" value="0"></div><div class="field"><label>Ajuste histórico días bono</label><input type="text" name="hist_dias_bono" value="0"></div><div class="field"><label>Soporte</label><input type="text" name="soporte_referencia" placeholder="Migración inicial con expediente físico / acta RRHH"></div><div class="field"><label>Observación</label><textarea name="observacion" placeholder="Ajuste histórico por saldos migrados antes de usar el sistema."></textarea></div><button class="btn secondary" type="submit">Registrar ajuste histórico</button></form><?php endif; ?></div></div>
<div class="card"><h2 style="margin-top:0">Últimos eventos</h2><div class="mini" style="margin-bottom:10px">v8.3: si registraste vacaciones sin copiar a novedades, selecciona arriba un período ABIERTO y usa el botón <b>Copiar a novedades</b> en el evento correspondiente.</div><div class="table-wrap"><table class="table"><thead><tr><th>Fecha</th><th>Trabajador</th><th>Tipo</th><th>Ciclo</th><th>Días</th><th>Monto Bs</th><th>Fuente</th><th>Período nómina</th><th>Observación</th><th>Acción</th></tr></thead><tbody><?php foreach($recentEvents as $e): $montoEvento=(float)$e['monto_disfrute_bs']+(float)$e['monto_bono_bs']; $eventoPeriodo=(int)($e['periodo_id'] ?? 0); ?><tr><td><?php echo h($e['fecha_documento']); ?></td><td><?php echo h(trim(($e['apellido']??'').' '.($e['nombre']??''))); ?><div class="mini"><?php echo h($e['cedula']??''); ?></div></td><td><?php echo h($e['tipo']); ?></td><td><?php echo h($e['ciclo_anual']); ?></td><td><?php echo number_format((float)$e['dias_disfrute'],2,',','.'); ?> / bono <?php echo number_format((float)$e['dias_bono'],2,',','.'); ?></td><td><?php echo number_format($montoEvento,2,',','.'); ?></td><td><span class="badge"><?php echo h($e['fuente_salario'] ?? ''); ?></span></td><td><?php if($eventoPeriodo>0): ?><span class="badge"><?php echo h(($e['periodo_codigo'] ?? ('ID '.$eventoPeriodo)).' · '.($e['periodo_estado'] ?? '')); ?></span><?php else: ?><span class="mini">No copiado</span><?php endif; ?></td><td><?php echo h($e['observacion'] ?? ''); ?></td><td><?php if($eventoPeriodo>0): ?><span class="mini">Copiado</span><?php elseif($montoEvento<=0): ?><span class="mini">Sin monto</span><?php elseif($periodoSync<=0): ?><span class="mini">Selecciona período arriba</span><?php else: ?><form method="post" onsubmit="return confirm('¿Copiar este pago de vacaciones a novedades del período seleccionado?');"><input type="hidden" name="accion" value="copiar_novedades"><input type="hidden" name="evento_id" value="<?php echo (int)$e['id']; ?>"><input type="hidden" name="persona_id" value="<?php echo (int)$e['persona_id']; ?>"><input type="hidden" name="periodo_sync" value="<?php echo (int)$periodoSync; ?>"><input type="hidden" name="fecha_corte" value="<?php echo h($fechaCorte); ?>"><input type="hidden" name="tasa_bcv_ref" value="<?php echo h((string)$tasaRef); ?>"><button type="submit" class="btn small">Copiar a novedades</button></form><?php endif; ?></td></tr><?php endforeach; ?></tbody></table></div></div>
</div></body></html>
