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

$schemaHoras = nomina_ensure_novedades_horas_schema($conexion);
$schema = nomina_detect_novedades_schema($conexion);
$flash = nomina_flash_get();
$errors = [];
$nominaCompatVersion = 'v6.9 · 2026-05-15 · retardos en horas + soporte auditor';

/**
 * Guardado compatible total MariaDB/MySQL.
 *
 * IMPORTANTE: No usamos UPSERT automático.
 * En el servidor MariaDB del hosting esa sintaxis venia fallando por la variante
 * la variante con alias de inserción y algunas versiones generan incompatibilidades. Para blindarlo, hacemos
 * SELECT -> UPDATE o INSERT de forma explicita dentro de la transaccion.
 */
function nomina_novedades_qcol($column) {
    return '`' . str_replace('`', '``', (string)$column) . '`';
}

function nomina_novedades_qval($conexion, $value, $numeric = false) {
    if ($value === null) { return 'NULL'; }
    if ($numeric) { return (string)(float)$value; }
    return "'" . mysqli_real_escape_string($conexion, (string)$value) . "'";
}

function nomina_novedades_row_exists($conexion, $table, $periodoId, $personaId, $conceptoId = null) {
    $tableSafe = nomina_novedades_qcol($table);
    $where = 'periodo_id = ' . (int)$periodoId . ' AND persona_id = ' . (int)$personaId;
    if ($conceptoId !== null) { $where .= ' AND concepto_id = ' . (int)$conceptoId; }
    $res = mysqli_query($conexion, "SELECT id FROM {$tableSafe} WHERE {$where} LIMIT 1");
    return ($res && mysqli_num_rows($res) > 0);
}

function nomina_novedades_save_payload($conexion, $table, array $keys, array $payload, array $numericColumns = []) {
    $tableSafe = nomina_novedades_qcol($table);
    $keyParts = [];
    foreach ($keys as $k => $v) {
        $keyParts[] = nomina_novedades_qcol($k) . ' = ' . nomina_novedades_qval($conexion, $v, true);
    }
    $where = implode(' AND ', $keyParts);

    $exists = nomina_novedades_row_exists(
        $conexion,
        $table,
        (int)($keys['periodo_id'] ?? 0),
        (int)($keys['persona_id'] ?? 0),
        array_key_exists('concepto_id', $keys) ? (int)$keys['concepto_id'] : null
    );

    if ($exists) {
        $sets = [];
        foreach ($payload as $column => $value) {
            if (array_key_exists($column, $keys)) { continue; }
            $sets[] = nomina_novedades_qcol($column) . ' = ' . nomina_novedades_qval($conexion, $value, in_array($column, $numericColumns, true));
        }
        if (!$sets) { return true; }
        $sql = "UPDATE {$tableSafe} SET " . implode(', ', $sets) . " WHERE {$where} LIMIT 1";
    } else {
        $fields = [];
        $values = [];
        foreach ($payload as $column => $value) {
            $fields[] = nomina_novedades_qcol($column);
            $values[] = nomina_novedades_qval($conexion, $value, in_array($column, $numericColumns, true));
        }
        $sql = "INSERT INTO {$tableSafe} (" . implode(', ', $fields) . ") VALUES (" . implode(', ', $values) . ")";
    }

    if (!mysqli_query($conexion, $sql)) {
        throw new Exception(mysqli_error($conexion) . ' | SQL: ' . $sql);
    }
    return true;
}

$useInsertAliasNovedades = false; // variable heredada; ya no se usa para guardar.
$postDraftNovedades = [];
$postDraftManualAssignments = [];

$periodos = nomina_get_periodos_with_stats($conexion);
$periodoId = isset($_REQUEST['periodo_id']) ? (int)$_REQUEST['periodo_id'] : 0;
if (!$periodoId && $periodos) {
    $periodoId = (int)$periodos[0]['id'];
}
$mode = strtoupper((string)($_REQUEST['mode'] ?? 'SIMPLE'));
if (!in_array($mode, ['SIMPLE','AVANZADO'], true)) {
    $mode = 'SIMPLE';
}

$periodo = $periodoId ? nomina_get_periodo($conexion, $periodoId) : null;
if (!$periodo && $periodos) {
    $periodo = $periodos[0];
    $periodoId = (int)$periodo['id'];
}

