<?php
require_once 'auth.php';
require_once 'config.php';
checkLogin();

// AUTO-REFRESH SESSION DATA (Role/Ship Assignment)
try {
    $pdo = getDBConnection();
    $stmt = $pdo->prepare("SELECT ship_id, role, status FROM users WHERE id = :id");
    $stmt->execute([':id' => $_SESSION['user_id']]);
    $uData = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($uData) {
        if ($uData['status'] !== 'active') {
            header("Location: api/logout.php");
            exit;
        }
        $_SESSION['ship_id'] = $uData['ship_id'];
        $_SESSION['role'] = $uData['role'];

        // GET ALL ASSIGNED SHIPS
        $stmtShips = $pdo->prepare("SELECT ship_id FROM user_ships WHERE user_id = :id");
        $stmtShips->execute([':id' => $_SESSION['user_id']]);
        $_SESSION['assigned_ships'] = $stmtShips->fetchAll(PDO::FETCH_COLUMN);

        // Fallback for migration
        if (empty($_SESSION['assigned_ships']) && !empty($uData['ship_id'])) {
            $_SESSION['assigned_ships'] = [$uData['ship_id']];
        }
    }
} catch (Exception $e) { /* Ignore */
}
?>
<!DOCTYPE html>
<html lang="es">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>TECNOTRACK MARINE - MONITOREO AVANZADO DE CADENA DE FRÍO</title>
    <link rel="stylesheet" href="styles/main.css?v=1.1.0">
    <script src="js/chart.umd.min.js"></script>
    <script src="js/chartjs-adapter-date-fns.bundle.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8"></script>
    <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom@2.0.1"></script>
</head>