$manualConcepts = nomina_get_manual_fixed_concepts($conexion, true);

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['persona_id']) && is_array($_POST['persona_id'])) {
    foreach ($_POST['persona_id'] as $pidDraftRaw) {
        $pidDraft = (int)$pidDraftRaw;
        if ($pidDraft <= 0) { continue; }
        $postDraftNovedades[$pidDraft] = [
            'dias_ausencia_periodo' => (string)($_POST['dias_aus_per'][$pidDraft] ?? '0'),
            'horas_retardo_periodo' => (string)($_POST['hrs_ret'][$pidDraft] ?? '0'),
            'he_diurna' => (string)($_POST['he_diurna'][$pidDraft] ?? '0'),
            'he_nocturna' => (string)($_POST['he_nocturna'][$pidDraft] ?? '0'),
            'horas_nocturnas_ordinarias' => (string)($_POST['horas_nocturnas'][$pidDraft] ?? '0'),
            'dias_ausencia_mes' => (string)($_POST['dias_aus_mes'][$pidDraft] ?? ''),
            'bono_manual_bs' => (string)($_POST['bono_manual'][$pidDraft] ?? '0'),
            'otros_descuentos_bs' => (string)($_POST['otros_desc'][$pidDraft] ?? '0'),
            'prestamo_bs' => (string)($_POST['prestamo'][$pidDraft] ?? '0'),
            // v8.4: no asumir 0 cuando el campo vacaciones no viene en el POST (modo simple),
            // porque podría borrar pagos copiados desde vacaciones.
            'pago_vacaciones_bs' => (isset($_POST['vacaciones']) && is_array($_POST['vacaciones']) && array_key_exists($pidDraft, $_POST['vacaciones'])) ? (string)$_POST['vacaciones'][$pidDraft] : null,
            'observaciones' => (string)($_POST['obs'][$pidDraft] ?? ''),
        ];
        if (isset($_POST['extra_manual'][$pidDraft]) && is_array($_POST['extra_manual'][$pidDraft])) {
            foreach ($_POST['extra_manual'][$pidDraft] as $conceptDraftId => $valorDraft) {
                $postDraftManualAssignments[$pidDraft][(int)$conceptDraftId] = ['valor_manual' => (string)$valorDraft];
            }
        }
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['guardar'])) {
    $periodoId = (int)($_POST['periodo_id'] ?? 0);
    $mode = strtoupper((string)($_POST['mode'] ?? 'SIMPLE'));
    $periodo = $periodoId ? nomina_get_periodo($conexion, $periodoId) : null;

    if (!$periodo) {
        $errors[] = 'Debes seleccionar un período válido.';
    }
    if ($periodo && strtoupper((string)$periodo['estado']) === 'CERRADO') {
        $errors[] = 'El período está cerrado y no admite nuevas novedades.';
    }
    if ($periodo && function_exists('nlm_periodo_has_locked_corrida') && nlm_periodo_has_locked_corrida($conexion, $periodoId)) {
        $errors[] = 'Este período ya tiene una corrida revisada/aprobada/pagada/cerrada. Las novedades quedan bloqueadas para preservar la trazabilidad.';
    }

    if (!$errors) {
        if ($mode === 'AVANZADO' && $manualConcepts) {
            nomina_ensure_manual_novedades_schema($conexion);
        }
        $personaIds = isset($_POST['persona_id']) && is_array($_POST['persona_id']) ? $_POST['persona_id'] : [];
        $novedadesSensiblesSinSoporte = [];
        foreach ($personaIds as $pidRawValidacion) {
            $pidVal = (int)$pidRawValidacion;
            if ($pidVal <= 0) { continue; }
            $obsVal = trim((string)($_POST['obs'][$pidVal] ?? ''));
            $sensibles = [];
            $valoresSensibles = [
                'ausencias' => nomina_normalize_decimal($_POST['dias_aus_per'][$pidVal] ?? 0),
                'retardos' => nomina_normalize_decimal($_POST['hrs_ret'][$pidVal] ?? 0),
                'HE diurnas' => nomina_normalize_decimal($_POST['he_diurna'][$pidVal] ?? 0),
                'HE nocturnas' => nomina_normalize_decimal($_POST['he_nocturna'][$pidVal] ?? 0),
                'horas nocturnas ordinarias' => nomina_normalize_decimal($_POST['horas_nocturnas'][$pidVal] ?? 0),
                'bonificación manual' => nomina_normalize_decimal($_POST['bono_manual'][$pidVal] ?? 0),
                'descuento manual' => nomina_normalize_decimal($_POST['otros_desc'][$pidVal] ?? 0),
                'préstamo' => nomina_normalize_decimal($_POST['prestamo'][$pidVal] ?? 0),
                'vacaciones manuales' => (isset($_POST['vacaciones']) && is_array($_POST['vacaciones']) && array_key_exists($pidVal, $_POST['vacaciones'])) ? nomina_normalize_decimal($_POST['vacaciones'][$pidVal] ?? 0) : 0,
            ];
            foreach ($valoresSensibles as $etiqueta => $valorSens) {
                if (abs((float)$valorSens) > 0.000001) { $sensibles[] = $etiqueta; }
            }
            if ($mode === 'AVANZADO' && $manualConcepts) {
                foreach ($manualConcepts as $manualConceptVal) {
                    $conceptIdVal = (int)$manualConceptVal['id'];
                    $rawManualVal = $_POST['extra_manual'][$pidVal][$conceptIdVal] ?? '';
                    $valorManualVal = trim((string)$rawManualVal) === '' ? 0 : nomina_normalize_decimal($rawManualVal);
                    if (abs((float)$valorManualVal) > 0.000001) { $sensibles[] = 'concepto manual ' . ($manualConceptVal['codigo'] ?? ''); }
                }
            }
            if ($sensibles && ((function_exists('mb_strlen') ? mb_strlen($obsVal, 'UTF-8') : strlen($obsVal)) < 15)) {
                $nom = 'ID ' . $pidVal;
                $resNom = mysqli_query($conexion, "SELECT nombre, apellido, cedula FROM personas WHERE id = {$pidVal} LIMIT 1");
                if ($resNom && mysqli_num_rows($resNom)) {
                    $rowNom = mysqli_fetch_assoc($resNom);
                    $nom = trim(($rowNom['apellido'] ?? '') . ', ' . ($rowNom['nombre'] ?? '')) . ' (CI ' . ($rowNom['cedula'] ?? '') . ')';
                }
                $novedadesSensiblesSinSoporte[] = $nom . ': ' . implode(', ', $sensibles);
            }
        }
        if ($novedadesSensiblesSinSoporte) {
            $errors[] = 'Toda novedad sensible requiere observación mínima de soporte: motivo, fecha y autorización o soporte. Pendiente: ' . implode(' | ', $novedadesSensiblesSinSoporte);
        }

        if (!$errors) {
        mysqli_begin_transaction($conexion);
        try {
            foreach ($personaIds as $pidRaw) {
                $pid = (int)$pidRaw;
                if ($pid <= 0) { continue; }

                $payload = [];
                $payload[$schema['periodo_id']] = $periodoId;
                $payload[$schema['persona_id']] = $pid;
                if ($schema['dias_ausencia_periodo']) { $payload[$schema['dias_ausencia_periodo']] = nomina_normalize_decimal($_POST['dias_aus_per'][$pid] ?? 0); }
                if ($schema['horas_retardo_periodo']) { $payload[$schema['horas_retardo_periodo']] = nomina_normalize_decimal($_POST['hrs_ret'][$pid] ?? 0); }
                if ($schema['he_diurna']) { $payload[$schema['he_diurna']] = nomina_normalize_decimal($_POST['he_diurna'][$pid] ?? 0); }
                if ($schema['he_nocturna']) { $payload[$schema['he_nocturna']] = nomina_normalize_decimal($_POST['he_nocturna'][$pid] ?? 0); }
                if ($schema['horas_nocturnas_ordinarias']) { $payload[$schema['horas_nocturnas_ordinarias']] = nomina_normalize_decimal($_POST['horas_nocturnas'][$pid] ?? 0); }
                if ($schema['dias_ausencia_mes']) {
                    $rawMes = $_POST['dias_aus_mes'][$pid] ?? '';
                    $payload[$schema['dias_ausencia_mes']] = $rawMes === '' ? null : nomina_normalize_decimal($rawMes);
                }
                if ($schema['bono_manual_bs']) { $payload[$schema['bono_manual_bs']] = nomina_normalize_decimal($_POST['bono_manual'][$pid] ?? 0); }
                if ($schema['otros_descuentos_bs']) { $payload[$schema['otros_descuentos_bs']] = nomina_normalize_decimal($_POST['otros_desc'][$pid] ?? 0); }
                if ($schema['prestamo_bs']) { $payload[$schema['prestamo_bs']] = nomina_normalize_decimal($_POST['prestamo'][$pid] ?? 0); }
                // v8.4: preservar pago_vacaciones_bs si el campo no fue enviado (por ejemplo, modo simple).
                // Esto evita que una novedad copiada desde vacaciones sea borrada a 0 al guardar otras novedades.
                if ($schema['pago_vacaciones_bs'] && isset($_POST['vacaciones']) && is_array($_POST['vacaciones']) && array_key_exists($pid, $_POST['vacaciones'])) {
                    $payload[$schema['pago_vacaciones_bs']] = nomina_normalize_decimal($_POST['vacaciones'][$pid] ?? 0);
                }
                if ($schema['observaciones']) {
                    $payload[$schema['observaciones']] = trim((string)($_POST['obs'][$pid] ?? ''));
                }

                $numericColsNovedades = array_values(array_filter([
                    $schema['periodo_id'],
                    $schema['persona_id'],
                    $schema['dias_ausencia_periodo'],
                    $schema['horas_retardo_periodo'],
                    $schema['he_diurna'],
                    $schema['he_nocturna'],
                    $schema['horas_nocturnas_ordinarias'],
                    $schema['dias_ausencia_mes'],
                    $schema['bono_manual_bs'],
                    $schema['otros_descuentos_bs'],
                    $schema['prestamo_bs'],
                    $schema['pago_vacaciones_bs'],
                ]));

                nomina_novedades_save_payload(
                    $conexion,
                    'novedades_periodo',
                    [$schema['periodo_id'] => $periodoId, $schema['persona_id'] => $pid],
                    $payload,
                    $numericColsNovedades
                );

                if ($mode === 'AVANZADO' && $manualConcepts) {
                    foreach ($manualConcepts as $manualConcept) {
                        $conceptId = (int)$manualConcept['id'];
                        $rawManual = $_POST['extra_manual'][$pid][$conceptId] ?? '';
                        $valorManual = trim((string)$rawManual) === '' ? 0 : nomina_normalize_decimal($rawManual);
                        if ($valorManual != 0) {
                            nomina_novedades_save_payload(
                                $conexion,
                                'novedades_periodo_conceptos_manual',
                                ['periodo_id' => $periodoId, 'persona_id' => $pid, 'concepto_id' => $conceptId],
                                ['periodo_id' => $periodoId, 'persona_id' => $pid, 'concepto_id' => $conceptId, 'valor_manual' => $valorManual],
                                ['periodo_id', 'persona_id', 'concepto_id', 'valor_manual']
                            );
                        } else {
                            mysqli_query($conexion, "DELETE FROM novedades_periodo_conceptos_manual WHERE periodo_id = {$periodoId} AND persona_id = {$pid} AND concepto_id = {$conceptId}");
                        }
                    }
                }
            }
            mysqli_commit($conexion);
            nomina_flash_set('success', 'Novedades guardadas correctamente.');
            header('Location: novedades_periodo.php?periodo_id=' . $periodoId . '&mode=' . strtolower($mode));
            exit;
        } catch (Throwable $e) {
            mysqli_rollback($conexion);
            $msgErrorSql = $e->getMessage();
            if (stripos($msgErrorSql, 'AS ' . 'nuevo') !== false || stripos($msgErrorSql, 'ON DUPLICATE ' . 'KEY UPDATE') !== false) {
                $msgErrorSql .= ' | Diagnóstico: esta versión v6.7 de novedades no usa alias de inserción ni actualización automática. Si este mensaje persiste, el servidor está ejecutando un archivo viejo en caché/opcache o existe otro archivo incluido con esa consulta.';
            }
            $errors[] = 'No se pudieron guardar las novedades: ' . $msgErrorSql;
        }
        }
    }
}