<body>
    <div class="dashboard-container">
        <header class="header">
            <div class="header-title">
                <img src="img/Logo_header.png" alt="Logo" class="header-logo">
            </div>

            <div class="header-status">
                <div id="statusIndicator" class="status-pill status-offline">
                    <span class="pulse-dot"></span>
                    <span id="statusText">SIN SEÑAL</span>
                </div>

                <?php
                // Fetch available ships based on role
                $pdo = getDBConnection();
                $ships = [];
                $role = $_SESSION['role'] ?? '';
                $userId = $_SESSION['user_id'] ?? 0;

                if ($role === 'admin') {
                    // Global admin sees everything
                    $stmt = $pdo->query("SELECT ship_id, name FROM ships ORDER BY name");
                    $ships = $stmt->fetchAll(PDO::FETCH_ASSOC);
                } else {
                    // Sub-adm or regular user: fetch assigned ships from user_ships table
                    $stmt = $pdo->prepare("SELECT s.ship_id, s.name 
                                         FROM ships s 
                                         JOIN user_ships us ON s.ship_id = us.ship_id 
                                         WHERE us.user_id = :user_id 
                                         ORDER BY s.name");
                    $stmt->execute([':user_id' => $userId]);
                    $ships = $stmt->fetchAll(PDO::FETCH_ASSOC);

                    // Fallback to legacy ship_id if no entries in user_ships (for backward compatibility during migration)
                    if (empty($ships) && !empty($_SESSION['ship_id'])) {
                        $stmt = $pdo->prepare("SELECT ship_id, name FROM ships WHERE ship_id = :id");
                        $stmt->execute([':id' => $_SESSION['ship_id']]);
                        $ships = $stmt->fetchAll(PDO::FETCH_ASSOC);
                    }
                }
                ?>

                <select id="shipSelector" class="ship-selector" onchange="changeShip(this.value)" <?php echo (count($ships) <= 1) ? 'disabled' : ''; ?>>
                    <?php foreach ($ships as $ship): ?>
                        <option value="<?php echo htmlspecialchars($ship['ship_id']); ?>">
                            <?php echo htmlspecialchars($ship['name']); ?>
                        </option>
                    <?php endforeach; ?>
                </select>

                <div class="header-gauges" style="display: flex; gap: 15px;">
                    <div class="header-gauge-container" id="headerGaugeMin" <?php if (canManageUsers())
                        echo 'onclick="openSettingsModal()" style="cursor: pointer;" title="Configurar Mínimo"'; ?>>
                        <svg viewBox="0 0 100 85" class="gauge-svg">
                            <path d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="#1a2e42" stroke-width="10"
                                stroke-linecap="round" />
                            <path id="gaugeMinPath" d="M 10 50 A 40 40 0 0 1 90 50" fill="none"
                                stroke="var(--blue-safe)" stroke-width="10" stroke-linecap="round"
                                stroke-dasharray="126" stroke-dashoffset="126" />
                            <g id="gaugeNeedleMin" transform="rotate(-90, 50, 50)">
                                <g class="needle-jitter">
                                    <path d="M 50 45 L 50 20" stroke="#fff" stroke-width="3" stroke-linecap="round" />
                                    <circle cx="50" cy="50" r="4" fill="#fff" />
                                </g>
                            </g>
                            <text x="50" y="15" text-anchor="middle" fill="#8892b0" font-size="10" font-weight="bold"
                                font-family="sans-serif">MIN</text>
                            <text id="gaugeTextMin" x="50" y="70" text-anchor="middle" fill="var(--blue-safe)"
                                font-size="16" font-weight="bold" font-family="sans-serif">0°</text>
                            <text id="gaugeSensorMin" x="50" y="81" text-anchor="middle" fill="#a0b4d0" font-size="11"
                                font-weight="600" font-family="sans-serif">-</text>
                        </svg>
                    </div>
                    <div class="header-gauge-container" id="headerGaugeMax" <?php if (canManageUsers())
                        echo 'onclick="openSettingsModal()" style="cursor: pointer;" title="Configurar Máximo"'; ?>>
                        <svg viewBox="0 0 100 85" class="gauge-svg">
                            <path d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="#1a2e42" stroke-width="10"
                                stroke-linecap="round" />
                            <path id="gaugeMaxPath" d="M 10 50 A 40 40 0 0 1 90 50" fill="none"
                                stroke="var(--red-alert)" stroke-width="10" stroke-linecap="round"
                                stroke-dasharray="126" stroke-dashoffset="126" />
                            <g id="gaugeNeedleMax" transform="rotate(-90, 50, 50)">
                                <g class="needle-jitter">
                                    <path d="M 50 45 L 50 20" stroke="#fff" stroke-width="3" stroke-linecap="round" />
                                    <circle cx="50" cy="50" r="4" fill="#fff" />
                                </g>
                            </g>
                            <text x="50" y="15" text-anchor="middle" fill="#8892b0" font-size="10" font-weight="bold"
                                font-family="sans-serif">MAX</text>
                            <text id="gaugeTextMax" x="50" y="70" text-anchor="middle" fill="var(--red-alert)"
                                font-size="16" font-weight="bold" font-family="sans-serif">25°</text>
                            <text id="gaugeSensorMax" x="50" y="81" text-anchor="middle" fill="#d0a0a0" font-size="11"
                                font-weight="600" font-family="sans-serif">-</text>
                        </svg>
                    </div>
                </div>

                <div class="header-links" style="display: flex; gap: 15px; align-items: center;">
                    <?php if (($_SESSION['role'] ?? '') === 'admin'): ?>
                        <a href="admin.php"
                            style="color: var(--cyan-glow); text-decoration: none; font-weight: 600; font-size: 0.9rem; border: 1px solid var(--cyan-glow); padding: 5px 10px; border-radius: 5px; background: rgba(0, 242, 255, 0.1);">PA-ADMIN</a>
                    <?php endif; ?>

                    <?php if (($_SESSION['role'] ?? '') === 'sub-adm' || ($_SESSION['role'] ?? '') === 'admin'): ?>
                        <button onclick="openSettingsModal()"
                            style="color: var(--cyan-glow); background: rgba(0, 242, 255, 0.1); border: 1px solid var(--cyan-glow); padding: 5px 10px; border-radius: 5px; font-weight: 600; cursor: pointer;">
                            ⚙️ CONFIG
                        </button>
                    <?php endif; ?>

                    <?php if (($_SESSION['role'] ?? '') === 'sub-adm'): ?>
                        <button onclick="openShipUsersModal()"
                            style="color: var(--cyan-glow); background: rgba(0, 242, 255, 0.1); border: 1px solid var(--cyan-glow); padding: 5px 10px; border-radius: 5px; font-weight: 600; cursor: pointer;">
                            USUARIOS
                        </button>
                    <?php endif; ?>

                    <a href="ver_datos.php"
                        style="color: var(--cyan-glow); text-decoration: none; font-weight: 600; font-size: 0.9rem;">HISTORIAL</a>

                    <a href="javascript:void(0)" onclick="showLogoutModal()"
                        style="color: #ff4d4d; text-decoration: none; font-weight: 600; font-size: 0.75rem; border: 1px solid #ff4d4d; padding: 5px 8px; border-radius: 5px; background: rgba(255, 77, 77, 0.1); text-transform: uppercase;">CERRAR SESIÓN</a>
                </div>
            </div>
        </header>

        <section class="ship-visualizer">
            <div class="visualizer-header">
                <h2 style="font-size: 0.8rem; color: var(--text-secondary); margin: 0;">MAPA DE SENSORES</h2>

                <?php if (($_SESSION['role'] ?? '') === 'admin' || ($_SESSION['role'] ?? '') === 'sub-adm'): ?>
                    <button id="lockToggle" class="lock-btn" onclick="toggleLock()"
                        title="Bloquear/Desbloquear marcadores">🔒</button>
                <?php endif; ?>

                <button id="muteBtn" class="lock-btn" onclick="toggleMute()" title="Silenciar Alerta"
                    style="background: var(--green-safe); margin-left:8px;">🔊</button>
                <button id="fullscreenBtn" class="fullscreen-btn" onclick="toggleFullscreen()"
                    title="Pantalla completa">⛶</button>
            </div>
            <div class="map-container" id="mapContainer">
                <img src="barco.png" alt="Mapa de Sensores" class="ship-model" id="shipImg">
                <div id="markersLayer"></div>
                <div class="scan-line"></div>
            </div>
            <audio id="alertSound" src="sound/alert.mp3" preload="auto" loop></audio>
        </section>

        <section class="metrics-grid" id="metricsGrid">
        </section>

        <section class="chart-section">
            <div class="chart-header"
                style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
                <h2 style="font-size: 1rem; color: var(--text-secondary); margin: 0;">TENDENCIAS DE TEMPERATURA (24H)
                </h2>
                <button class="fullscreen-btn" onclick="toggleChartFullscreen()" title="Pantalla completa"
                    style="margin: 0;">⛶</button>
            </div>
            <div id="customLegend" class="custom-legend"></div>
            <div class="chart-container-wrapper">
                <div id="chartLoadingOverlay" class="chart-loading-overlay">
                    <div class="loading-spinner"></div>
                    <span>Cargando tendencias...</span>
                </div>
                <canvas id="coldChainChart"></canvas>
                <div class="chart-zoom-controls">
                    <button onclick="zoomIn()" title="Aumentar Zoom">+</button>
                    <button onclick="zoomOut()" title="Disminuir Zoom">−</button>
                    <button onclick="resetZoom()" title="Restablecer" style="font-size: 0.8rem;">LIVE</button>
                </div>
            </div>
        </section>

        <section class="messages-panel">
            <div class="messages-list" id="mensajesPruebaLista"></div>
        </section>
    </div>

    <script>
        let currentBuque = '<?php echo $_SESSION['ship_id'] ?? 'BUQUE-01'; ?>';
        let mainChart = null;
        let isLocked = true; // Bloqueado por defecto
        let activeMarker = null;
        let activeSensors = [];
        let lastData = null; // Cache for immediate rendering

        // --- AUDIO ALERT SYSTEM ---
        let isMuted = false;
        let isAlarmPlaying = false;
        let pendingAlarm = false; // Nueva flag para saber si hay una alarma esperando desbloqueo
        const alertSound = document.getElementById('alertSound');

        // Unlock audio on first user interaction
        function unlockAudio(force = false) {
            if (force || (pendingAlarm && !isMuted && !isAlarmPlaying)) {
                console.log("Audio desbloqueado por interacción usuario (Force: " + force + ")");
                playAlarm();
            }
            // Remove listeners once interactions start happening
            document.removeEventListener('click', interactionHandler);
            document.removeEventListener('scroll', interactionHandler);
            document.removeEventListener('keydown', interactionHandler);
            document.removeEventListener('touchstart', interactionHandler);
        }

        const interactionHandler = (e) => {
            // Fix: Don't auto-unlock/close on global clicks if the modal is still open.
            // Force user to click the specific button.
            const modal = document.getElementById('welcomeModal');
            if (modal && modal.style.display !== 'none') {
                return;
            }
            unlockAudio(false);
        };

        ['click', 'scroll', 'keydown', 'touchstart'].forEach(evt =>
            document.addEventListener(evt, interactionHandler, { passive: true })
        );

        function toggleMute() {
            isMuted = !isMuted;
            const btn = document.getElementById('muteBtn');
            if (isMuted) {
                btn.textContent = '🔇';
                btn.style.background = 'var(--red-alert)';
                stopAlarm();
                pendingAlarm = false;
            } else {
                btn.textContent = '🔊';
                btn.style.background = 'var(--green-safe)';
                // Si hay alarma pendiente, retomarla
                if (lastData) checkGlobalAlarm();
            }
        }

        // MODAL HELPERS
        function showMessage(title, text, type = 'info') {
            document.getElementById('msgTitle').textContent = title;
            document.getElementById('msgText').textContent = text;
            const icon = (type === 'error-modal') ? '❌' : (type === 'success' ? '✅' : 'ℹ️'); // type renamed to avoid clash
            document.getElementById('msgIcon').textContent = icon;
            document.getElementById('messageModal').style.display = 'flex';
        }

        function closeMessageModal() {
            document.getElementById('messageModal').style.display = 'none';
        }

        let confirmCallback = null;
        function showConfirm(title, text, callback) {
            document.getElementById('confirmTitle').textContent = title;
            document.getElementById('confirmText').textContent = text;
            confirmCallback = callback;
            document.getElementById('confirmModal').style.display = 'flex';
        }

        function closeConfirmModal(confirmed) {
            document.getElementById('confirmModal').style.display = 'none';
            if (confirmed && confirmCallback) confirmCallback();
            confirmCallback = null;
        }

        function playAlarm() {
            if (isMuted) return;

            // STATELSS CHECK: Only play if currently paused
            if (alertSound.paused) {
                console.log("🔊 STARTING ALARM: Active High Temp Detected");
                alertSound.volume = 1.0; // FORCE MAX VOLUME
                alertSound.currentTime = 0; // Restart from beginning

                const promise = alertSound.play();
                if (promise !== undefined) {
                    promise.catch(error => {
                        console.error("Autoplay prevented:", error);
                        pendingAlarm = true; // Keep flag just for the modal/interaction logic
                    });
                }
            } else {
                // Ensure volume is up even if already playing (double check)
                if (alertSound.volume < 1.0) alertSound.volume = 1.0;
            }
        }

        function stopAlarm() {
            // STATELESS CHECK: Only stop if not paused
            if (!alertSound.paused) {
                console.log("shhh... Stopping Alarm (Normal Status)");
                alertSound.pause();
                alertSound.currentTime = 0;
            }
            isAlarmPlaying = false; // flag update for consistency
        }

        function checkGlobalAlarm() {
            // 1. Detect if ANY sensor is currently high
            let anyHighTemp = false;
            if (typeof activeSensors !== 'undefined') {
                anyHighTemp = activeSensors.some(s => s.isHighTemp);
            }

            // 2. DECIDE: Play or Stop based on CURRENT state vs DESIRED state
            if (anyHighTemp && !isMuted) {
                // DESIRED: Playing
                playAlarm();
            } else {
                // DESIRED: Stopped (either no high temp OR muted)
                stopAlarm();
            }
        }

        // --- DYNAMIC SENSOR MANAGEMENT ---

        let currentMaxTemp = 25.0; // Default
        let currentMinTemp = 0.0;  // Default

        async function loadShipSettings() {
            try {
                const res = await fetch(`api/ship_settings.php?ship_id=${currentBuque}`);
                const data = await res.json();
                if (data.success) {
                    currentMaxTemp = parseFloat(data.max_temp);
                    currentMinTemp = parseFloat(data.min_temp || 0);
                    console.log(`Settings Loaded: Max=${currentMaxTemp}, Min=${currentMinTemp}`);
                    updateGauge(currentMaxTemp, 'max');
                    updateGauge(currentMinTemp, 'min');
                }
            } catch (e) { console.error("Error loading settings"); }
        }

        function calculateSensorRanges() {
            // Calcular el rango dinámico basado en todas las configuraciones de sensores
            let minTemp = currentMinTemp;
            let maxTemp = currentMaxTemp;
            let sensorCount = 0;

            if (activeSensors && activeSensors.length > 0 && Object.keys(sensorTempConfigs).length > 0) {
                const minTemps = [];
                const maxTemps = [];

                activeSensors.forEach(sensor => {
                    const config = sensorTempConfigs[sensor.id];
                    if (config) {
                        minTemps.push(config.min_temp);
                        maxTemps.push(config.max_temp);
                        sensorCount++;
                    }
                });

                if (minTemps.length > 0) {
                    minTemp = Math.min(...minTemps);
                    maxTemp = Math.max(...maxTemps);
                }
            }

            return { minTemp, maxTemp, sensorCount };
        }

        function updateGauge(temp, type, sensorLabel = null) {
            // type = 'max' or 'min'
            const isMax = (type === 'max');
            const minScale = 0;
            const maxScale = 100;
            const val = Math.max(minScale, Math.min(temp, maxScale));

            // Ratio calculation
            // 0 -> -90deg, 100 -> 90deg. Range = 180deg.
            const ratio = (val - minScale) / (maxScale - minScale);
            const degree = -90 + (ratio * 180);

            // IDs based on type (Max or Min)
            const suffix = isMax ? 'Max' : 'Min';

            // Update Needle con transición suave
            const needle = document.getElementById(`gaugeNeedle${suffix}`);
            if (needle) {
                needle.style.transition = 'transform 1s cubic-bezier(0.4, 0, 0.2, 1)';
                needle.setAttribute('transform', `rotate(${degree}, 50, 50)`);
            }

            // Update Text - mostrar valor y nombre del sensor
            const text = document.getElementById(`gaugeText${suffix}`);
            const sensorText = document.getElementById(`gaugeSensor${suffix}`);

            if (text) {
                text.textContent = temp.toFixed(0) + "°";
            }

            if (sensorText && sensorLabel) {
                sensorText.textContent = sensorLabel;
            }

            // Update Arc
            const path = document.getElementById(`gauge${suffix}Path`);
            if (path) {
                const totalLen = 126;
                const offset = totalLen - (totalLen * ratio);
                path.style.transition = 'stroke-dashoffset 1s cubic-bezier(0.4, 0, 0.2, 1)';
                path.style.strokeDashoffset = offset;
            }
        }

        // Variables para rotación automática de manómetros
        let gaugeRotationInterval = null;
        let currentGaugeIndex = { min: 0, max: 0 };
        const GAUGE_ROTATION_INTERVAL = 3000; // 3 segundos por sensor

        function getSensorsWithConfigs() {
            // Obtener lista de sensores con sus configuraciones
            const sensorsWithConfigs = [];

            if (activeSensors && activeSensors.length > 0) {
                activeSensors.forEach(sensor => {
                    const config = sensorTempConfigs[sensor.id];
                    if (config) {
                        sensorsWithConfigs.push({
                            id: sensor.id,
                            label: sensor.label || `Sensor ${sensor.id}`,
                            min_temp: config.min_temp,
                            max_temp: config.max_temp
                        });
                    }
                });
            }

            return sensorsWithConfigs;
        }

        function rotateGauge(type) {
            const sensors = getSensorsWithConfigs();

            if (sensors.length === 0) {
                // Si no hay sensores configurados, usar valores globales
                const defaultLabel = type === 'max' ? 'Global' : 'Global';
                updateGauge(
                    type === 'max' ? currentMaxTemp : currentMinTemp,
                    type,
                    defaultLabel
                );
                return;
            }

            // Rotar al siguiente sensor
            const index = currentGaugeIndex[type];
            const sensor = sensors[index];

            if (sensor) {
                const value = type === 'max' ? sensor.max_temp : sensor.min_temp;
                updateGauge(value, type, sensor.label);

                // Avanzar al siguiente sensor (cíclico)
                currentGaugeIndex[type] = (index + 1) % sensors.length;
            }
        }

        function startGaugeRotation() {
            // Detener rotación anterior si existe
            if (gaugeRotationInterval) {
                clearInterval(gaugeRotationInterval);
            }

            // Iniciar rotación para ambos manómetros
            const sensors = getSensorsWithConfigs();

            if (sensors.length > 0) {
                // Iniciar inmediatamente
                rotateGauge('min');
                rotateGauge('max');

                // Continuar rotando cada X segundos
                gaugeRotationInterval = setInterval(() => {
                    rotateGauge('min');
                    rotateGauge('max');
                }, GAUGE_ROTATION_INTERVAL);
            } else {
                // Si no hay sensores, mostrar valores globales
                updateGauge(currentMinTemp, 'min', 'Global');
                updateGauge(currentMaxTemp, 'max', 'Global');
            }
        }

        function stopGaugeRotation() {
            if (gaugeRotationInterval) {
                clearInterval(gaugeRotationInterval);
                gaugeRotationInterval = null;
            }
        }

        function updateGaugesFromSensorConfigs() {
            // Reiniciar rotación cuando se actualizan las configuraciones
            currentGaugeIndex = { min: 0, max: 0 };
            startGaugeRotation();
        }

        let sensorTempConfigs = {}; // Almacenar configuraciones por sensor

        async function loadSensorTempConfigs() {
            // Cargar configuraciones de temperatura por sensor
            try {
                const response = await fetch(`api/sensor_temperature_config.php?ship_id=${currentBuque}`);
                const data = await response.json();

                if (data.success && data.configs && data.configs.length > 0) {
                    sensorTempConfigs = {};
                    data.configs.forEach(config => {
                        sensorTempConfigs[config.sensor_id] = {
                            sensor_id: config.sensor_id,
                            sensor_label: config.sensor_label || config.display_label || `Sensor ${config.sensor_id}`,
                            max_temp: parseFloat(config.max_temp) || 27.00,
                            min_temp: parseFloat(config.min_temp) || -40.00
                        };
                    });

                    console.log('Configuraciones por sensor cargadas:', sensorTempConfigs);
                    // Actualizar manómetros con el rango dinámico
                    updateGaugesFromSensorConfigs();
                    return true;
                } else {
                    // Si no hay configuraciones pero hay sensores activos, crear defaults
                    if (activeSensors && activeSensors.length > 0) {
                        sensorTempConfigs = {};
                        activeSensors.forEach(sensor => {
                            sensorTempConfigs[sensor.id] = {
                                sensor_id: sensor.id,
                                sensor_label: sensor.label,
                                max_temp: currentMaxTemp,
                                min_temp: currentMinTemp
                            };
                        });
                        console.log('Configuraciones por sensor creadas desde defaults:', sensorTempConfigs);
                        // Actualizar manómetros con el rango dinámico
                        updateGaugesFromSensorConfigs();
                    }
                }
            } catch (e) {
                console.error('Error cargando configuraciones por sensor:', e);
                // Si hay error, crear defaults desde activeSensors
                if (activeSensors && activeSensors.length > 0) {
                    sensorTempConfigs = {};
                    activeSensors.forEach(sensor => {
                        sensorTempConfigs[sensor.id] = {
                            sensor_id: sensor.id,
                            sensor_label: sensor.label,
                            max_temp: currentMaxTemp,
                            min_temp: currentMinTemp
                        };
                    });
                    // Actualizar manómetros con el rango dinámico
                    updateGaugesFromSensorConfigs();
                }
            }
            return false;
        }

        async function openSettingsModal() {
            // Cargar configuraciones de temperatura por sensor
            try {
                const response = await fetch(`api/sensor_temperature_config.php?ship_id=${currentBuque}`);
                const data = await response.json();

                if (data.success && data.configs) {
                    sensorTempConfigs = {};
                    data.configs.forEach(config => {
                        sensorTempConfigs[config.sensor_id] = {
                            sensor_id: config.sensor_id,
                            sensor_label: config.sensor_label || config.display_label || `Sensor ${config.sensor_id}`,
                            max_temp: parseFloat(config.max_temp) || 27.00,
                            min_temp: parseFloat(config.min_temp) || -40.00
                        };
                    });

                    // Si no hay configuraciones, crear defaults desde activeSensors
                    if (Object.keys(sensorTempConfigs).length === 0 && activeSensors.length > 0) {
                        activeSensors.forEach(sensor => {
                            sensorTempConfigs[sensor.id] = {
                                sensor_id: sensor.id,
                                sensor_label: sensor.label,
                                max_temp: currentMaxTemp,
                                min_temp: currentMinTemp
                            };
                        });
                    }
                }
            } catch (e) {
                console.error('Error cargando configuraciones:', e);
                // Crear defaults desde activeSensors
                if (activeSensors.length > 0) {
                    activeSensors.forEach(sensor => {
                        sensorTempConfigs[sensor.id] = {
                            sensor_id: sensor.id,
                            sensor_label: sensor.label,
                            max_temp: currentMaxTemp,
                            min_temp: currentMinTemp
                        };
                    });
                }
            }

            // Renderizar el modal con las configuraciones
            renderSettingsModal();
            document.getElementById('settingsModal').style.display = 'flex';
        }

        function renderSettingsModal() {
            const container = document.getElementById('sensorConfigsContainer');
            if (!container) return;

            container.innerHTML = '';

            // Usar activeSensors como fuente de verdad para el orden y los nombres
            if (!activeSensors || activeSensors.length === 0) {
                container.innerHTML = '<p style="color: #888; text-align: center;">No hay sensores configurados</p>';
                return;
            }

            activeSensors.forEach(sensor => {
                // Buscar la configuración de límites (max/min) para este sensor
                const config = sensorTempConfigs[sensor.id] || {
                    max_temp: currentMaxTemp,
                    min_temp: currentMinTemp
                };

                const sensorDiv = document.createElement('div');
                sensorDiv.style.cssText = 'margin-bottom: 20px; padding: 15px; background: rgba(0, 242, 255, 0.05); border: 1px solid rgba(0, 242, 255, 0.2); border-radius: 8px;';
                sensorDiv.innerHTML = `
                    <div style="color: var(--cyan-glow); font-weight: 600; margin-bottom: 12px; font-size: 14px;">
                        ${sensor.label}
                    </div>
                    <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px;">
                        <div>
                            <label style="color: #fff; display: block; margin-bottom: 5px; font-size: 12px;">Temp. Máx (°C):</label>
                            <input type="number" step="0.1" 
                                   data-sensor-id="${sensor.id}" 
                                   data-type="max" 
                                   class="sensor-temp-input"
                                   value="${parseFloat(config.max_temp).toFixed(2)}"
                                   style="width: 100%; padding: 8px; background: #050a10; border: 1px solid var(--red-alert); color: #fff; font-size: 14px; text-align: center; border-radius: 4px;">
                        </div>
                        <div>
                            <label style="color: #fff; display: block; margin-bottom: 5px; font-size: 12px;">Temp. Mín (°C):</label>
                            <input type="number" step="0.1" 
                                   data-sensor-id="${sensor.id}" 
                                   data-type="min" 
                                   class="sensor-temp-input"
                                   value="${parseFloat(config.min_temp).toFixed(2)}"
                                   style="width: 100%; padding: 8px; background: #050a10; border: 1px solid var(--blue-safe); color: #fff; font-size: 14px; text-align: center; border-radius: 4px;">
                        </div>
                    </div>
                `;
                container.appendChild(sensorDiv);
            });
        }

        async function saveSettings() {
            // Recopilar todas las configuraciones de sensores
            const inputs = document.querySelectorAll('.sensor-temp-input');
            const configs = [];

            inputs.forEach(input => {
                const sensorId = parseInt(input.getAttribute('data-sensor-id'));
                const type = input.getAttribute('data-type');
                const value = parseFloat(input.value);

                if (isNaN(value)) return;

                let config = configs.find(c => c.sensor_id === sensorId);
                if (!config) {
                    const sensorLabel = activeSensors.find(s => s.id === sensorId)?.label || `Sensor ${sensorId}`;
                    const existingConfig = sensorTempConfigs[sensorId] || {};
                    config = {
                        sensor_id: sensorId,
                        sensor_label: sensorLabel, // Actualizar nombre basado en dashboard
                        max_temp: existingConfig.max_temp || currentMaxTemp,
                        min_temp: existingConfig.min_temp || currentMinTemp
                    };
                    configs.push(config);
                }

                if (type === 'max') {
                    config.max_temp = value;
                } else if (type === 'min') {
                    config.min_temp = value;
                }
            });

            if (configs.length === 0) {
                return showMessage('Atención', 'No hay sensores configurados', 'warning');
            }

            try {
                const res = await fetch('api/sensor_temperature_config.php', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        ship_id: currentBuque,
                        configs: configs
                    })
                });
                const data = await res.json();
                if (data.success) {
                    // Actualizar configuraciones locales
                    configs.forEach(config => {
                        sensorTempConfigs[config.sensor_id] = config;
                    });

                    // Actualizar manómetros con el nuevo rango
                    updateGaugesFromSensorConfigs();

                    // Actualizar valores globales para compatibilidad (promedio o primer sensor)
                    if (configs.length > 0) {
                        currentMaxTemp = configs[0].max_temp;
                        currentMinTemp = configs[0].min_temp;
                    }

                    document.getElementById('settingsModal').style.display = 'none';
                    showMessage('Éxito', 'Configuración guardada', 'success');
                    renderUI(); // Re-render to update alerts immediately
                    // Update gauges immediately
                    updateGauge(currentMaxTemp, 'max');
                    updateGauge(currentMinTemp, 'min');
                } else {
                    showMessage('Error', data.message, 'error-modal');
                }
            } catch (e) {
                console.error('Error guardando configuraciones:', e);
                showMessage('Error', 'Error de conexión', 'error-modal');
            }
        }

        async function loadConfig() {
            // Cargar configuración de alerta (Max Temp) - valores globales por defecto
            await loadShipSettings();

            // Primero intentar cargar del servidor (sincronización entre dispositivos)
            let loaded = await loadConfigFromServer();

            if (!loaded) {
                // Si no hay datos en el servidor, intentar localStorage
                const saved = localStorage.getItem(`config_${currentBuque}`);
                if (saved) {
                    activeSensors = JSON.parse(saved);
                    loaded = true;
                }
            }

            // --- DYNAMIC SENSOR LOADING ---
            // We no longer fallback to hardcoded 14 sensors. 
            // If server has no config, we start with an empty list (0 sensors)
            // or let the updateDashboard populate from 'ultima' if needed.
            if (!activeSensors || activeSensors.length === 0) {
                console.log("No se encontró configuración de sensores. El dashboard se mantendrá vacío hasta que se configuren sensores en el Panel Admin.");
                activeSensors = [];
                loaded = true; // Mark as loaded even if empty to avoid default loops
            }

            // Cargar configuraciones de temperatura por sensor DESPUÉS de tener activeSensors
            await loadSensorTempConfigs();

            renderUI();
        }

        let saveTimeout = null;

        function saveConfig() {
            // Guardar en localStorage para acceso rápido
            localStorage.setItem(`config_${currentBuque}`, JSON.stringify(activeSensors));

            // Guardar en servidor con debounce para evitar demasiadas peticiones
            clearTimeout(saveTimeout);
            saveTimeout = setTimeout(() => {
                saveConfigToServer();
            }, 300); // Esperar 300ms después del último cambio
        }

        async function saveConfigToServer() {
            try {
                const response = await fetch('api/sensor_positions.php', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        buque_id: currentBuque,
                        sensors: activeSensors
                    })
                });

                const result = await response.json();
                if (!result.success) {
                    console.error('Error al guardar config en servidor:', result.message);
                }
            } catch (error) {
                console.error('Error al guardar config en servidor:', error);
            }
        }


        async function loadConfigFromServer() {
            try {
                const response = await fetch(`api/sensor_positions.php?buque_id=${currentBuque}`);
                const result = await response.json();

                if (result.success && result.data && result.data.sensors && result.data.sensors.length > 0) {
                    // Convertir datos del servidor al formato esperado
                    activeSensors = result.data.sensors.map(s => ({
                        id: Number(s.id),
                        label: s.label || `SENSOR #${s.id}`,
                        x: s.x,
                        yTop: s.yTop,
                        ySide: s.ySide
                    }));
                    return true;
                }
            } catch (error) {
                console.error('Error al cargar config del servidor:', error);
            }
            return false;
        }

        // Sincronizar posiciones desde el servidor periódicamente
        async function syncPositionsFromServer() {
            // Evitar sincronizar si el usuario interactuó recientemente (5 segundos)
            // Esto permite que los cambios locales se guarden y propaguen antes de volver a leer
            if (Date.now() - lastUserInteraction < 5000) return;

            try {
                const response = await fetch(`api/sensor_positions.php?buque_id=${currentBuque}`);
                const result = await response.json();

                if (result.success && result.data && result.data.sensors && result.data.sensors.length > 0) {
                    let hasChanges = false;

                    // Comparar y actualizar solo si hay cambios
                    result.data.sensors.forEach(serverSensor => {
                        const sId = Number(serverSensor.id);
                        const localSensor = activeSensors.find(s => s.id === sId);

                        if (localSensor) {
                            // Verificar si hay diferencias
                            if (localSensor.x !== serverSensor.x ||
                                localSensor.yTop !== serverSensor.yTop ||
                                localSensor.ySide !== serverSensor.ySide ||
                                (localSensor.label !== serverSensor.label && serverSensor.label)) {
                                hasChanges = true;
                                localSensor.x = serverSensor.x;
                                localSensor.yTop = serverSensor.yTop;
                                localSensor.ySide = serverSensor.ySide;
                                if (serverSensor.label) localSensor.label = serverSensor.label;
                            }
                        } else {
                            // Sensor nuevo en el servidor
                            hasChanges = true;
                            activeSensors.push({
                                id: sId,
                                label: serverSensor.label || `SENSOR #${sId}`,
                                x: serverSensor.x,
                                yTop: serverSensor.yTop,
                                ySide: serverSensor.ySide
                            });
                        }
                    });

                    // Si hubo cambios, actualizar la UI
                    if (hasChanges) {
                        // Actualizar localStorage
                        localStorage.setItem(`config_${currentBuque}`, JSON.stringify(activeSensors));
                        // Recalcular posiciones de marcadores
                        recalculateMarkerPositions();
                        // Actualizar labels si cambiaron (solo 'side' ahora)
                        activeSensors.forEach(s => {
                            const labelEl = document.getElementById(`mLabel-side-${s.id}`);
                            if (labelEl) labelEl.textContent = s.label;
                        });
                    }
                }
            } catch (error) {
                console.error('Error al sincronizar posiciones:', error);
            }
        }

        function renderUI() {
            const grid = document.getElementById('metricsGrid');
            const map = document.getElementById('markersLayer');

            // --- ROLE CHECK FOR ADMIN ACTIONS ---
            const isAdmin = <?php echo json_encode(($_SESSION['role'] ?? '') === 'admin' || ($_SESSION['role'] ?? '') === 'sub-adm'); ?>;

            grid.innerHTML = ''; // Limpiar grid (IMPORTANTE)
            map.innerHTML = '';

            activeSensors.forEach(s => {
                const card = document.createElement('div');
                card.className = 'metric-card';
                card.id = `card${s.id}`;

                // Eliminamos botón de borrado (Solicitud de Usuario)
                // const deleteBtn = isAdmin ? `<button class="delete-btn" onclick="removeSensor(${s.id})">🗑️</button>` : '';

                card.innerHTML = `
                    <div class="card-meta">
                        <span class="ip-meta" id="ip${s.id}">IP: --</span>
                        <span class="time-meta" id="time${s.id}">--:--:--</span>
                    </div>
                    <input class="editable-label" value="${s.label}" readonly 
                        ${isAdmin ? `onclick="openRenameModal(${s.id}, '${s.label}')"` : ''} 
                        style="${isAdmin ? 'cursor: pointer;' : 'cursor: default;'}"
                        spellcheck="false" title="${isAdmin ? 'Click para renombrar' : ''}">
                    <div class="metric-value">
                        <span id="temp${s.id}">--</span>
                        <span class="metric-unit">°C</span>
                    </div>
                `;
                grid.appendChild(card);

                // Solo crear un marcador 'side' (amarillo) por sensor
                createMarker(s, 'side', map, isAdmin);
            });

            if (mainChart) updateChartDatasets();
            // Aplicar datos solo después de asegurar que las configuraciones están cargadas
            if (lastData) {
                // Asegurar que las configuraciones por sensor estén cargadas antes de aplicar
                if (Object.keys(sensorTempConfigs).length === 0) {
                    // Cargar configuraciones de forma síncrona antes de aplicar
                    loadSensorTempConfigs().then(() => {
                        applyData(lastData);
                    });
                } else {
                    applyData(lastData);
                }
            }
            setTimeout(() => recalculateMarkerPositions(), 100);
        }

        function createMarker(s, type, container, isAdmin) {
            const marker = document.createElement('div');
            marker.className = `sensor-marker m${s.id} marker-${type}`;
            marker.id = `marker-${type}-${s.id}`;

            marker.onclick = (e) => {
                e.stopPropagation();
                highlightSensor(s.id);
            };

            marker.style.position = 'absolute';
            marker.style.zIndex = '100';

            updateMarkerPosition(marker, s, type);

            // Permitir drag si es admin o sub-adm
            if (isAdmin) {
                const onStart = (e) => {
                    startDrag(e, s.id, type);
                };
                marker.addEventListener('mousedown', onStart);
                marker.addEventListener('touchstart', onStart, { passive: false });
                marker.style.cursor = 'move';
            } else {
                marker.style.cursor = 'pointer';
            }

            marker.innerHTML = `
                <span class="marker-label" id="mLabel-${type}-${s.id}">${s.label}</span>
                <span class="marker-temp" id="mTemp-${type}-${s.id}">--°C</span>
                <div class="marker-connector" id="mConnector-${type}-${s.id}"></div>
                <div class="radar-pulse" id="radarPulse-${type}-${s.id}" style="display: block;">
                    <div class="radar-ring ring-1"></div>
                    <div class="radar-ring ring-2"></div>
                    <div class="radar-ring ring-3"></div>
                </div>
            `;
            container.appendChild(marker);
        }

        function updateMarkerPosition(marker, sensor, type) {
            // Los marcadores usan porcentajes relativos al contenedor (markersLayer)
            // Ya no redimensionamos el contenedor aquí para evitar saltos y errores de cálculo

            // Aplicar posición usando porcentajes directos
            // Solo usamos ySide ya que ahora solo hay marcadores 'side'
            marker.style.position = 'absolute';
            marker.style.left = sensor.x;
            marker.style.top = sensor.ySide;
            marker.style.transform = 'translate(-50%, -50%)';
            marker.style.margin = '0';
            marker.style.padding = '0';
            marker.style.zIndex = '100';
            marker.style.pointerEvents = 'auto';

            // Resetear el offset del label
            const labelEl = marker.querySelector('.marker-label');
            const connectorEl = marker.querySelector('.marker-connector');
            if (labelEl) {
                labelEl.style.transform = 'translateX(-50%)';
                labelEl.style.bottom = 'calc(100% + 4px)';
                labelEl.style.left = '50%';
            }
            if (connectorEl) {
                connectorEl.style.display = 'none';
            }
        }

        // Función para ajustar las etiquetas de los marcadores cuando se solapan
        function adjustMarkerLabels() {
            const markers = [];
            const container = document.getElementById('mapContainer');
            if (!container) return;

            // Obtener todos los marcadores (solo 'side' ahora)
            activeSensors.forEach(s => {
                const marker = document.getElementById(`marker-side-${s.id}`);
                if (marker) {
                    const rect = marker.getBoundingClientRect();
                    const containerRect = container.getBoundingClientRect();
                    const label = marker.querySelector('.marker-label');

                    if (!label) return;

                    // Obtener el rect del label (puede estar desplazado)
                    const labelRect = label.getBoundingClientRect();

                    // Calcular posición relativa al contenedor
                    const x = rect.left - containerRect.left + rect.width / 2;
                    const y = rect.top - containerRect.top + rect.height / 2;

                    markers.push({
                        id: s.id,
                        marker: marker,
                        x: x,
                        y: y,
                        rect: rect,
                        label: label,
                        labelRect: labelRect,
                        currentOffset: 0 // Offset actual del label
                    });
                }
            });

            // Detectar colisiones y ajustar
            const threshold = 120; // Distancia mínima en píxeles horizontal para considerar colisión
            const labelHeight = 28; // Altura aproximada del label con padding
            const minSpacing = 40; // Espaciado mínimo entre labels

            // Ordenar marcadores por posición Y (de arriba a abajo)
            markers.sort((a, b) => a.y - b.y);

            // Primero, resetear todos los offsets
            markers.forEach(m => {
                m.currentOffset = 0;
                if (m.label) {
                    m.label.style.transform = 'translateX(-50%)';
                    m.label.style.marginTop = '0';
                }
            });

            // Calcular offsets para cada marcador (iterar varias veces para ajustes en cascada)
            for (let iteration = 0; iteration < 3; iteration++) {
                markers.forEach((marker1, i) => {
                    if (!marker1.label) return;

                    let maxOffset = marker1.currentOffset || 0;

                    // Revisar todos los marcadores anteriores (arriba)
                    for (let j = 0; j < i; j++) {
                        const marker2 = markers[j];
                        if (!marker2.label) continue;

                        // Calcular distancia horizontal
                        const dx = Math.abs(marker1.x - marker2.x);

                        // Si están cerca horizontalmente (misma columna o columnas adyacentes)
                        if (dx < threshold) {
                            // Obtener el offset actual del marker2
                            const marker2Offset = marker2.currentOffset || 0;

                            // Calcular la posición Y del label de marker2 (arriba)
                            // El label está arriba del marcador, así que restamos
                            const marker2LabelBottom = marker2.y - marker2Offset - labelHeight;

                            // Calcular la posición Y del label de marker1 (abajo)
                            const marker1LabelTop = marker1.y - (marker1.currentOffset || 0);

                            // Si los labels se solapan o están muy cerca
                            const spacing = marker1LabelTop - marker2LabelBottom;
                            if (spacing < minSpacing) {
                                // Calcular cuánto necesita moverse marker1 hacia arriba
                                const neededOffset = (marker1.currentOffset || 0) + (minSpacing - spacing);
                                maxOffset = Math.max(maxOffset, neededOffset);
                            }
                        }
                    }

                    // Actualizar el offset
                    marker1.currentOffset = maxOffset;
                });
            }

            // Aplicar los offsets calculados y mostrar/ocultar conectores
            markers.forEach(marker => {
                if (!marker.label) return;

                const connector = marker.marker.querySelector('.marker-connector');
                const totalOffset = marker.currentOffset + labelHeight;

                if (marker.currentOffset > 0) {
                    marker.label.style.transform = 'translateX(-50%) translateY(-' + totalOffset + 'px)';
                    marker.label.style.marginTop = '0';

                    // Mostrar y configurar el conector
                    if (connector) {
                        connector.style.display = 'block';
                        connector.style.height = totalOffset + 'px';
                        connector.style.top = '0';
                        connector.style.left = '50%';
                        connector.style.transform = 'translateX(-50%)';
                    }
                } else {
                    marker.label.style.transform = 'translateX(-50%)';
                    marker.label.style.marginTop = '0';

                    // Ocultar el conector
                    if (connector) {
                        connector.style.display = 'none';
                    }
                }
            });
        }

        // Recalcular posiciones cuando cambia el tamaño de la ventana o entra en pantalla completa
        function recalculateMarkerPositions() {
            const img = document.getElementById('shipImg');
            const container = document.getElementById('mapContainer');
            const markersLayer = document.getElementById('markersLayer');

            if (!img || !container || !markersLayer) return;

            // --- REPAIR: Reset inline styles to allow image to scale naturally before measuring ---
            container.style.width = '';
            container.style.height = '';
            markersLayer.style.width = '';
            markersLayer.style.height = '';

            // Esperar si la imagen no ha cargado
            if (!img.complete || img.naturalWidth === 0) {
                return; // ResizeObserver cuidará de esto cuando cargue
            }

            // OBTENER DIMENSIONES REALES DE VISUALIZACIÓN
            // Usamos offsetWidth/Height para evitar problemas con transformaciones o scroll
            const width = img.offsetWidth;
            const height = img.offsetHeight;

            if (width > 0 && height > 0) {
                // Sincronizar contenedor y capa de marcadores con la imagen EXACTAMENTE
                container.style.width = width + 'px';
                container.style.height = height + 'px';
                markersLayer.style.width = width + 'px';
                markersLayer.style.height = height + 'px';

                // Asegurar posicionamiento absoluto base
                markersLayer.style.position = 'absolute';
                markersLayer.style.top = '0';
                markersLayer.style.left = '0';
            }

            // Reposicionar todos los marcadores (solo 'side' ahora)
            activeSensors.forEach(s => {
                const marker = document.getElementById(`marker-side-${s.id}`);
                if (marker) {
                    updateMarkerPosition(marker, s, 'side');
                }
            });

            // Verificar alarmas globales después de procesar todos
            checkGlobalAlarm();
        }

        // Escuchar cambios de tamaño y pantalla completa
        let resizeTimeout;
        window.addEventListener('resize', () => {
            clearTimeout(resizeTimeout);
            resizeTimeout = setTimeout(recalculateMarkerPositions, 150);
        });

        document.addEventListener('fullscreenchange', updateFullscreenButton);
        document.addEventListener('webkitfullscreenchange', updateFullscreenButton);
        document.addEventListener('msfullscreenchange', updateFullscreenButton);

        // Listen for internal fullscreen resizing
        document.addEventListener('fullscreenchange', () => { setTimeout(recalculateMarkerPositions, 300); });
        document.addEventListener('webkitfullscreenchange', () => { setTimeout(recalculateMarkerPositions, 300); });

        // Recalcular cuando la imagen se carga
        const shipImg = document.getElementById('shipImg');
        if (shipImg) {
            shipImg.addEventListener('load', () => {
                setTimeout(recalculateMarkerPositions, 100);
            });
        }

        // Recalcular cuando la imagen cambia de tamaño (útil en pantalla completa)
        if (shipImg) {
            const resizeObserver = new ResizeObserver(() => {
                setTimeout(recalculateMarkerPositions, 100);
            });
            resizeObserver.observe(shipImg);
        }

        function applyData(data) {
            if (!data.ultima) return;
            activeSensors.forEach(s => {
                // MODIFICACIÓN DE PRECISIÓN DE DECIMALES
                const rawVal = data.ultima[`temp${s.id}`];
                const tEl = document.getElementById(`temp${s.id}`);

                if (tEl) {
                    if (rawVal != null && rawVal !== "") {
                        // Forzamos parseFloat para asegurar que JS no redondee automáticamente si viene como string
                        tEl.textContent = parseFloat(rawVal).toFixed(2);
                    } else {
                        tEl.textContent = '--';
                    }
                }

                const ipEl = document.getElementById(`ip${s.id}`);
                const timeEl = document.getElementById(`time${s.id}`);
                if (ipEl) ipEl.style.display = 'none'; // Hide the Origin IP completely
                if (timeEl) {
                    const d = new Date(data.ultima.fecha);
                    timeEl.textContent = d.toLocaleTimeString('es-AR', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
                }

                // Verificar si la temperatura supera el umbral dinámico para activar alerta
                // Usar configuración por sensor si existe, sino usar global
                const sensorConfig = sensorTempConfigs[s.id];
                const tempThreshold = sensorConfig ? sensorConfig.max_temp : currentMaxTemp;
                const tempMinThreshold = sensorConfig ? sensorConfig.min_temp : currentMinTemp;
                const valNum = rawVal != null ? parseFloat(rawVal) : null;
                const isHighTemp = valNum != null && valNum > tempThreshold;
                const isLowTemp = valNum != null && valNum < tempMinThreshold;
                s.isHighTemp = isHighTemp; // Store status logic
                s.isLowTemp = isLowTemp; // Store low temp status

                // Aplicar alerta a los marcadores del mapa y mostrar/ocultar labels (solo 'side' ahora)
                const type = 'side';
                const mEl = document.getElementById(`mTemp-${type}-${s.id}`);
                const labelEl = document.getElementById(`mLabel-${type}-${s.id}`);
                const markerEl = document.getElementById(`marker-${type}-${s.id}`);

                if (mEl) mEl.textContent = valNum != null ? `${valNum.toFixed(2)}°C` : '--°C';

                // Mostrar/ocultar labels según la temperatura
                if (markerEl) {
                    const radarPulse = document.getElementById(`radarPulse-${type}-${s.id}`);

                    if (isHighTemp) {
                        // Mostrar labels cuando hay alerta de temperatura alta
                        markerEl.classList.add('alert-high-temp');
                        if (radarPulse) radarPulse.style.display = 'none'; // Ocultar radar en alerta
                        if (labelEl) {
                            labelEl.style.display = 'block';
                            labelEl.style.opacity = '1';
                        }
                        if (mEl) {
                            mEl.style.display = 'block';
                            mEl.style.opacity = '1';
                        }
                    } else {
                        // Ocultar labels cuando la temperatura es normal y mostrar radar
                        markerEl.classList.remove('alert-high-temp');
                        if (radarPulse) radarPulse.style.display = 'block'; // Mostrar radar en estado normal
                        if (labelEl) {
                            labelEl.style.display = 'none';
                            labelEl.style.opacity = '0';
                        }
                        if (mEl) {
                            mEl.style.display = 'none';
                            mEl.style.opacity = '0';
                        }
                    }
                }

                // Aplicar alerta a la card
                const card = document.getElementById(`card${s.id}`);
                if (card && valNum != null) {
                    if (isHighTemp) {
                        // Temperatura alta: parpadeo de alerta
                        card.classList.add('alert-high-temp');
                        card.style.borderLeft = '6px solid var(--red-alert)';
                    } else {
                        // Temperatura normal
                        card.classList.remove('alert-high-temp');
                        card.style.borderLeft = ''; // Volver al estilo CSS por defecto (Cyan)
                    }
                } else if (card) {
                    // Si no hay valor, quitar alerta
                    card.classList.remove('alert-high-temp');
                }
            });
        }

        function addSensor() {
            if (activeSensors.length >= 16) {
                alert("Límite de sensores alcanzado (16)");
                return;
            }
            const usedIds = activeSensors.map(s => s.id);
            let nextId = 1;
            while (usedIds.includes(nextId)) nextId++;

            activeSensors.push({
                id: nextId,
                label: `SENSOR #${nextId}`,
                x: '50%',
                yTop: '23%',
                ySide: '76%'
            });
            saveConfig();
            renderUI();
        }

        /*
        function removeSensor(id) {
            if (!confirm("¿Eliminar este sensor?")) return;
            activeSensors = activeSensors.filter(s => s.id !== id);
            saveConfig();
            renderUI();
        }
        */

        // --- RENAME MODAL LOGIC ---
        let renameTargetId = null;

        function openRenameModal(id, currentName) {
            renameTargetId = id;
            const input = document.getElementById('renameInput');
            input.value = currentName;

            const modal = document.getElementById('renameModal');
            modal.style.display = 'flex';

            // Focus input after a short delay to allow transition
            setTimeout(() => input.focus(), 100);
        }

        function closeRenameModal() {
            document.getElementById('renameModal').style.display = 'none';
            renameTargetId = null;
        }

        function confirmRename() {
            if (renameTargetId === null) return;

            const input = document.getElementById('renameInput');
            const newName = input.value.trim();

            if (newName) {
                updateLabel(renameTargetId, newName);
                closeRenameModal();
            } else {
                alert("El nombre no puede estar vacío");
            }
        }

        // Allow Enter key to confirm
        document.addEventListener('DOMContentLoaded', () => {
            const renameInput = document.getElementById('renameInput');
            if (renameInput) {
                renameInput.addEventListener('keyup', function (event) {
                    if (event.key === 'Enter') confirmRename();
                });
            }
        });

        // Variable to track user interaction and pause sync temporarily
        let lastUserInteraction = 0;

        function updateLabel(id, newLabel) {
            const sensor = activeSensors.find(s => s.id === id);
            if (sensor) {
                sensor.label = newLabel;
                lastUserInteraction = Date.now(); // Mark interaction

                // Update marker label (solo 'side' ahora)
                const sideLabel = document.getElementById(`mLabel-side-${id}`);
                if (sideLabel) sideLabel.textContent = newLabel;

                // Update card input immediately
                const cardInput = document.querySelector(`#card${id} .editable-label`);
                if (cardInput) {
                    cardInput.value = newLabel;
                    // Update the onclick handler to reflect the new current name
                    cardInput.onclick = () => openRenameModal(id, newLabel);
                }

                saveConfig();
            }
        }

        // --- DUAL-AXIS DRAG AND DROP ---

        function startDrag(e, id, type) {
            if (isLocked) return;
            lastUserInteraction = Date.now(); // Pause sync while dragging
            activeMarker = { id: id, type: type, element: document.getElementById(`marker-${type}-${id}`) };
            e.preventDefault(); // Block selection and context menus
        }

        function handleMove(e) {
            if (!activeMarker) return;

            // Handle both touch and mouse
            const clientX = (e.touches && e.touches.length > 0) ? e.touches[0].clientX : e.clientX;
            const clientY = (e.touches && e.touches.length > 0) ? e.touches[0].clientY : e.clientY;

            // Prevent scrolling on mobile while dragging
            if (e.type === 'touchmove') e.preventDefault();

            const container = document.getElementById('mapContainer');
            const img = document.getElementById('shipImg');

            if (!container || !img) return;

            // Asegurar que el contenedor tenga el tamaño de la imagen antes de calcular
            const imgRect = img.getBoundingClientRect();
            container.style.width = imgRect.width + 'px';
            container.style.height = imgRect.height + 'px';

            // Calcular posición relativa al contenedor (que ahora tiene el tamaño de la imagen)
            const containerRect = container.getBoundingClientRect();

            let x = ((clientX - containerRect.left) / containerRect.width) * 100;
            let y = ((clientY - containerRect.top) / containerRect.height) * 100;

            x = Math.max(0, Math.min(100, x));
            y = Math.max(0, Math.min(100, y));

            const sensor = activeSensors.find(s => s.id === activeMarker.id);
            if (!sensor) return;

            sensor.x = `${x.toFixed(2)}%`;
            // Solo guardar en ySide ya que ahora solo hay marcadores 'side'
            sensor.ySide = `${y.toFixed(2)}%`;

            // Actualizar posición del marcador
            const sideEl = document.getElementById(`marker-side-${sensor.id}`);
            if (sideEl) {
                updateMarkerPosition(sideEl, sensor, 'side');
            }

            // Guardar durante el movimiento para sincronización en tiempo real
            saveConfig();
        }

        document.addEventListener('mousemove', handleMove);
        document.addEventListener('touchmove', handleMove, { passive: false });

        const endDrag = () => {
            if (activeMarker) {
                saveConfig();
                activeMarker = null;
            }
        };

        document.addEventListener('mouseup', endDrag);
        document.addEventListener('touchend', endDrag);

        function toggleLock() {
            isLocked = !isLocked;
            const btn = document.getElementById('lockToggle');
            btn.textContent = isLocked ? '🔒' : '🔓';
            btn.style.background = isLocked ? 'var(--red-alert)' : 'var(--cyan-glow)';
            document.getElementById('mapContainer').style.cursor = isLocked ? 'default' : 'crosshair';
        }

        function toggleFullscreen() {
            const shipVisualizer = document.querySelector('.ship-visualizer');
            const isFullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement || document.msFullscreenElement);

            if (!isFullscreen) {
                // Entrar en pantalla completa
                const requestFullscreen = shipVisualizer.requestFullscreen ||
                    shipVisualizer.webkitRequestFullscreen ||
                    shipVisualizer.mozRequestFullScreen ||
                    shipVisualizer.msRequestFullscreen;

                if (requestFullscreen) {
                    requestFullscreen.call(shipVisualizer).then(() => {
                        if (screen.orientation && screen.orientation.lock) {
                            screen.orientation.lock('landscape').catch(() => { });
                        }
                    }).catch(() => { });
                }
            } else {
                // Salir de pantalla completa
                const exitFullscreen = document.exitFullscreen ||
                    document.webkitExitFullscreen ||
                    document.mozCancelFullScreen ||
                    document.msExitFullscreen;

                if (exitFullscreen) {
                    exitFullscreen.call(document);
                }
            }
        }

        function updateFullscreenButton() {
            const btn = document.getElementById('fullscreenBtn');
            const isFullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement || document.msFullscreenElement);
            if (btn) btn.textContent = isFullscreen ? '⛶' : '⛶';
        }

        function toggleChartFullscreen() {
            const chartContainer = document.querySelector('.chart-container-wrapper');
            const isFullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement || document.msFullscreenElement);

            if (!isFullscreen) {
                const requestFullscreen = chartContainer.requestFullscreen ||
                    chartContainer.webkitRequestFullscreen ||
                    chartContainer.mozRequestFullScreen ||
                    chartContainer.msRequestFullscreen;

                if (requestFullscreen) {
                    requestFullscreen.call(chartContainer).then(() => {
                        if (screen.orientation && screen.orientation.lock) {
                            screen.orientation.lock('landscape').catch(() => { });
                        }
                    }).catch(() => { });
                }
            } else {
                const exitFullscreen = document.exitFullscreen ||
                    document.webkitExitFullscreen ||
                    document.mozCancelFullScreen ||
                    document.msExitFullscreen;

                if (exitFullscreen) {
                    exitFullscreen.call(document);
                }
            }
        }

        // --- CHARTING & UPDATES ---

        const sensorColors = [
            '#00f2ff', '#ff00ff', '#ffff00', '#00ff00', '#ff8000',
            '#ff0000', '#8000ff', '#0080ff', '#ff0080', '#00ff80',
            '#ffffff', '#bcbcbc', '#ffcc00', '#99ccff', '#ff99cc', '#ccff99'
        ];

        function updateChartDatasets() {
            mainChart.data.datasets = activeSensors.map((s, idx) => ({
                label: s.label,
                data: [],
                borderColor: sensorColors[idx % sensorColors.length],
                tension: 0.1, // Líneas más simples = Renderizado más rápido
                borderWidth: 1.5,
                pointRadius: 3, // Puntos más grandes y visibles para interactuar
                pointHitRadius: 15, // Área de contacto ampliada
                pointHoverRadius: 8,
                spanGaps: true,
                hidden: false,
                normalized: true, // Optimización para datos ordenados
                stepped: false,
                fill: false
            }));
            mainChart.update('none'); // Actualización instantánea sin animación
            generateCustomLegend();
        }

        function initChart() {
            const ctx = document.getElementById('coldChainChart').getContext('2d');
            mainChart = new Chart(ctx, {
                type: 'line',
                data: { labels: [], datasets: [] },
                plugins: [{
                    id: 'nowLine',
                    afterDraw: (chart) => {
                        const xAxis = chart.scales.x;
                        if (!xAxis) return;
                        const x = xAxis.getPixelForValue(new Date());
                        if (x < chart.chartArea.left || x > chart.chartArea.right) return;

                        const ctx = chart.ctx;
                        ctx.save();
                        ctx.beginPath();
                        ctx.strokeStyle = 'rgba(0, 242, 255, 0.5)';
                        ctx.lineWidth = 3;
                        ctx.moveTo(x, chart.chartArea.top);
                        ctx.lineTo(x, chart.chartArea.bottom);
                        ctx.stroke();

                        ctx.beginPath();
                        ctx.strokeStyle = '#00f2ff';
                        ctx.setLineDash([5, 5]);
                        ctx.lineWidth = 1;
                        ctx.moveTo(x, chart.chartArea.top);
                        ctx.lineTo(x, chart.chartArea.bottom);
                        ctx.stroke();

                        ctx.fillStyle = '#00f2ff';
                        ctx.font = 'bold 10px Inter, sans-serif';
                        ctx.textAlign = 'center';
                        ctx.shadowBlur = 10;
                        ctx.shadowColor = 'rgba(0, 242, 255, 0.8)';
                        ctx.fillText('• AHORA •', x, chart.chartArea.top - 12);
                        ctx.restore();
                    }
                }],
                options: {
                    animation: false, // Desactivar animaciones generales para fluidez
                    responsive: true,
                    maintainAspectRatio: false,
                    resizeDelay: 200,
                    parsing: false, // Optimización crítica: ya pre-procesamos los datos
                    layout: {
                        padding: { top: 20, bottom: 10, left: 10, right: 60 }
                    },
                    plugins: {
                        legend: { display: false },
                        tooltip: {
                            mode: 'index',
                            intersect: false,
                            backgroundColor: 'rgba(5, 10, 16, 0.9)',
                            titleColor: '#00f2ff',
                            borderColor: 'rgba(0, 242, 255, 0.3)',
                            borderWidth: 1,
                            padding: 12,
                            cornerRadius: 8
                        },
                        zoom: {
                            pan: { enabled: true, mode: 'x', threshold: 10 },
                            zoom: { wheel: { enabled: true }, pinch: { enabled: true }, mode: 'x' }
                        }
                    },
                    interaction: { mode: 'nearest', axis: 'x', intersect: false },
                    scales: {
                        x: {
                            type: 'time',
                            time: { unit: 'hour', displayFormats: { hour: 'HH:mm', minute: 'HH:mm:ss' } },
                            ticks: { color: '#8892b0', font: { size: 10 }, maxTicksLimit: 12, autoSkip: true },
                            grid: { color: 'rgba(255,255,255,0.03)' }
                        },
                        y: {
                            ticks: { color: '#8892b0', callback: (v) => v + '°' },
                            grid: { color: 'rgba(255,255,255,0.03)' }
                        }
                    }
                }
            });
        }

        function generateCustomLegend() {
            const legendContainer = document.getElementById('customLegend');
            legendContainer.innerHTML = '';

            if (!mainChart || !mainChart.data || !mainChart.data.datasets) return;

            // Check if there are ANY datasets with Data to show the ALL button
            let hasAnyData = false;

            // First determine which datasets have data
            const datasetsWithData = mainChart.data.datasets.map((ds, index) => {
                const sensor = activeSensors[index];

                // If there's no data at all yet, assume no data
                if (!lastData || !lastData.ultima || !sensor) return { display: false, hasData: false };

                const val = lastData.ultima[`temp${sensor.id}`];
                const hasData = (val !== null && val !== "" && val !== undefined);

                if (hasData) hasAnyData = true;

                return { display: hasData, ds, index };
            });

            // Only show the ALL button if there's actual data to toggle
            if (hasAnyData) {
                const allBtn = document.createElement('button');
                allBtn.className = 'legend-btn';
                allBtn.style.borderColor = '#ffffff';
                allBtn.style.color = '#ffffff';
                allBtn.style.fontWeight = 'bold';
                allBtn.innerText = 'ALL';
                allBtn.title = "Mostrar todos los sensores activos";

                allBtn.onclick = () => {
                    const allVisible = !datasetsWithData.filter(d => d.display).some(d => d.ds.hidden);

                    if (allVisible) {
                        // Ocultar todos los activos
                        datasetsWithData.filter(d => d.display).forEach(d => {
                            d.ds.hidden = true;
                        });
                    } else {
                        // Mostrar todos los activos
                        datasetsWithData.filter(d => d.display).forEach(d => {
                            d.ds.hidden = false;
                        });
                    }

                    mainChart.update();
                    generateCustomLegend(); // Regenerar para reflejar cambios visuales
                };
                legendContainer.appendChild(allBtn);
            }

            // Mapear botones solo para los sensores que TENGAN DATOS
            datasetsWithData.forEach(item => {
                if (!item.display) return; // SKIP IF NO DATA

                const dataset = item.ds;
                const index = item.index;

                const btn = document.createElement('button');
                btn.className = `legend-btn ${dataset.hidden ? 'inactive' : ''}`;

                if (dataset.hidden) {
                    btn.style.borderColor = '#555';
                    btn.style.color = '#555';
                    btn.style.opacity = '0.5';
                } else {
                    btn.style.borderColor = dataset.borderColor;
                    btn.style.color = dataset.borderColor;
                    btn.style.opacity = '1';
                }

                btn.innerText = dataset.label;

                btn.onclick = () => {
                    const meta = mainChart.getDatasetMeta(index);
                    meta.hidden = meta.hidden === null ? !mainChart.data.datasets[index].hidden : null;
                    mainChart.data.datasets[index].hidden = !mainChart.data.datasets[index].hidden;

                    mainChart.update();
                    generateCustomLegend();
                };

                legendContainer.appendChild(btn);
            });
        }


        let isFirstLoad = true;

        function updateChartWindow() {
            if (!mainChart) return;
            if (typeof mainChart.isZoomedOrPanned === 'function' && mainChart.isZoomedOrPanned()) return;

            const now = new Date();
            const twentyFourHoursAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
            const maxTime = new Date(now.getTime() + 2 * 60 * 1000);

            mainChart.options.scales.x.min = twentyFourHoursAgo;
            mainChart.options.scales.x.max = maxTime;

            mainChart.update('none'); // Update without animation for performance
        }

        // Intervalo independiente para mover la línea de "AHORA" y la ventana del gráfico cada segundo
        // Esto hace que el gráfico se sienta vivo y fluido independientemente de la carga de datos
        setInterval(() => {
            if (!isFirstLoad) {
                updateChartWindow();
            }
        }, 1000);

        function zoomIn() { if (mainChart) mainChart.zoom(1.1); }
        function zoomOut() { if (mainChart) mainChart.zoom(0.9); }
        function resetZoom() { if (mainChart) { mainChart.resetZoom(); updateChartWindow(); } }



        async function updateDashboard() {
            if (isFirstLoad) {
                const overlay = document.getElementById('chartLoadingOverlay');
                if (overlay) overlay.classList.remove('hidden');
            }

            try {
                const response = await fetch(`api/dashboard_data.php?buque_id=${currentBuque}`);
                const result = await response.json();

                if (result.success) {
                    lastData = result.data;
                    updateUIStatus(true);

                    const sel = document.getElementById('shipSelector');
                    if (lastData.lista_buques && sel.options.length <= 1) {
                        sel.innerHTML = lastData.lista_buques.map(b => {
                            // Support new object format {ship_id, name} or fallback to old string format
                            const id = typeof b === 'object' ? b.ship_id : b;
                            const name = typeof b === 'object' ? b.name : b;
                            return `<option value="${id}" ${id === currentBuque ? 'selected' : ''}>${name}</option>`;
                        }).join('');
                    }

                    // Aplicar datos solo después de asegurar que las configuraciones están cargadas
                    // Si sensorTempConfigs está vacío, cargarlo primero
                    if (Object.keys(sensorTempConfigs).length === 0) {
                        await loadSensorTempConfigs();
                    }
                    applyData(lastData);
                    checkGlobalAlarm();

                    if (lastData.historial && lastData.historial.length > 0) {
                        const now = new Date();
                        const ACTIVITY_THRESHOLD = 5 * 60 * 1000; // 5 minutos

                        // Optimización: Parsear fechas UNA sola vez para todos los sensores
                        const parsedHistorial = lastData.historial.map(h => ({
                            date: new Date(h.fecha),
                            raw: h
                        }));

                        mainChart.data.datasets.forEach((dataset, idx) => {
                            const sensor = activeSensors[idx];
                            if (sensor) {
                                const prop = `temp${sensor.id}`;
                                const sensorData = [];

                                for (let i = 0; i < parsedHistorial.length; i++) {
                                    const val = parsedHistorial[i].raw[prop];
                                    if (val !== null && val !== "" && val !== undefined) {
                                        sensorData.push({
                                            x: parsedHistorial[i].date,
                                            y: parseFloat(val)
                                        });
                                    }
                                }

                                dataset.data = sensorData;
                                dataset.fill = false;

                                // Detener la línea si no hay datos recientes
                                if (sensorData.length > 0) {
                                    const lastPointDate = sensorData[sensorData.length - 1].x;
                                    const timeDiff = now - lastPointDate;

                                    if (timeDiff > ACTIVITY_THRESHOLD) {
                                        dataset.spanGaps = false; // El sensor dejó de reportar, mostrar hueco
                                    } else {
                                        dataset.spanGaps = true; // Mantener línea continua mientras esté activo
                                    }
                                }

                                // Lógica de Estado Inicial de la Leyenda (Solo en primera carga)
                                if (isFirstLoad && lastData.ultima) {
                                    const val = lastData.ultima[`temp${sensor.id}`];
                                    const hasData = (val !== null && val !== "" && val !== undefined);

                                    if (!hasData) {
                                        dataset.hidden = true; // Ocultar línea forzosamente si no hay datos
                                    } else {
                                        dataset.hidden = false;
                                    }
                                }
                            }
                        });
                    } else if (mainChart) {
                        // Limpiar gráficos si no hay historial
                        mainChart.data.datasets.forEach(dataset => {
                            dataset.data = [];
                        });
                    }

                    if (isFirstLoad) {
                        mainChart.update();
                        generateCustomLegend(); // Generar leyenda inmediatamente después de actualizar
                        isFirstLoad = false;
                        setTimeout(() => {
                            const overlay = document.getElementById('chartLoadingOverlay');
                            if (overlay) overlay.classList.add('hidden');
                        }, 3500);
                    }
                }
            } catch (error) {
                console.error(error);
                updateUIStatus(false);
            }
        }

        async function changeShip(id) {
            if (currentBuque === id) return;

            // 1. Limpiar estado visual y variables globales ANTES de cargar config
            currentBuque = id;
            isFirstLoad = true;
            activeSensors = []; // Resetear array de sensores locales
            lastData = null; // Resetear el caché de datos
            sensorTempConfigs = {}; // Limpiar configuraciones anteriores
            stopGaugeRotation();

            // 2. Limpiar UI
            if (mainChart) {
                mainChart.data.datasets = [];
                mainChart.update('none');
            }
            document.getElementById('metricsGrid').innerHTML = '';
            document.getElementById('markersLayer').innerHTML = '';
            document.getElementById('customLegend').innerHTML = '';

            const overlay = document.getElementById('chartLoadingOverlay');
            if (overlay) overlay.classList.remove('hidden');

            // 3. Cargar la configuración real del nuevo buque
            await loadConfig();

            // 4. Cargar configuraciones de alertas por sensor
            await loadSensorTempConfigs();

            // 5. Cargar datos del tablero
            await updateDashboard();

            // 6. Reiniciar UI de Widgets
            startGaugeRotation();
        }

        function updateUIStatus(online) {
            const indicator = document.getElementById('statusIndicator');
            const text = document.getElementById('statusText');
            if (indicator) {
                indicator.className = online ? 'status-pill status-online' : 'status-pill status-offline';
                text.textContent = online ? 'LINK ACTIVO' : 'SIN DATOS';
            }
        }

        initChart();
        loadConfig().then(async () => {
            // Asegurar que las configuraciones por sensor estén cargadas antes de actualizar
            await loadSensorTempConfigs();
            updateDashboard();
            // Iniciar rotación de manómetros
            startGaugeRotation();
        });

        setInterval(updateDashboard, 10000);
        setInterval(updateChartWindow, 1000);
        setInterval(syncPositionsFromServer, 2000);

        const lockBtn = document.getElementById('lockToggle');
        if (lockBtn) {
            lockBtn.textContent = isLocked ? '🔒' : '🔓';
            lockBtn.style.background = isLocked ? 'var(--red-alert)' : 'var(--cyan-glow)';
        }
    </script>

    <div id="renameModal" class="modal-overlay" style="display: none;">
        <div class="modal-content">
            <h3>📝 Renombrar Sensor</h3>
            <p>¿Ingrese el nuevo nombre para este sensor?</p>
            <input type="text" id="renameInput" class="modal-input" placeholder="Nombre del sensor">
            <div class="modal-actions">
                <button class="modal-btn cancel" onclick="closeRenameModal()">Cancelar</button>
                <button class="modal-btn confirm" onclick="confirmRename()">Guardar Cambio</button>
            </div>
        </div>
    </div>

    <script>
        function showLogoutModal() { document.getElementById('logoutModal').style.display = 'flex'; }
        function closeLogoutModal() { document.getElementById('logoutModal').style.display = 'none'; }
        function confirmLogout() { window.location.href = 'api/logout.php'; }
    </script>

    <div id="welcomeModal" class="modal-overlay" style="display: flex;">
        <div class="modal-content" style="max-width: 500px; text-align: center;">
            <div style="font-size: 3rem; margin-bottom: 10px;">🛡️</div>
            <h3 style="margin-top: 0;">SISTEMA DE MONITOREO</h3>
            <p>Monitoreo de Sensores de Temperatura en Tiempo Real</p>
            <p style="font-size: 0.9rem; color: #aaa; margin-bottom: 30px;">
                Esta aplicación requiere acceso al sistema de audio para emitir alertas críticas cuando se supere el
                umbral de 25°C.
                <br><br>
                Por favor, presione el siguiente botón para inicializar el sistema.
            </p>
            <button class="modal-btn confirm" onclick="unlockAudio()"
                style="width: 100%; font-size: 1.1rem; padding: 15px;">
                🔊 INGRESAR Y HABILITAR AUDIO
            </button>
        </div>
    </div>

    <div id="logoutModal" class="modal-overlay" style="display: none;">
        <div class="modal-content" style="max-width: 400px; text-align: center;">
            <div style="font-size: 3rem; margin-bottom: 10px;">👋</div>
            <h3 style="margin-top: 0;">¿Cerrar Sesión?</h3>
            <p>¿Realmente deseas salir del sistema de monitoreo?</p>
            <div class="modal-actions" style="margin-top: 25px;">
                <button class="modal-btn cancel" onclick="closeLogoutModal()">Cancelar</button>
                <button class="modal-btn confirm" onclick="confirmLogout()" style="background: var(--red-alert);">SÍ,
                    CERRAR SESIÓN</button>
            </div>
        </div>
    </div>

    <div id="rotationPrompt">
        <div class="rotate-icon">📲</div>
        <h3>Modo Horizontal Requerido</h3>
        <p>Para visualizar el mapa correctamente, por favor gire su dispositivo.</p>
    </div>

    <script>
        let audioUnlocked = false;
        const _originalUnlock = unlockAudio;
        unlockAudio = function () {
            if (isAlarmPlaying) return;
            const anyHigh = typeof activeSensors !== 'undefined' && activeSensors.some(s => s.isHighTemp);

            if (pendingAlarm || anyHigh) {
                console.log("Modal unlock: Alarm condition detected. Playing!");
                alertSound.volume = 1.0;
                _originalUnlock(true);
            } else {
                console.log("Modal unlock: No pending alarm. Warming up silently.");
                alertSound.volume = 0;
                alertSound.play().then(() => {
                    alertSound.pause();
                    alertSound.currentTime = 0;
                    alertSound.volume = 1;
                }).catch(e => {
                    alertSound.volume = 1;
                });
                _originalUnlock(false);
            }

            document.getElementById('welcomeModal').style.opacity = '0';
            setTimeout(() => {
                document.getElementById('welcomeModal').style.display = 'none';
                audioUnlocked = true;
                checkOrientation();
            }, 500);
        }

        function checkOrientation() {
            if (!audioUnlocked) return;
            const prompt = document.getElementById('rotationPrompt');
            const isMobile = window.innerWidth <= 768;
            const isPortrait = window.innerHeight > window.innerWidth;
            prompt.style.display = (isMobile && isPortrait) ? 'flex' : 'none';
        }

        window.addEventListener('resize', checkOrientation);
        window.addEventListener('orientationchange', () => { setTimeout(checkOrientation, 200); });

        function showToast(message) {
            let toast = document.querySelector('.sensor-toast');
            if (!toast) {
                toast = document.createElement('div');
                toast.className = 'sensor-toast';
                document.body.appendChild(toast);
            }
            toast.textContent = message;
            toast.classList.add('show');
            clearTimeout(toast.timeout);
            toast.timeout = setTimeout(() => { toast.classList.remove('show'); }, 2000);
        }

        function highlightSensor(id) {
            const card = document.getElementById(`card${id}`);
            const sensor = activeSensors.find(s => s.id === id);
            if (!card || !sensor) return;
            showToast(`Sensor: ${sensor.label}`);
            card.scrollIntoView({ behavior: 'smooth', block: 'center' });
            card.classList.remove('highlight-card');
            void card.offsetWidth;
            card.classList.add('highlight-card');
            setTimeout(() => { card.classList.remove('highlight-card'); }, 2500);
        }
    </script>

    <div id="shipUsersModal"
        style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); align-items:center; justify-content:center; z-index:9999; overflow-y: auto; padding: 20px;">
        <div
            style="background:#112240; padding:30px; border:1px solid var(--cyan-glow); border-radius:10px; width:700px; max-width:90%; max-height:90vh; overflow-y: auto;">
            <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
                <h3 style="color:var(--cyan-glow); margin:0;">👥 USUARIOS DEL BUQUE</h3>
                <button onclick="document.getElementById('shipUsersModal').style.display='none'"
                    style="background:none; border:none; color:#fff; font-size:1.5rem; cursor:pointer;">&times;</button>
            </div>

            <div style="margin-bottom:25px;">
                <h4 style="color:#fff; margin-bottom:15px; font-size:0.95rem;">📋 Lista de Usuarios con Acceso</h4>
                <div id="shipUsersList"
                    style="max-height:400px; overflow-y:auto; margin-bottom:20px; background:#050a10; border:1px solid #333; border-radius:5px; padding:10px;">
                    <p style="color:#888; text-align:center;">Cargando usuarios...</p>
                </div>
            </div>

            <div style="border-top:1px solid #333; padding-top:20px; margin-top:20px;">
                <h4 style="color:#fff; margin-bottom:15px; font-size:0.95rem;">➕ Crear Nuevo Usuario (Solo Lectura)</h4>
                <p style="color:#888; font-size:0.85rem; margin-bottom:15px;">Los usuarios creados solo podrán
                    visualizar los datos del buque, sin permisos de edición.</p>
                <div style="display:flex; gap:10px; margin-top:10px;">
                    <input type="text" id="newShipUser" placeholder="Nombre de usuario"
                        style="flex:1; padding:10px; background:#050a10; border:1px solid #444; color:#fff; border-radius:5px;">
                    <input type="password" id="newShipPass" placeholder="Contraseña"
                        style="flex:1; padding:10px; background:#050a10; border:1px solid #444; color:#fff; border-radius:5px;">
                    <button onclick="createShipUser()"
                        style="padding:10px 20px; background:var(--cyan-glow); color:#000; font-weight:bold; border:none; cursor:pointer; border-radius:5px;">CREAR</button>
                </div>
            </div>
        </div>
    </div>

    <script>
        async function openShipUsersModal() {
            document.getElementById('shipUsersModal').style.display = 'flex';
            loadShipUsers();
        }

        async function loadShipUsers() {
            const list = document.getElementById('shipUsersList');
            list.innerHTML = '<p style="color:#888; text-align:center;">Cargando...</p>';
            try {
                const res = await fetch(`api/manage_users.php?ship_id=${currentBuque}`);
                const data = await res.json();
                if (data.success) {
                    if (data.users.length === 0) {
                        list.innerHTML = '<p style="color:#888; text-align:center; padding:20px;">No hay usuarios con acceso a este buque.</p>';
                        return;
                    }

                    let html = '<table style="width:100%; border-collapse:collapse; color:#fff; font-size:0.9rem;">';
                    html += '<thead><tr style="border-bottom:2px solid var(--cyan-glow);">';
                    html += '<th style="padding:10px; text-align:left; color:var(--cyan-glow);">Usuario</th>';
                    html += '<th style="padding:10px; text-align:left; color:var(--cyan-glow);">Rol</th>';
                    html += '<th style="padding:10px; text-align:left; color:var(--cyan-glow);">Fecha de Alta</th>';
                    html += '<th style="padding:10px; text-align:right; color:var(--cyan-glow);">Acción</th>';
                    html += '</tr></thead><tbody>';

                    // Obtener el ID del usuario actual desde PHP
                    const currentUserId = <?php echo json_encode($_SESSION['user_id'] ?? null); ?>;

                    data.users.forEach(u => {
                        const roleLabel = u.role === 'sub-adm' ? 'Admin asignado' : 'Usuario';
                        const roleColor = u.role === 'sub-adm' ? '#6c5ce7' : '#888';
                        const statusColor = u.status === 'active' ? '#00ff00' : '#ff4d4d';
                        const statusText = u.status === 'active' ? 'Activo' : u.status === 'pending' ? 'Pendiente' : 'Rechazado';
                        const fecha = u.created_at ? new Date(u.created_at).toLocaleDateString('es-ES', { year: 'numeric', month: 'short', day: 'numeric' }) : 'N/A';

                        // Verificar si el usuario fue creado por el sub-adm actual
                        const wasCreatedByMe = u.created_by && currentUserId && parseInt(u.created_by) === parseInt(currentUserId);
                        const canManage = u.role === 'user' && wasCreatedByMe;

                        html += `<tr style="border-bottom:1px solid #222; transition:background 0.2s;" onmouseover="this.style.background='#0a1520'" onmouseout="this.style.background='transparent'">`;
                        html += `<td style="padding:12px 10px;">
                            <div style="display:flex; align-items:center; gap:8px;">
                                <span style="color:#fff; font-weight:500;">${u.username}</span>
                                <span style="background:${statusColor}; color:#000; padding:2px 6px; border-radius:3px; font-size:0.7rem; font-weight:bold;">${statusText}</span>
                                ${wasCreatedByMe ? '<span style="background:#00ff00; color:#000; padding:2px 6px; border-radius:3px; font-size:0.7rem; font-weight:bold;" title="Creado por ti">✓</span>' : ''}
                            </div>
                        </td>`;
                        html += `<td style="padding:12px 10px;"><span style="color:${roleColor}; font-weight:500;">${roleLabel}</span></td>`;
                        html += `<td style="padding:12px 10px; color:#888;">${fecha}</td>`;
                        html += `<td style="padding:12px 10px; text-align:right;">`;

                        // --- LÓGICA DE VISIBILIDAD DE BOTONES ---
                        const isSelf = currentUserId && parseInt(u.id) === parseInt(currentUserId);
                        const canModifyPass = canManage || isSelf; // Puede si lo creó O si es él mismo
                        const canDelete = canManage && !isSelf;   // Puede borrar si lo creó Y NO es él mismo

                        if (canModifyPass || canDelete) {
                            html += `<div style="display:flex; gap:8px; justify-content:flex-end;">`;
                            if (canModifyPass) {
                                html += `<button onclick="openChangePasswordModal(${u.id}, '${u.username}')" style="background:var(--cyan-glow); color:#000; border:none; padding:6px 12px; border-radius:4px; cursor:pointer; font-size:0.85rem; font-weight:bold; transition:opacity 0.2s;" onmouseover="this.style.opacity='0.8'" onmouseout="this.style.opacity='1'">🔑 Cambiar</button>`;
                            }
                            if (canDelete) {
                                html += `<button onclick="deleteShipUser(${u.id})" style="background:#ff4d4d; color:#fff; border:none; padding:6px 12px; border-radius:4px; cursor:pointer; font-size:0.85rem; transition:opacity 0.2s;" onmouseover="this.style.opacity='0.8'" onmouseout="this.style.opacity='1'">🗑️ Eliminar</button>`;
                            }
                            html += `</div>`;
                        } else if (u.role === 'user') {
                            html += `<span style="color:#888; font-size:0.8rem;">No creado por ti</span>`;
                        } else {
                            html += `<span style="color:#888; font-size:0.8rem;">-</span>`;
                        }

                        html += `</td></tr>`;
                    });

                    html += '</tbody></table>';
                    list.innerHTML = html;
                } else {
                    list.innerHTML = `<p style="color:#ff4d4d; text-align:center; padding:20px;">Error: ${data.message}</p>`;
                }
            } catch (e) {
                console.error('Error cargando usuarios:', e);
                list.innerHTML = '<p style="color:#ff4d4d; text-align:center; padding:20px;">Error de conexión</p>';
            }
        }

        async function createShipUser() {
            const user = document.getElementById('newShipUser').value;
            const pass = document.getElementById('newShipPass').value;
            if (!user || !pass) return showMessage('Atención', 'Ingrese usuario y contraseña', 'warning');
            try {
                const res = await fetch('api/manage_users.php', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ action: 'create', ship_id: currentBuque, username: user, password: pass })
                });
                const data = await res.json();
                if (data.success) {
                    document.getElementById('newShipUser').value = '';
                    document.getElementById('newShipPass').value = '';
                    loadShipUsers();
                } else { showMessage('Error', data.message, 'error-modal'); }
            } catch (e) { showMessage('Error', 'Error de conexión', 'error-modal'); }
        }

        function deleteShipUser(id) {
            showConfirm('Eliminar Usuario', '¿Confirmar eliminación de este usuario? Esta acción no se puede deshacer.', async () => {
                try {
                    const res = await fetch('api/manage_users.php', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ action: 'delete', user_id: id })
                    });
                    const data = await res.json();
                    if (data.success) {
                        showMessage('Éxito', 'Usuario eliminado correctamente', 'success');
                        loadShipUsers();
                    } else {
                        showMessage('Error', data.message, 'error-modal');
                    }
                } catch (e) {
                    showMessage('Error', 'Error de conexión', 'error-modal');
                }
            });
        }

        function openChangePasswordModal(userId, username) {
            document.getElementById('changePasswordUserId').value = userId;
            document.getElementById('changePasswordUsername').textContent = username;
            document.getElementById('changePasswordNewPass').value = '';
            document.getElementById('changePasswordModal').style.display = 'flex';
        }

        function closeChangePasswordModal() {
            document.getElementById('changePasswordModal').style.display = 'none';
            document.getElementById('changePasswordNewPass').value = '';
        }

        async function changeShipUserPassword() {
            const userId = document.getElementById('changePasswordUserId').value;
            const newPassword = document.getElementById('changePasswordNewPass').value;

            if (!newPassword || newPassword.length < 4) {
                showMessage('Atención', 'La contraseña debe tener al menos 4 caracteres', 'warning');
                return;
            }

            try {
                const res = await fetch('api/manage_users.php', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ action: 'change_password', user_id: userId, new_password: newPassword })
                });
                const data = await res.json();
                if (data.success) {
                    showMessage('Éxito', 'Contraseña actualizada correctamente', 'success');
                    closeChangePasswordModal();
                } else {
                    showMessage('Error', data.message, 'error-modal');
                }
            } catch (e) {
                showMessage('Error', 'Error de conexión', 'error-modal');
            }
        }
    </script>

    <!-- Modal para cambiar contraseña -->
    <div id="changePasswordModal"
        style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); align-items:center; justify-content:center; z-index:10000;">
        <div
            style="background:#112240; padding:30px; border:1px solid var(--cyan-glow); border-radius:10px; width:450px; max-width:90%;">
            <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
                <h3 style="color:var(--cyan-glow); margin:0;">🔑 Cambiar Contraseña</h3>
                <button onclick="closeChangePasswordModal()"
                    style="background:none; border:none; color:#fff; font-size:1.5rem; cursor:pointer;">&times;</button>
            </div>
            <p style="color:#888; margin-bottom:15px;">Usuario: <span id="changePasswordUsername"
                    style="color:#fff; font-weight:bold;"></span></p>
            <input type="hidden" id="changePasswordUserId">
            <div style="margin-bottom:20px;">
                <label style="color:#fff; display:block; margin-bottom:8px; font-size:0.9rem;">Nueva Contraseña:</label>
                <input type="password" id="changePasswordNewPass" placeholder="Ingrese la nueva contraseña"
                    style="width:100%; padding:10px; background:#050a10; border:1px solid #444; color:#fff; border-radius:5px; box-sizing:border-box;"
                    onkeypress="if(event.key === 'Enter') changeShipUserPassword();">
                <small style="color:#888; font-size:0.8rem; display:block; margin-top:5px;">Mínimo 4 caracteres</small>
            </div>
            <div style="display:flex; gap:10px; justify-content:flex-end;">
                <button onclick="closeChangePasswordModal()"
                    style="padding:10px 20px; background:#444; color:#fff; border:none; border-radius:5px; cursor:pointer; font-weight:bold;">Cancelar</button>
                <button onclick="changeShipUserPassword()"
                    style="padding:10px 20px; background:var(--cyan-glow); color:#000; border:none; border-radius:5px; cursor:pointer; font-weight:bold;">Cambiar</button>
            </div>
        </div>
    </div>

    <div id="settingsModal"
        style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); align-items:center; justify-content:center; z-index:9999; overflow-y: auto; padding: 20px;">
        <div
            style="background:#112240; padding:30px; border:1px solid var(--cyan-glow); border-radius:10px; width:600px; max-width:90%; max-height:90vh; overflow-y: auto;">
            <h3 style="color:var(--cyan-glow); margin-top:0; margin-bottom: 20px;">CONFIGURACIÓN DE ALERTAS POR SENSOR
            </h3>
            <p style="color:#888; font-size:0.9rem; margin-bottom: 20px;">
                Configura las temperaturas máximas y mínimas para cada sensor individualmente.
            </p>
            <div id="sensorConfigsContainer" style="margin-bottom: 20px;">
                <!-- Las configuraciones se cargarán dinámicamente aquí -->
            </div>
            <div style="display:flex; gap:10px; margin-top:20px;">
                <button onclick="saveSettings()"
                    style="flex:1; padding:12px; background:var(--cyan-glow); color:#000; font-weight:bold; border:none; cursor:pointer; border-radius:6px;">GUARDAR</button>
                <button onclick="document.getElementById('settingsModal').style.display='none'"
                    style="flex:1; padding:12px; background:transparent; color:#888; border:1px solid #444; cursor:pointer; border-radius:6px;">CANCELAR</button>
            </div>
        </div>
    </div>

    <div id="messageModal" class="modal-overlay" style="display: none; z-index: 10000;">
        <div class="modal-content" style="max-width: 400px; text-align: center;">
            <div id="msgIcon" style="font-size: 3rem; margin-bottom: 10px;">ℹ️</div>
            <h3 id="msgTitle" style="margin-top: 0; color: #fff;">Título</h3>
            <p id="msgText" style="color: #ccc;">Mensaje...</p>
            <button class="modal-btn confirm" onclick="closeMessageModal()">ENTENDIDO</button>
        </div>
    </div>

    <div id="confirmModal" class="modal-overlay" style="display: none; z-index: 10000;">
        <div class="modal-content" style="max-width: 400px; text-align: center;">
            <div style="font-size: 3rem; margin-bottom: 10px;">❓</div>
            <h3 id="confirmTitle" style="margin-top: 0; color: #fff;">Confirmar</h3>
            <p id="confirmText" style="color: #ccc;">¿Está seguro?</p>
            <div class="modal-actions" style="justify-content: center; gap: 10px; margin-top: 20px;">
                <button class="modal-btn cancel" onclick="closeConfirmModal(false)">CANCELAR</button>
                <button class="modal-btn confirm" onclick="closeConfirmModal(true)">CONFIRMAR</button>
            </div>
        </div>
    </div>

    <button id="backToTop" class="back-to-top" onclick="scrollToTop()" title="Volver arriba">↑</button>

    <script>
        window.addEventListener('scroll', () => {
            const btn = document.getElementById('backToTop');
            if (window.scrollY > 300) btn.classList.add('visible');
            else btn.classList.remove('visible');
        });
        function scrollToTop() { window.scrollTo({ top: 0, behavior: 'smooth' }); }
    </script>
</body>

</html>