$personas = nomina_fetch_active_people($conexion);
$novedades = $periodoId ? nomina_fetch_novedades_by_period($conexion, $periodoId, $schema) : [];
$manualAssignments = $periodoId ? nomina_fetch_manual_concept_assignments($conexion, $periodoId) : [];
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $errors) {
    foreach ($postDraftNovedades as $pidDraft => $draftValues) {
        $novedades[$pidDraft] = array_merge($novedades[$pidDraft] ?? [], $draftValues);
    }
    foreach ($postDraftManualAssignments as $pidDraft => $draftConcepts) {
        foreach ($draftConcepts as $conceptDraftId => $draftConceptValue) {
            $manualAssignments[$pidDraft][$conceptDraftId] = $draftConceptValue;
        }
    }
}
$hasExtendedFields = $schema['schema_name'] === 'extendido';
?>
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Novedades del período</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root{--primary:#1a3c8b;--accent:#ff9800;--success:#166534;--danger:#be123c;--gray:#6b7280;--bg:#f5f7fa;--card:#fff;--line:#e5e7eb;--shadow:0 8px 24px rgba(16,24,40,.08);--radius:16px}
*{box-sizing:border-box}body{margin:0;font-family:'Inter',sans-serif;background:var(--bg);color:#24364b}a{color:var(--primary);text-decoration:none}.container{max-width:1400px;margin:24px auto;padding:0 16px}.topbar,.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow)}.topbar{display:flex;justify-content:space-between;align-items:center;padding:16px 18px;gap:16px}.title{font-size:20px;font-weight:700}.subtitle{font-size:13px;color:var(--gray);margin-top:4px}.card{padding:18px;margin-top:16px}.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:10px 14px;border-radius:12px;border:1px solid transparent;background:var(--primary);color:#fff;font-weight:600;cursor:pointer}.btn.secondary{background:#fff;color:var(--primary);border-color:rgba(26,60,139,.22)}.btn.ghost{background:rgba(26,60,139,.08);color:var(--primary)}
.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:14px}.col-3{grid-column:span 3}.col-4{grid-column:span 4}.col-6{grid-column:span 6}.col-12{grid-column:span 12}@media(max-width:1100px){.col-3,.col-4,.col-6{grid-column:span 12}.topbar{flex-direction:column;align-items:flex-start}}
label{display:block;font-size:12px;font-weight:600;margin:0 0 6px 2px;color:#334155}select,input,textarea{width:100%;padding:10px 12px;border:1px solid var(--line);border-radius:12px;background:#fff;font:inherit}textarea{min-height:42px;resize:vertical}select:focus,input:focus,textarea:focus{outline:none;border-color:rgba(26,60,139,.55);box-shadow:0 0 0 3px rgba(26,60,139,.12)}
.help{border-left:4px solid var(--accent);background:rgba(255,152,0,.10);padding:14px;border-radius:14px;font-size:13px}.help ul{margin:8px 0 0 18px}.alert{padding:12px 14px;border-radius:12px;margin:12px 0;font-size:13px;border:1px solid}.alert.error{background:rgba(190,18,60,.08);border-color:rgba(190,18,60,.24);color:var(--danger)}.alert.success{background:rgba(22,101,52,.08);border-color:rgba(22,101,52,.22);color:var(--success)}.alert.info{background:rgba(26,60,139,.08);border-color:rgba(26,60,139,.22);color:var(--primary)}.tabs{display:flex;gap:8px;flex-wrap:wrap}.tab{padding:8px 12px;border-radius:999px;border:1px solid rgba(26,60,139,.18);font-size:13px;color:var(--primary);background:#fff}.tab.active{background:rgba(26,60,139,.10);font-weight:700}.table-wrap{overflow:auto;border:1px solid var(--line);border-radius:14px;margin-top:14px}.table{width:100%;border-collapse:collapse;min-width:1300px}.table th,.table td{padding:10px 12px;border-bottom:1px solid #eef2f7;font-size:13px;vertical-align:top;text-align:left}.table th{background:#fafafa;font-weight:700}.muted{color:var(--gray);font-size:12px}.badge{display:inline-flex;padding:5px 10px;border-radius:999px;background:rgba(26,60,139,.10);color:var(--primary);font-size:12px;font-weight:600}.mini{font-size:11px;color:#64748b}.sticky-top-actions{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;flex-wrap:wrap;margin-bottom:12px}.row-actions{display:flex;gap:10px;flex-wrap:wrap}.num{max-width:110px}.obs{min-width:220px}.employee{min-width:240px}.hint-box{padding:12px;border:1px dashed rgba(26,60,139,.25);background:#fbfdff;border-radius:12px}.chip-warning{display:inline-block;padding:4px 8px;border-radius:999px;background:rgba(255,152,0,.12);color:#9a5b00;font-size:11px;font-weight:600}
</style>
<link rel="stylesheet" href="nomina_ui_patch.css?v=20260415">
</head>
<body data-nomina-page="novedades">
<div class="container">
    <div class="topbar">
        <div>
            <div class="title">Novedades del Período</div>
            <div class="subtitle">Registra excepciones del trabajador antes del cálculo: ausencias, retardos, horas extra, bono nocturno, descuentos, conceptos manuales y observaciones. <span class="mini">Versión <?php echo h($nominaCompatVersion); ?></span></div>
        </div>
        <div style="display:flex;gap:10px;flex-wrap:wrap;">
            <a class="btn secondary" href="index.php">Volver al dashboard</a>
        </div>
    </div>

    <div class="card">
        <div class="help">
            <strong>Cómo usar esta pantalla</strong>
            <ul>
                <li>Aquí no reconstruyes la quincena completa: solo registras <b>excepciones</b> como ausencias, retardos, horas extra, bono nocturno ordinario, descuentos, préstamos, conceptos manuales y pago manual de vacaciones.</li>
                <li>Lo normal debería venir luego precargado por <b>calendario</b> o por <b>asistencia</b> en el cálculo.</li>
                <li>Usa <b>HE diurnas</b> para horas extraordinarias de día, <b>HE nocturnas</b> para horas extraordinarias de noche y <b>Horas nocturnas ordinarias</b> para el recargo legal del 30% cuando la jornada normal fue nocturna.</li>
                <li>En la última quincena, el campo <b>Ausencias del mes para cestaticket</b> permite prorratear el bono mensual.</li>
                <li><b>Retardos:</b> se cargan en horas decimales. Ejemplos: 30 minutos = 0,50; 45 minutos = 0,75; 1 hora 15 minutos = 1,25. El cálculo descuenta horas de retardo × salario hora.</li>
                <li><b>Nivel auditor:</b> si cargas horas extra, bono nocturno, ausencias, retardos, descuentos, préstamos, vacaciones manuales o conceptos manuales, la observación es obligatoria.</li>
            </ul>
        </div>

        <?php if ($flash): ?><div class="alert <?php echo h($flash['type']); ?>"><?php echo h($flash['message']); ?></div><?php endif; ?>
        <?php if ($errors): ?>
            <div class="alert error"><strong>Revisa estos puntos:</strong><ul style="margin:8px 0 0 18px;"><?php foreach ($errors as $error): ?><li><?php echo $error; ?></li><?php endforeach; ?></ul></div>
        <?php endif; ?>
        <?php if (!empty($schemaHoras['changes'])): ?>
            <div class="alert success">Se actualizaron automáticamente las novedades para capturar horas extra y bono nocturno: <b><?php echo h(implode(', ', $schemaHoras['changes'])); ?></b>.</div>
        <?php endif; ?>
        <?php if (!empty($schemaHoras['errors'])): ?>
            <div class="alert error"><strong>No se pudo completar la migración automática de horas:</strong><ul style="margin:8px 0 0 18px;"><?php foreach ($schemaHoras['errors'] as $error): ?><li><?php echo h($error); ?></li><?php endforeach; ?></ul></div>
        <?php endif; ?>
        <?php if (!$hasExtendedFields): ?>
            <div class="alert info">La tabla <b>novedades_periodo</b> sigue en estructura base. El sistema trabajará en modo compatible, pero campos como <b>Vacaciones</b> y <b>Ausencias del mes para cestaticket</b> no se guardarán hasta aplicar la migración.</div>
        <?php endif; ?>
        <?php if (!$periodos): ?>
            <div class="alert error">
                <strong>No hay períodos de nómina registrados.</strong><br>
                Esto suele ocurrir después de ejecutar una limpieza de corridas/períodos. Debes crear o restaurar el período antes de cargar novedades.
                <div style="margin-top:10px;display:flex;gap:10px;flex-wrap:wrap">
                    <a class="btn secondary" href="periodos_nomina.php">Crear período manualmente</a>
                </div>
            </div>
        <?php endif; ?>
        <?php if ($periodo && (int)$periodo['total_corridas'] > 0): ?>
            <div class="alert info">Este período ya tiene <b><?php echo (int)$periodo['total_corridas']; ?></b> corrida(s) asociada(s). Si vuelves a calcular, revisa que no existan pagos o aprobaciones que deban conservarse.</div>
        <?php endif; ?>

        <div class="alert info">
            <b>Guía de retardos:</b> este campo se carga en <b>horas decimales</b>. 30 minutos = <b>0,50</b>; 45 minutos = <b>0,75</b>; 1 hora 15 minutos = <b>1,25</b>.
            El cálculo descuenta <b>horas de retardo × salario hora</b>.
        </div>

        <form method="get" class="grid" style="margin-top:12px;">
            <div class="col-6">
                <label for="periodo_id">Período</label>
                <select id="periodo_id" name="periodo_id" onchange="this.form.submit()">
                    <?php foreach ($periodos as $p): ?>
                        <option value="<?php echo (int)$p['id']; ?>" <?php echo (int)$p['id'] === (int)$periodoId ? 'selected' : ''; ?>>
                            <?php echo h($p['codigo'] . ' (' . $p['tipo'] . ') ' . $p['fecha_desde'] . ' a ' . $p['fecha_hasta'] . ((int)$p['es_ultima_quincena'] === 1 ? ' [Última quincena]' : '')); ?>
                        </option>
                    <?php endforeach; ?>
                </select>
            </div>
            <div class="col-6">
                <label>Modo de captura</label>
                <div class="tabs">
                    <a class="tab <?php echo $mode === 'SIMPLE' ? 'active' : ''; ?>" href="novedades_periodo.php?periodo_id=<?php echo (int)$periodoId; ?>&mode=simple">Modo simple</a>
                    <a class="tab <?php echo $mode === 'AVANZADO' ? 'active' : ''; ?>" href="novedades_periodo.php?periodo_id=<?php echo (int)$periodoId; ?>&mode=avanzado">Modo avanzado</a>
                </div>
                <div class="muted" style="margin-top:8px;">Usa <b>simple</b> para RRHH operativo. Usa <b>avanzado</b> cuando necesites prorrateo del cestaticket, conceptos manuales adicionales o pago manual de vacaciones.</div>
            </div>
        </form>

        <?php if ($periodo): ?>
            <div class="hint-box" style="margin-top:14px;">
                <div><strong><?php echo h($periodo['codigo']); ?></strong> · <?php echo h($periodo['fecha_desde']); ?> a <?php echo h($periodo['fecha_hasta']); ?> · Estado: <b><?php echo h($periodo['estado']); ?></b></div>
                <div class="muted" style="margin-top:6px;">
                    <?php if ((int)$periodo['es_ultima_quincena'] === 1): ?>
                        <span class="chip-warning">Última quincena</span> Aquí se paga el cestaticket mensual. El prorrateo usa “Ausencias del mes para cestaticket”.
                    <?php else: ?>
                        Período ordinario. El cestaticket mensual no se liquida aquí salvo que cambies la lógica del sistema.
                    <?php endif; ?>
                </div>
            </div>
        <?php endif; ?>
    </div>

    <div class="card">
        <form method="post" id="form-novedades">
            <input type="hidden" name="periodo_id" value="<?php echo (int)$periodoId; ?>">
            <input type="hidden" name="mode" value="<?php echo strtolower($mode); ?>">

            <div class="alert info" style="margin-top:0;border-color:rgba(255,152,0,.35);background:rgba(255,152,0,.10);">
                <strong>Antes de cargar novedades sensibles:</strong> cuando registres ausencias, retardos, horas extra, bono nocturno, descuentos, préstamos, vacaciones manuales o conceptos manuales, completa <b>Observaciones</b> con una justificación ordenada: <b>motivo + fecha + autorización/soporte</b>. Ejemplo: “Hora extra autorizada por supervisor de turno. Fecha 15/05/2026. Soporte asistencia diaria.” El sistema validará antes de enviar para evitar recargar la pantalla o perder los valores escritos.
            </div>

            <div class="sticky-top-actions">
                <div>
                    <h2 style="margin:0 0 6px 0;">Excepciones del período por trabajador</h2>
                    <div class="muted">Carga solo diferencias frente a lo normal del período: ausencias, retardos, horas extra, horas nocturnas ordinarias, ajustes monetarios y observaciones operativas.</div>
                </div>
                <div class="row-actions">
                    <a class="btn secondary" href="nomina_calcular_actualizado.php?periodo_id=<?php echo (int)$periodoId; ?>&origen_cantidades=CALENDARIO">Ir a cálculo</a>
                    <button class="btn" type="submit" name="guardar">Guardar novedades</button>
                </div>
            </div>

            <div class="table-wrap">
                <table class="table">
                    <thead>
                        <tr>
                            <th class="employee">Trabajador</th>
                            <th>Ausencias</th>
                            <th>Retardos (horas)<br><span class="mini">30 min = 0,50</span></th>
                            <th>HE diurnas</th>
                            <th>HE nocturnas</th>
                            <th>Horas nocturnas ordinarias</th>
                            <?php if ($mode === 'AVANZADO'): ?>
                                <th>Ausencias del mes</th>
                            <?php endif; ?>
                            <th>Bonificación manual (Bs)</th>
                            <th>Descuentos manuales (Bs)</th>
                            <th>Cuota préstamo (Bs)</th>
                            <?php if ($mode === 'AVANZADO' && $hasExtendedFields): ?><th>Pago manual vacaciones (Bs)</th><?php endif; ?>
                            <?php if ($mode === 'AVANZADO' && $manualConcepts): ?>
                                <?php foreach ($manualConcepts as $manualConcept): ?>
                                    <th><?php echo h($manualConcept['codigo']); ?><br><span class="mini"><?php echo h($manualConcept['nombre']); ?> · <?php echo h(strtoupper((string)$manualConcept['moneda_monto_fijo'])); ?></span></th>
                                <?php endforeach; ?>
                            <?php endif; ?>
                            <th>Observaciones<br><span class="mini">Obligatoria con novedades sensibles</span></th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ($personas as $persona): ?>
                            <?php $pid = (int)$persona['id']; $nov = $novedades[$pid] ?? []; if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($postDraftNovedades[$pid])) { $nov = array_merge($nov, $postDraftNovedades[$pid]); } ?>
                            <tr>
                                <td class="employee">
                                    <input type="hidden" name="persona_id[]" value="<?php echo $pid; ?>">
                                    <strong><?php echo h($persona['apellido'] . ', ' . $persona['nombre']); ?></strong><br>
                                    <span class="mini">CI: <?php echo h($persona['cedula']); ?> · Cargo: <?php echo h($persona['cargo'] ?: 'Sin cargo'); ?></span><br>
                                    <span class="mini">Turno: <?php echo h($persona['turno_nombre'] ?: 'Sin turno'); ?> · Salario referencia Bs: <?php echo number_format(nomina_get_effective_salary_bs($persona, 1), 2, ',', '.'); ?></span>
                                </td>
                                <td><input class="num" name="dias_aus_per[<?php echo $pid; ?>]" value="<?php echo h($nov['dias_ausencia_periodo'] ?? '0'); ?>"></td>
                                <td><input class="num" name="hrs_ret[<?php echo $pid; ?>]" value="<?php echo h($nov['horas_retardo_periodo'] ?? '0'); ?>" placeholder="Ej: 0,50"><div class="mini">Horas decimales. 0,50 = 30 min.</div></td>
                                <td>
                                    <input class="num" name="he_diurna[<?php echo $pid; ?>]" value="<?php echo h($nov['he_diurna'] ?? '0'); ?>" placeholder="0">
                                    <div class="mini">A-007 · horas extra diurnas.</div>
                                </td>
                                <td>
                                    <input class="num" name="he_nocturna[<?php echo $pid; ?>]" value="<?php echo h($nov['he_nocturna'] ?? '0'); ?>" placeholder="0">
                                    <div class="mini">A-008 · horas extra nocturnas.</div>
                                </td>
                                <td>
                                    <input class="num" name="horas_nocturnas[<?php echo $pid; ?>]" value="<?php echo h($nov['horas_nocturnas_ordinarias'] ?? '0'); ?>" placeholder="0">
                                    <div class="mini">A-011 · jornada nocturna ordinaria 30%.</div>
                                </td>
                                <?php if ($mode === 'AVANZADO'): ?>
                                    <td>
                                        <?php if ($hasExtendedFields): ?>
                                            <input class="num" name="dias_aus_mes[<?php echo $pid; ?>]" value="<?php echo h($nov['dias_ausencia_mes'] ?? ''); ?>" placeholder="Opcional">
                                            <div class="mini">Solo última quincena.</div>
                                        <?php else: ?>
                                            <input class="num" disabled value="Migración pendiente">
                                        <?php endif; ?>
                                    </td>
                                <?php endif; ?>
                                <td><input class="num" name="bono_manual[<?php echo $pid; ?>]" value="<?php echo h($nov['bono_manual_bs'] ?? '0'); ?>"></td>
                                <td><input class="num" name="otros_desc[<?php echo $pid; ?>]" value="<?php echo h($nov['otros_descuentos_bs'] ?? '0'); ?>"></td>
                                <td><input class="num" name="prestamo[<?php echo $pid; ?>]" value="<?php echo h($nov['prestamo_bs'] ?? '0'); ?>"></td>
                                <?php if ($mode === 'AVANZADO' && $hasExtendedFields): ?>
                                    <td>
                                        <input class="num" name="vacaciones[<?php echo $pid; ?>]" value="<?php echo h($nov['pago_vacaciones_bs'] ?? '0'); ?>" placeholder="0">
                                        <div class="mini">Solo si necesitas registrar un pago manual extraordinario.</div>
                                    </td>
                                <?php endif; ?>
                                <?php if ($mode === 'AVANZADO' && $manualConcepts): ?>
                                    <?php foreach ($manualConcepts as $manualConcept): ?>
                                        <?php $manualVal = $manualAssignments[$pid][$manualConcept['id']]['valor_manual'] ?? ''; ?>
                                        <td>
                                            <input class="num" name="extra_manual[<?php echo $pid; ?>][<?php echo (int)$manualConcept['id']; ?>]" value="<?php echo h($manualVal); ?>" placeholder="<?php echo h(number_format((float)($manualConcept['monto_fijo'] ?? 0), 2, '.', '')); ?>">
                                            <div class="mini">Monto en <?php echo h(strtoupper((string)$manualConcept['moneda_monto_fijo'])); ?>.</div>
                                        </td>
                                    <?php endforeach; ?>
                                <?php endif; ?>
                                <td><textarea class="obs" name="obs[<?php echo $pid; ?>]" placeholder="Ej: Permiso médico 15/05/2026. Soporte recibido por RRHH. Autorizado por supervisor."><?php echo h($nov['observaciones'] ?? ''); ?></textarea></td>
                            </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>

            <div class="row-actions" style="margin-top:14px;justify-content:flex-end;">
                <button class="btn" type="submit" name="guardar">Guardar novedades</button>
            </div>
        </form>
    </div>
</div>

<script>
(function(){
    const form = document.getElementById('form-novedades');
    if (!form) return;
    const sensitiveNames = [
        'dias_aus_per', 'hrs_ret', 'he_diurna', 'he_nocturna', 'horas_nocturnas',
        'bono_manual', 'otros_desc', 'prestamo', 'vacaciones', 'extra_manual'
    ];
    function toNumber(value) {
        if (value === null || value === undefined) return 0;
        const raw = String(value).trim().replace(/\./g, '').replace(',', '.');
        if (raw === '') return 0;
        const n = Number(raw);
        return Number.isFinite(n) ? n : 0;
    }
    function isSensitiveInput(input) {
        const name = input.getAttribute('name') || '';
        return sensitiveNames.some(prefix => name.indexOf(prefix + '[') === 0 || name.indexOf(prefix + ']') !== -1);
    }
    function getPidFromName(name) {
        const match = String(name).match(/\[(\d+)\]/);
        return match ? match[1] : '';
    }
    form.addEventListener('submit', function(ev){
        const rows = form.querySelectorAll('tbody tr');
        const missing = [];
        rows.forEach(row => {
            let hasSensitive = false;
            row.querySelectorAll('input').forEach(input => {
                if (!isSensitiveInput(input)) return;
                if (Math.abs(toNumber(input.value)) > 0.000001) hasSensitive = true;
            });
            if (!hasSensitive) return;
            const obs = row.querySelector('textarea[name^="obs["]');
            const obsVal = obs ? obs.value.trim() : '';
            if (obsVal.length < 15) {
                const strong = row.querySelector('.employee strong');
                missing.push(strong ? strong.textContent.trim() : 'trabajador sin identificar');
                if (obs) obs.style.borderColor = '#be123c';
            }
        });
        if (missing.length) {
            ev.preventDefault();
            alert('No se enviaron las novedades. Toda novedad sensible requiere observación mínima ordenada: motivo + fecha + autorización/soporte. Pendiente: ' + missing.join(' | '));
            const firstBad = form.querySelector('textarea[style*="190"]') || form.querySelector('textarea[style*="be123c"]');
            if (firstBad) firstBad.focus();
        }
    });
})();
</script>

<script src="nomina_ui_patch.js?v=20260415"></script>
</body>
</html>
