<!-- Live View Panel for {{ unit.id }} -->
<div class="h-full flex flex-col">
    <!-- Bootstrap data from server -->
    <script id="slm-bootstrap-data" type="application/json">
    {
        "unit_id": "{{ unit.id }}",
        "is_measuring": {{ 'true' if is_measuring else 'false' }},
        "measurement_state": "{{ measurement_state }}",
        "measurement_start_time": {% if current_status and current_status.measurement_start_time %}"{{ current_status.measurement_start_time }}"{% else %}null{% endif %}
    }
    </script>

    <!-- Header -->
    <div class="flex items-center justify-between mb-6">
        <div>
            <h2 class="text-2xl font-bold text-gray-900 dark:text-white">{{ unit.id }}</h2>
            <p class="text-sm text-gray-600 dark:text-gray-400">
                {% if unit.slm_model %}{{ unit.slm_model }}{% endif %}
                {% if unit.slm_serial_number %} • S/N: {{ unit.slm_serial_number }}{% endif %}
            </p>
            {% if modem %}
            <p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
                via Modem: {{ modem.id }}{% if modem_ip %} ({{ modem_ip }}){% endif %}
            </p>
            {% elif modem_ip %}
            <p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
                Direct: {{ modem_ip }}
            </p>
            {% else %}
            <p class="text-xs text-red-500 dark:text-red-400 mt-1">
                ⚠️ No modem assigned or IP configured
            </p>
            {% endif %}
        </div>

        <!-- Status and Actions -->
        <div class="flex items-center gap-3">
            <!-- Settings Gear -->
            <button onclick="openSettingsModal('{{ unit.id }}')"
                    class="p-2 text-gray-600 dark:text-gray-400 hover:text-seismo-orange dark:hover:text-seismo-orange rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
                    title="Unit Settings">
                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
                </svg>
            </button>

            <!-- FTP Browser -->
            <button onclick="openFTPBrowser('{{ unit.id }}')"
                    class="p-2 text-gray-600 dark:text-gray-400 hover:text-seismo-orange dark:hover:text-seismo-orange rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
                    title="Browse Files (FTP)">
                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path>
                </svg>
            </button>

            <!-- Measurement Status Badge -->
            <div class="flex flex-col items-end gap-2">
                <div>
                    {% if is_measuring %}
                        <span class="px-4 py-2 bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400 rounded-lg font-medium flex items-center">
                            <span class="w-2 h-2 bg-green-500 rounded-full mr-2 animate-pulse"></span>
                            Measuring
                        </span>
                    {% else %}
                        <span class="px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg font-medium">
                            Stopped
                        </span>
                    {% endif %}
                </div>
                <!-- Elapsed Time Display -->
                <div id="elapsed-time-container" class="{% if not is_measuring %}hidden{% endif %}">
                    <div class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
                        <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                        </svg>
                        <span id="elapsed-time" class="font-mono font-medium text-gray-900 dark:text-white">00:00:00</span>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Measurement Controls -->
    <div class="mb-6 border border-gray-200 dark:border-gray-700 rounded-lg p-4">
        <h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">Measurement Control</h3>
        <div class="flex gap-2 flex-wrap">
            <button onclick="startMeasurementWithCheck('{{ unit.id }}')"
                    class="px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg flex items-center">
                <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                </svg>
                Start
            </button>

            <button onclick="controlUnit('{{ unit.id }}', 'pause')"
                    class="px-4 py-2 bg-yellow-600 hover:bg-yellow-700 text-white rounded-lg flex items-center">
                <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 9v6m4-6v6m7-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                </svg>
                Pause
            </button>

            <button onclick="controlUnit('{{ unit.id }}', 'stop')"
                    class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg flex items-center">
                <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 10a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1v-4z"></path>
                </svg>
                Stop
            </button>

            <button onclick="controlUnit('{{ unit.id }}', 'reset')"
                    class="px-4 py-2 bg-gray-600 hover:bg-gray-700 text-white rounded-lg flex items-center">
                <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
                </svg>
                Reset
            </button>

            <button onclick="controlUnit('{{ unit.id }}', 'store')"
                    class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg flex items-center">
                <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"></path>
                </svg>
                Store
            </button>

            <button id="start-stream-btn" onclick="initLiveDataStream('{{ unit.id }}')"
                    class="px-4 py-2 bg-seismo-orange hover:bg-orange-600 text-white rounded-lg flex items-center ml-auto">
                <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
                </svg>
                Start Live Stream
            </button>

            <button id="stop-stream-btn" onclick="stopLiveDataStream()" style="display: none;"
                    class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg flex items-center ml-auto">
                <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 10a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1v-4z"></path>
                </svg>
                Stop Live Stream
            </button>

            <span id="live-feed-status" class="ml-3 self-center" style="display: none;"></span>
        </div>
    </div>

    <!-- Current Metrics -->
    <div class="grid grid-cols-5 gap-4 mb-6">
        <div class="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4">
            <p class="text-xs text-gray-600 dark:text-gray-400 mb-1">Lp (Instant)</p>
            <p id="live-lp" class="text-2xl font-bold text-blue-600 dark:text-blue-400">
                {% if current_status and current_status.lp %}{{ current_status.lp }}{% else %}--{% endif %}
            </p>
            <p class="text-xs text-gray-500 dark:text-gray-400">dB</p>
        </div>

        <div class="bg-green-50 dark:bg-green-900/20 rounded-lg p-4">
            <p class="text-xs text-gray-600 dark:text-gray-400 mb-1">Leq (Average)</p>
            <p id="live-leq" class="text-2xl font-bold text-green-600 dark:text-green-400">
                {% if current_status and current_status.leq %}{{ current_status.leq }}{% else %}--{% endif %}
            </p>
            <p class="text-xs text-gray-500 dark:text-gray-400">dB</p>
        </div>

        <div class="bg-red-50 dark:bg-red-900/20 rounded-lg p-4">
            <p class="text-xs text-gray-600 dark:text-gray-400 mb-1">Lmax (Max)</p>
            <p id="live-lmax" class="text-2xl font-bold text-red-600 dark:text-red-400">
                {% if current_status and current_status.lmax %}{{ current_status.lmax }}{% else %}--{% endif %}
            </p>
            <p class="text-xs text-gray-500 dark:text-gray-400">dB</p>
        </div>

        <div class="bg-purple-50 dark:bg-purple-900/20 rounded-lg p-4">
            <p id="live-ln1-label" class="text-xs text-gray-600 dark:text-gray-400 mb-1">{% if current_status and current_status.ln1_label %}{{ current_status.ln1_label }}{% else %}L1{% endif %}</p>
            <p id="live-ln1" class="text-2xl font-bold text-purple-600 dark:text-purple-400">
                {% if current_status and current_status.ln1 %}{{ current_status.ln1 }}{% else %}--{% endif %}
            </p>
            <p class="text-xs text-gray-500 dark:text-gray-400">dB</p>
        </div>

        <div class="bg-orange-50 dark:bg-orange-900/20 rounded-lg p-4">
            <p id="live-ln2-label" class="text-xs text-gray-600 dark:text-gray-400 mb-1">{% if current_status and current_status.ln2_label %}{{ current_status.ln2_label }}{% else %}L10{% endif %}</p>
            <p id="live-ln2" class="text-2xl font-bold text-orange-600 dark:text-orange-400">
                {% if current_status and current_status.ln2 %}{{ current_status.ln2 }}{% else %}--{% endif %}
            </p>
            <p class="text-xs text-gray-500 dark:text-gray-400">dB</p>
        </div>
    </div>

    <!-- Live Chart -->
    <div class="flex-1 bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4" style="min-height: 400px;">
        <canvas id="liveChart"></canvas>
    </div>

    <!-- Device Status Cards -->
    <div class="mt-6">
        <h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">Device Status</h3>
        <div class="grid grid-cols-4 gap-4">
            <!-- Battery Status -->
            <div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
                <div class="flex items-center justify-between mb-2">
                    <span class="text-xs text-gray-600 dark:text-gray-400">Battery</span>
                    <svg class="w-4 h-4 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
                        <path d="M6 2a2 2 0 00-2 2v12a2 2 0 002 2h8a2 2 0 002-2V4a2 2 0 00-2-2H6zm0 2h8v12H6V4zm7 2a1 1 0 011 1v6a1 1 0 11-2 0V7a1 1 0 011-1z"/>
                    </svg>
                </div>
                <div id="battery-level" class="text-2xl font-bold text-gray-900 dark:text-white">
                    {% if current_status and current_status.battery_level %}{{ current_status.battery_level }}%{% else %}--{% endif %}
                </div>
                <div class="mt-2 bg-gray-200 dark:bg-gray-700 rounded-full h-2">
                    <div id="battery-bar" class="bg-green-500 h-2 rounded-full transition-all"
                         style="width: {% if current_status and current_status.battery_level %}{{ current_status.battery_level }}{% else %}0{% endif %}%">
                    </div>
                </div>
            </div>

            <!-- Power Source -->
            <div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
                <div class="flex items-center justify-between mb-2">
                    <span class="text-xs text-gray-600 dark:text-gray-400">Power</span>
                    <svg class="w-4 h-4 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
                        <path fill-rule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z" clip-rule="evenodd"/>
                    </svg>
                </div>
                <div id="power-source" class="text-lg font-semibold text-gray-900 dark:text-white">
                    {% if current_status and current_status.power_source %}{{ current_status.power_source }}{% else %}--{% endif %}
                </div>
            </div>

            <!-- SD Card Space -->
            <div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
                <div class="flex items-center justify-between mb-2">
                    <span class="text-xs text-gray-600 dark:text-gray-400">SD Card</span>
                    <svg class="w-4 h-4 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
                        <path d="M3 4a2 2 0 012-2h10a2 2 0 012 2v12a2 2 0 01-2 2H5a2 2 0 01-2-2V4zm2 0v12h10V4H5z"/>
                    </svg>
                </div>
                <div id="sd-remaining" class="text-lg font-semibold text-gray-900 dark:text-white">
                    {% if current_status and current_status.sd_remaining_mb %}{{ current_status.sd_remaining_mb }} MB{% else %}--{% endif %}
                </div>
                <div id="sd-ratio" class="text-xs text-gray-500 dark:text-gray-400">
                    {% if current_status and current_status.sd_free_ratio %}{{ current_status.sd_free_ratio }}% free{% else %}--{% endif %}
                </div>
            </div>

            <!-- Last Update -->
            <div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
                <div class="flex items-center justify-between mb-2">
                    <span class="text-xs text-gray-600 dark:text-gray-400">Last Update</span>
                    <svg class="w-4 h-4 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
                        <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd"/>
                    </svg>
                </div>
                <div id="last-update" class="text-xs font-medium text-gray-700 dark:text-gray-300">
                    Just now
                </div>
                <div id="auto-refresh-indicator" class="mt-2 flex items-center text-xs text-green-600 dark:text-green-400">
                    <span class="w-2 h-2 bg-green-500 rounded-full mr-1 animate-pulse"></span>
                    Auto-refresh: 30s
                </div>
            </div>
        </div>
    </div>

    <!-- Device Settings & Commands -->
    <div class="mt-6 grid grid-cols-1 lg:grid-cols-2 gap-6">
        <!-- Store Name & Clock -->
        <div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
            <h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-4">Store Name & Time</h3>

            <!-- Store Name (Index Number) -->
            <div class="mb-4">
                <label class="block text-xs text-gray-600 dark:text-gray-400 mb-2">Store Name (Index Number)</label>
                <div class="flex items-center gap-2">
                    <input type="number" id="index-number-input"
                           class="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
                           min="0" max="9999" placeholder="0000">
                    <button onclick="getIndexNumber('{{ unit.id }}')"
                            class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm">
                        Get
                    </button>
                    <button onclick="setIndexNumber('{{ unit.id }}')"
                            class="px-4 py-2 bg-seismo-orange hover:bg-orange-600 text-white rounded-lg text-sm">
                        Set
                    </button>
                </div>
                <p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Range: 0000-9999. Used for file numbering.</p>
                <div id="index-overwrite-warning" class="hidden mt-2 p-2 bg-red-100 dark:bg-red-900/30 border border-red-300 dark:border-red-700 rounded text-xs text-red-800 dark:text-red-400">
                    ⚠️ <strong>Warning:</strong> Data exists at this index. Starting measurement will overwrite previous data!
                </div>
            </div>

            <!-- Device Clock -->
            <div>
                <label class="block text-xs text-gray-600 dark:text-gray-400 mb-2">Device Clock</label>
                <div class="flex items-center gap-2">
                    <div id="device-clock" class="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-gray-50 dark:bg-gray-700/50 text-gray-900 dark:text-white font-mono text-sm">
                        --
                    </div>
                    <button onclick="getDeviceClock('{{ unit.id }}')"
                            class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm">
                        Refresh
                    </button>
                    <button onclick="syncDeviceClock('{{ unit.id }}')"
                            class="px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg text-sm">
                        Sync
                    </button>
                </div>
                <p class="text-xs text-gray-500 dark:text-gray-400 mt-1">Sync sets device clock to match server time.</p>
            </div>
        </div>

        <!-- Measurement Settings -->
        <div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
            <h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-4">Measurement Settings</h3>

            <!-- Frequency Weighting -->
            <div class="mb-4">
                <label class="block text-xs text-gray-600 dark:text-gray-400 mb-2">Frequency Weighting</label>
                <div class="flex items-center gap-2">
                    <select id="frequency-weighting-select"
                            class="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
                        <option value="">--</option>
                        <option value="A">A</option>
                        <option value="C">C</option>
                        <option value="Z">Z</option>
                    </select>
                    <button onclick="getFrequencyWeighting('{{ unit.id }}')"
                            class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm">
                        Get
                    </button>
                    <button onclick="setFrequencyWeighting('{{ unit.id }}')"
                            class="px-4 py-2 bg-seismo-orange hover:bg-orange-600 text-white rounded-lg text-sm">
                        Set
                    </button>
                </div>
            </div>

            <!-- Time Weighting -->
            <div class="mb-4">
                <label class="block text-xs text-gray-600 dark:text-gray-400 mb-2">Time Weighting</label>
                <div class="flex items-center gap-2">
                    <select id="time-weighting-select"
                            class="flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
                        <option value="">--</option>
                        <option value="F">F (Fast)</option>
                        <option value="S">S (Slow)</option>
                        <option value="I">I (Impulse)</option>
                    </select>
                    <button onclick="getTimeWeighting('{{ unit.id }}')"
                            class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm">
                        Get
                    </button>
                    <button onclick="setTimeWeighting('{{ unit.id }}')"
                            class="px-4 py-2 bg-seismo-orange hover:bg-orange-600 text-white rounded-lg text-sm">
                        Set
                    </button>
                </div>
            </div>

            <!-- All Settings Query -->
            <div>
                <button onclick="getAllSettings('{{ unit.id }}')"
                        class="w-full px-4 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-lg text-sm flex items-center justify-center">
                    <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path>
                    </svg>
                    Query All Settings
                </button>
                <p class="text-xs text-gray-500 dark:text-gray-400 mt-1 text-center">View all device settings for diagnostics</p>
            </div>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// Initialize Chart.js for live data visualization
function initializeChart() {
    // Wait for Chart.js to load
    if (typeof Chart === 'undefined') {
        console.log('Waiting for Chart.js to load...');
        setTimeout(initializeChart, 100);
        return;
    }

    console.log('Chart.js loaded, version:', Chart.version);

    const canvas = document.getElementById('liveChart');
    if (!canvas) {
        console.error('Chart canvas not found');
        return;
    }

    console.log('Canvas found:', canvas);

    // Destroy existing chart if it exists
    if (window.liveChart && typeof window.liveChart.destroy === 'function') {
        console.log('Destroying existing chart');
        window.liveChart.destroy();
    }

    const ctx = canvas.getContext('2d');
    console.log('Creating new chart...');

    // Dark mode detection
    const isDarkMode = document.documentElement.classList.contains('dark');
    const gridColor = isDarkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
    const textColor = isDarkMode ? 'rgba(255, 255, 255, 0.7)' : 'rgba(0, 0, 0, 0.7)';

    window.liveChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: [],
        datasets: [
            {
                label: 'Lp (Instantaneous)',
                data: [],
                borderColor: 'rgb(59, 130, 246)',
                backgroundColor: 'rgba(59, 130, 246, 0.1)',
                tension: 0.3,
                borderWidth: 2,
                pointRadius: 0
            },
            {
                label: 'Leq (Equivalent)',
                data: [],
                borderColor: 'rgb(34, 197, 94)',
                backgroundColor: 'rgba(34, 197, 94, 0.1)',
                tension: 0.3,
                borderWidth: 2,
                pointRadius: 0
            },
            {
                label: 'L1',
                data: [],
                borderColor: 'rgb(139, 92, 246)',
                backgroundColor: 'rgba(139, 92, 246, 0.1)',
                tension: 0.3,
                borderWidth: 2,
                pointRadius: 0
            },
            {
                label: 'L10',
                data: [],
                borderColor: 'rgb(245, 158, 11)',
                backgroundColor: 'rgba(245, 158, 11, 0.1)',
                tension: 0.3,
                borderWidth: 2,
                pointRadius: 0
            }
        ]
    },
    options: {
        responsive: true,
        maintainAspectRatio: false,
        animation: false,
        interaction: {
            intersect: false,
            mode: 'index'
        },
        scales: {
            x: {
                display: true,
                grid: {
                    color: gridColor
                },
                ticks: {
                    color: textColor,
                    maxTicksLimit: 10
                }
            },
            y: {
                display: true,
                title: {
                    display: true,
                    text: 'Sound Level (dB)',
                    color: textColor
                },
                grid: {
                    color: gridColor
                },
                ticks: {
                    color: textColor
                },
                min: 30,
                max: 130
            }
        },
        plugins: {
            legend: {
                labels: {
                    color: textColor
                }
            }
        }
    }
    });

    console.log('Chart created successfully:', window.liveChart);
}

// Initialize chart when DOM is ready
console.log('Executing initializeChart...');
initializeChart();

// WebSocket management (use global scope to avoid redeclaration)
if (typeof window.currentWebSocket === 'undefined') {
    window.currentWebSocket = null;
}

// Backfill the chart with the recent DOD trail so it opens with context.
async function backfillChart(unitId) {
    try {
        const r = await fetch(`/api/slmm/${encodeURIComponent(unitId)}/history?hours=2`);
        if (!r.ok) return;
        const d = await r.json();
        const readings = d.readings || [];
        if (!window.chartData) return;
        for (const row of readings) {
            // Trail timestamps are naive UTC; append 'Z' so they convert to local
            // consistently with the live frames (which use local Date.now()).
            window.chartData.timestamps.push(row.timestamp ? new Date(row.timestamp + 'Z').toLocaleTimeString() : '');
            window.chartData.lp.push(parseFloat(row.lp || 0));
            window.chartData.leq.push(parseFloat(row.leq || 0));
            window.chartData.ln1.push(parseFloat(row.ln1 || 0));
            window.chartData.ln2.push(parseFloat(row.ln2 || 0));
        }
        if (window.liveChart) {
            window.liveChart.data.labels = window.chartData.timestamps;
            window.liveChart.data.datasets[0].data = window.chartData.lp;
            window.liveChart.data.datasets[1].data = window.chartData.leq;
            window.liveChart.data.datasets[2].data = window.chartData.ln1;
            window.liveChart.data.datasets[3].data = window.chartData.ln2;
            window.liveChart.update('none');
        }
    } catch (e) {
        console.warn('Chart backfill failed:', e);
    }
}

async function initLiveDataStream(unitId) {
    // Close existing connection if any
    if (window.currentWebSocket) {
        window.currentWebSocket.close();
    }

    // Reset chart data
    if (window.chartData) {
        window.chartData.timestamps = [];
        window.chartData.lp = [];
        window.chartData.leq = [];
        window.chartData.ln1 = [];
        window.chartData.ln2 = [];
    }
    if (window.liveChart && window.liveChart.data && window.liveChart.data.datasets) {
        window.liveChart.data.labels = [];
        window.liveChart.data.datasets.forEach(ds => ds.data = []);
        window.liveChart.update();
    }

    // Seed the chart with recent history BEFORE opening the live socket, so live
    // frames append after the backfill (right order) and the chart isn't blank.
    await backfillChart(unitId);

    // WebSocket URL for SLMM backend via proxy.
    // /monitor = the shared fan-out DOD feed (many viewers, one device connection,
    // and it carries L1/L10 which the DRD /stream cannot).
    const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const wsUrl = `${wsProtocol}//${window.location.host}/api/slmm/${unitId}/monitor`;

    window.currentWebSocket = new WebSocket(wsUrl);

    window.currentWebSocket.onopen = function() {
        console.log('WebSocket connected');
        // Toggle button visibility
        const startBtn = document.getElementById('start-stream-btn');
        const stopBtn = document.getElementById('stop-stream-btn');
        if (startBtn) startBtn.style.display = 'none';
        if (stopBtn) stopBtn.style.display = 'flex';
    };

    window.currentWebSocket.onmessage = function(event) {
        try {
            const data = JSON.parse(event.data);
            // The DOD monitor sends keepalive 'heartbeat' frames (no metrics) and a
            // 'feed_status' on each frame. Reflect status, but don't let a heartbeat
            // or an 'unreachable' frame blank the cards / spike the chart with zeros.
            updateFeedStatus(data.feed_status);
            if (data.heartbeat || data.feed_status === 'unreachable') return;
            updateLiveMetrics(data);
            updateLiveChart(data);
        } catch (error) {
            console.error('Error parsing WebSocket message:', error);
        }
    };

    window.currentWebSocket.onerror = function(error) {
        console.error('WebSocket error:', error);
    };

    window.currentWebSocket.onclose = function() {
        console.log('WebSocket closed');
        // Toggle button visibility
        const startBtn = document.getElementById('start-stream-btn');
        const stopBtn = document.getElementById('stop-stream-btn');
        if (startBtn) startBtn.style.display = 'flex';
        if (stopBtn) stopBtn.style.display = 'none';
    };
}

function stopLiveDataStream() {
    if (window.currentWebSocket) {
        window.currentWebSocket.close();
        window.currentWebSocket = null;
    }
}

// Reflect device reachability from the monitor feed's feed_status. Safe no-op
// if the badge element isn't on the page.
function updateFeedStatus(status) {
    const el = document.getElementById('live-feed-status');
    if (!el || status == null) return;
    if (status === 'unreachable') {
        el.textContent = 'Device offline';
        el.className = 'text-xs font-medium px-2 py-0.5 rounded bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300';
    } else {
        el.textContent = 'Live';
        el.className = 'text-xs font-medium px-2 py-0.5 rounded bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300';
    }
    el.style.display = '';
}

// Update metrics display
function updateLiveMetrics(data) {
    if (document.getElementById('live-lp')) {
        document.getElementById('live-lp').textContent = data.lp || '--';
    }
    if (document.getElementById('live-leq')) {
        document.getElementById('live-leq').textContent = data.leq || '--';
    }
    if (document.getElementById('live-lmax')) {
        document.getElementById('live-lmax').textContent = data.lmax || '--';
    }
    // Only update Ln values when the frame actually carries them. DRD stream
    // frames omit percentiles (DOD-only), so without this guard a live stream
    // would blank L1/L10 over the values rendered from the cached DOD snapshot.
    if (data.ln1 != null && document.getElementById('live-ln1')) {
        document.getElementById('live-ln1').textContent = data.ln1;
    }
    if (data.ln1_label && document.getElementById('live-ln1-label')) {
        document.getElementById('live-ln1-label').textContent = data.ln1_label;
    }
    if (data.ln2 != null && document.getElementById('live-ln2')) {
        document.getElementById('live-ln2').textContent = data.ln2;
    }
    if (data.ln2_label && document.getElementById('live-ln2-label')) {
        document.getElementById('live-ln2-label').textContent = data.ln2_label;
    }
}

// Chart data storage (use global scope to avoid redeclaration)
if (typeof window.chartData === 'undefined') {
    window.chartData = {
        timestamps: [],
        lp: [],
        leq: [],
        ln1: [],
        ln2: []
    };
}

// Update live chart
function updateLiveChart(data) {
    const now = new Date();
    window.chartData.timestamps.push(now.toLocaleTimeString());
    window.chartData.lp.push(parseFloat(data.lp || 0));
    window.chartData.leq.push(parseFloat(data.leq || 0));
    window.chartData.ln1.push(parseFloat(data.ln1 || 0));
    window.chartData.ln2.push(parseFloat(data.ln2 || 0));

    // Keep a rolling window large enough to hold the ~2h backfill (one point/min)
    // plus a good run of live points before the oldest scroll off.
    if (window.chartData.timestamps.length > 600) {
        window.chartData.timestamps.shift();
        window.chartData.lp.shift();
        window.chartData.leq.shift();
        window.chartData.ln1.shift();
        window.chartData.ln2.shift();
    }

    // Update chart if available
    if (window.liveChart) {
        window.liveChart.data.labels = window.chartData.timestamps;
        window.liveChart.data.datasets[0].data = window.chartData.lp;
        window.liveChart.data.datasets[1].data = window.chartData.leq;
        window.liveChart.data.datasets[2].data = window.chartData.ln1;
        window.liveChart.data.datasets[3].data = window.chartData.ln2;
        window.liveChart.update('none');
    }
}

// Control function
async function controlUnit(unitId, action) {
    try {
        const response = await fetch(`/api/slm-dashboard/control/${unitId}/${action}`, {
            method: 'POST'
        });
        const result = await response.json();

        if (result.status === 'ok') {
            // Handle timer based on action
            if (action === 'start') {
                startMeasurementTimer(unitId);
            } else if (action === 'stop' || action === 'reset') {
                stopMeasurementTimer();
                clearMeasurementStartTime(unitId);
            }
            // Note: pause does not stop timer - it keeps running

            // Reload the live view to update status
            setTimeout(() => {
                htmx.ajax('GET', `/api/slm-dashboard/live-view/${unitId}`, {
                    target: '#slm-command-center',
                    swap: 'innerHTML'
                });
            }, 500);
        } else {
            alert(`Error: ${result.detail || 'Unknown error'}`);
        }
    } catch (error) {
        alert(`Failed to control unit: ${error.message}`);
    }
}

// Start measurement with overwrite check
async function startMeasurementWithCheck(unitId) {
    try {
        // Check for overwrite risk
        const checkResponse = await fetch(`/api/slmm/${unitId}/overwrite-check`);
        const checkResult = await checkResponse.json();

        console.log('Overwrite check result:', checkResult);

        if (checkResult.status === 'ok') {
            // API returns data directly, not nested under .data
            const overwriteStatus = checkResult.overwrite_status;
            const willOverwrite = checkResult.will_overwrite;

            if (willOverwrite === true || overwriteStatus === 'Exist') {
                // Data exists - warn user
                const confirmed = confirm(
                    `⚠️ WARNING: Data exists at the current store index!\n\n` +
                    `Overwrite Status: ${overwriteStatus}\n\n` +
                    `Starting measurement will OVERWRITE previous data.\n\n` +
                    `Are you sure you want to continue?`
                );

                if (!confirmed) {
                    return; // User cancelled
                }
            }
        }

        // Proceed with start
        await controlUnit(unitId, 'start');

    } catch (error) {
        console.error('Overwrite check failed:', error);
        // Still allow start, but warn user
        const proceed = confirm(
            'Could not verify overwrite status.\n\n' +
            'Do you want to start measurement anyway?'
        );
        if (proceed) {
            await controlUnit(unitId, 'start');
        }
    }
}

// Index Number (Store Name) functions
async function getIndexNumber(unitId) {
    try {
        const response = await fetch(`/api/slmm/${unitId}/index-number`);
        const result = await response.json();

        if (result.status === 'ok') {
            const indexNumber = result.data?.index_number || result.index_number;
            document.getElementById('index-number-input').value = parseInt(indexNumber);

            // Check for overwrite risk at this index
            await checkOverwriteStatus(unitId);
        } else {
            alert(`Failed to get index number: ${result.detail || 'Unknown error'}`);
        }
    } catch (error) {
        alert(`Failed to get index number: ${error.message}`);
    }
}

async function setIndexNumber(unitId) {
    const input = document.getElementById('index-number-input');
    const indexValue = parseInt(input.value);

    if (isNaN(indexValue) || indexValue < 0 || indexValue > 9999) {
        alert('Please enter a valid index number (0-9999)');
        return;
    }

    try {
        const response = await fetch(`/api/slmm/${unitId}/index-number`, {
            method: 'PUT',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ index: indexValue })
        });

        const result = await response.json();

        if (result.status === 'ok') {
            alert(`Index number set to ${String(indexValue).padStart(4, '0')}`);
            // Check for overwrite risk at new index
            await checkOverwriteStatus(unitId);
        } else {
            alert(`Failed to set index number: ${result.detail || 'Unknown error'}`);
        }
    } catch (error) {
        alert(`Failed to set index number: ${error.message}`);
    }
}

async function checkOverwriteStatus(unitId) {
    try {
        const response = await fetch(`/api/slmm/${unitId}/overwrite-check`);
        const result = await response.json();

        console.log('Overwrite status check:', result);

        const warningDiv = document.getElementById('index-overwrite-warning');

        if (result.status === 'ok') {
            // API returns data directly, not nested under .data
            const overwriteStatus = result.overwrite_status;
            const willOverwrite = result.will_overwrite;

            if (willOverwrite === true || overwriteStatus === 'Exist') {
                warningDiv.classList.remove('hidden');
            } else {
                warningDiv.classList.add('hidden');
            }
        } else {
            warningDiv.classList.add('hidden');
        }
    } catch (error) {
        console.error('Failed to check overwrite status:', error);
        // Hide warning on error
        const warningDiv = document.getElementById('index-overwrite-warning');
        if (warningDiv) {
            warningDiv.classList.add('hidden');
        }
    }
}

// Device Clock functions
async function getDeviceClock(unitId) {
    try {
        const response = await fetch(`/api/slmm/${unitId}/clock`);
        const result = await response.json();

        if (result.status === 'ok') {
            const clockValue = result.data?.clock || result.clock;
            document.getElementById('device-clock').textContent = clockValue;
        } else {
            alert(`Failed to get device clock: ${result.detail || 'Unknown error'}`);
        }
    } catch (error) {
        alert(`Failed to get device clock: ${error.message}`);
    }
}

async function syncDeviceClock(unitId) {
    try {
        // Format current time for NL43: YYYY/MM/DD,HH:MM:SS
        const now = new Date();
        const year = now.getFullYear();
        const month = String(now.getMonth() + 1).padStart(2, '0');
        const day = String(now.getDate()).padStart(2, '0');
        const hours = String(now.getHours()).padStart(2, '0');
        const minutes = String(now.getMinutes()).padStart(2, '0');
        const seconds = String(now.getSeconds()).padStart(2, '0');

        const datetime = `${year}/${month}/${day},${hours}:${minutes}:${seconds}`;

        const response = await fetch(`/api/slmm/${unitId}/clock`, {
            method: 'PUT',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ datetime: datetime })
        });

        const result = await response.json();

        if (result.status === 'ok') {
            alert('Device clock synchronized successfully!');
            await getDeviceClock(unitId);
        } else {
            alert(`Failed to sync clock: ${result.detail || 'Unknown error'}`);
        }
    } catch (error) {
        alert(`Failed to sync clock: ${error.message}`);
    }
}

// Frequency Weighting functions
async function getFrequencyWeighting(unitId) {
    try {
        const response = await fetch(`/api/slmm/${unitId}/frequency-weighting?channel=Main`);
        const result = await response.json();

        if (result.status === 'ok') {
            const weighting = result.data?.frequency_weighting || result.frequency_weighting;
            document.getElementById('frequency-weighting-select').value = weighting;
        } else {
            alert(`Failed to get frequency weighting: ${result.detail || 'Unknown error'}`);
        }
    } catch (error) {
        alert(`Failed to get frequency weighting: ${error.message}`);
    }
}

async function setFrequencyWeighting(unitId) {
    const select = document.getElementById('frequency-weighting-select');
    const weighting = select.value;

    if (!weighting) {
        alert('Please select a frequency weighting');
        return;
    }

    try {
        const response = await fetch(`/api/slmm/${unitId}/frequency-weighting`, {
            method: 'PUT',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ weighting: weighting, channel: 'Main' })
        });

        const result = await response.json();

        if (result.status === 'ok') {
            alert(`Frequency weighting set to ${weighting}`);
        } else {
            alert(`Failed to set frequency weighting: ${result.detail || 'Unknown error'}`);
        }
    } catch (error) {
        alert(`Failed to set frequency weighting: ${error.message}`);
    }
}

// Time Weighting functions
async function getTimeWeighting(unitId) {
    try {
        const response = await fetch(`/api/slmm/${unitId}/time-weighting?channel=Main`);
        const result = await response.json();

        if (result.status === 'ok') {
            const weighting = result.data?.time_weighting || result.time_weighting;
            document.getElementById('time-weighting-select').value = weighting;
        } else {
            alert(`Failed to get time weighting: ${result.detail || 'Unknown error'}`);
        }
    } catch (error) {
        alert(`Failed to get time weighting: ${error.message}`);
    }
}

async function setTimeWeighting(unitId) {
    const select = document.getElementById('time-weighting-select');
    const weighting = select.value;

    if (!weighting) {
        alert('Please select a time weighting');
        return;
    }

    try {
        const response = await fetch(`/api/slmm/${unitId}/time-weighting`, {
            method: 'PUT',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ weighting: weighting, channel: 'Main' })
        });

        const result = await response.json();

        if (result.status === 'ok') {
            alert(`Time weighting set to ${weighting}`);
        } else {
            alert(`Failed to set time weighting: ${result.detail || 'Unknown error'}`);
        }
    } catch (error) {
        alert(`Failed to set time weighting: ${error.message}`);
    }
}

// Get All Settings
async function getAllSettings(unitId) {
    try {
        const response = await fetch(`/api/slmm/${unitId}/settings/all`);
        const result = await response.json();

        if (result.status === 'ok') {
            const settings = result.data?.settings || result.settings;

            // Format settings for display
            let message = 'Current Device Settings:\n\n';
            for (const [key, value] of Object.entries(settings)) {
                const label = key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
                message += `${label}: ${value}\n`;
            }

            alert(message);
        } else {
            alert(`Failed to get settings: ${result.detail || 'Unknown error'}`);
        }
    } catch (error) {
        alert(`Failed to get settings: ${error.message}`);
    }
}

// ========================================
// Measurement Timer
// ========================================
let measurementTimerInterval = null;
const TIMER_STORAGE_KEY = 'slm_measurement_start_';

function startMeasurementTimer(unitId) {
    // Stop any existing timer
    stopMeasurementTimer();

    // Only set start time if not already set (preserve existing start time)
    const existingStartTime = localStorage.getItem(TIMER_STORAGE_KEY + unitId);
    if (!existingStartTime) {
        const startTime = Date.now();
        localStorage.setItem(TIMER_STORAGE_KEY + unitId, startTime.toString());
        console.log('No existing start time, setting to now:', new Date(startTime));
    } else {
        console.log('Using existing start time from localStorage:', new Date(parseInt(existingStartTime)));
    }

    // Show timer container
    const container = document.getElementById('elapsed-time-container');
    if (container) {
        container.classList.remove('hidden');
    }

    // Update timer immediately
    updateElapsedTime(unitId);

    // Update every second
    measurementTimerInterval = setInterval(() => {
        updateElapsedTime(unitId);
    }, 1000);

    console.log('Measurement timer started for', unitId);
}

function stopMeasurementTimer() {
    if (measurementTimerInterval) {
        clearInterval(measurementTimerInterval);
        measurementTimerInterval = null;
    }

    // Hide timer container
    const container = document.getElementById('elapsed-time-container');
    if (container) {
        container.classList.add('hidden');
    }

    console.log('Measurement timer stopped');
}

function updateElapsedTime(unitId) {
    const startTimeStr = localStorage.getItem(TIMER_STORAGE_KEY + unitId);
    if (!startTimeStr) {
        return;
    }

    const startTime = parseInt(startTimeStr);
    const now = Date.now();
    const elapsedMs = now - startTime;

    // Convert to HH:MM:SS
    const hours = Math.floor(elapsedMs / (1000 * 60 * 60));
    const minutes = Math.floor((elapsedMs % (1000 * 60 * 60)) / (1000 * 60));
    const seconds = Math.floor((elapsedMs % (1000 * 60)) / 1000);

    const timeString =
        String(hours).padStart(2, '0') + ':' +
        String(minutes).padStart(2, '0') + ':' +
        String(seconds).padStart(2, '0');

    const display = document.getElementById('elapsed-time');
    if (display) {
        display.textContent = timeString;
    }
}

function clearMeasurementStartTime(unitId) {
    localStorage.removeItem(TIMER_STORAGE_KEY + unitId);
    console.log('Cleared measurement start time for', unitId);
}

// Resume timer if measurement is in progress
async function resumeMeasurementTimerIfNeeded(unitId, isMeasuring) {
    const startTimeStr = localStorage.getItem(TIMER_STORAGE_KEY + unitId);

    if (isMeasuring && startTimeStr) {
        // Measurement is active and we have a start time - resume timer
        startMeasurementTimer(unitId);
    } else if (!isMeasuring && startTimeStr) {
        // Measurement stopped but we have a start time - clear it
        clearMeasurementStartTime(unitId);
        stopMeasurementTimer();
    } else if (isMeasuring && !startTimeStr) {
        // Measurement is active but no start time recorded
        // Try to get start time from last folder on FTP
        console.log('Measurement active but no start time - fetching from FTP...');
        await fetchStartTimeFromFTP(unitId);
    }
}

// Fetch measurement start time from last folder on FTP
async function fetchStartTimeFromFTP(unitId) {
    try {
        console.log('Fetching FTP files from /NL-43...');
        const response = await fetch(`/api/slmm/${unitId}/ftp/files?path=/NL-43`);
        const result = await response.json();

        console.log('FTP response status:', response.status);
        console.log('FTP response data:', result);

        if (result.status === 'ok' && result.files && result.files.length > 0) {
            console.log(`Found ${result.files.length} files/folders`);

            // Filter for directories only
            const folders = result.files.filter(f => f.is_dir || f.type === 'directory');
            console.log(`Found ${folders.length} folders:`, folders.map(f => f.name));

            if (folders.length > 0) {
                // Sort by modified timestamp (newest first) or by name
                folders.sort((a, b) => {
                    // Try sorting by modified_timestamp first (ISO format)
                    if (a.modified_timestamp && b.modified_timestamp) {
                        return new Date(b.modified_timestamp) - new Date(a.modified_timestamp);
                    }
                    // Fall back to sorting by name (descending, assuming YYYYMMDD_HHMMSS format)
                    return b.name.localeCompare(a.name);
                });

                const lastFolder = folders[0];
                console.log('Last measurement folder:', lastFolder.name);
                console.log('Folder details:', lastFolder);

                // Try to parse timestamp from folder name
                // Common formats: YYYYMMDD_HHMMSS, YYYY-MM-DD_HH-MM-SS, or use modified time
                const startTime = parseFolderTimestamp(lastFolder);

                if (startTime) {
                    console.log('✓ Parsed start time from folder:', new Date(startTime));
                    console.log('✓ Storing start time in localStorage:', startTime);
                    localStorage.setItem(TIMER_STORAGE_KEY + unitId, startTime.toString());
                    startMeasurementTimer(unitId);
                } else {
                    // Can't parse folder time - start from now
                    console.warn('✗ Could not parse folder timestamp, starting timer from now');
                    startMeasurementTimer(unitId);
                }
            } else {
                // No folders found - start from now
                console.warn('✗ No measurement folders found in FTP response, starting timer from now');
                startMeasurementTimer(unitId);
            }
        } else {
            // FTP failed or no files - start from now
            console.warn('✗ FTP request failed or returned no files:', result);
            startMeasurementTimer(unitId);
        }
    } catch (error) {
        console.error('✗ Error fetching start time from FTP:', error);
        // Fallback - start from now
        startMeasurementTimer(unitId);
    }
}

// Parse timestamp from folder name or modified time
function parseFolderTimestamp(folder) {
    console.log('Parsing timestamp from folder:', folder.name);

    // Try parsing from folder name first
    // Expected formats: YYYYMMDD_HHMMSS or YYYY-MM-DD_HH-MM-SS
    const name = folder.name;

    // Pattern: YYYYMMDD_HHMMSS (e.g., 20250114_143052)
    const pattern1 = /(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2})/;
    const match1 = name.match(pattern1);
    if (match1) {
        const [_, year, month, day, hour, min, sec] = match1;
        const timestamp = new Date(year, month - 1, day, hour, min, sec).getTime();
        console.log(`  ✓ Matched pattern YYYYMMDD_HHMMSS: ${new Date(timestamp)}`);
        return timestamp;
    }

    // Pattern: YYYY-MM-DD_HH-MM-SS (e.g., 2025-01-14_14-30-52)
    const pattern2 = /(\d{4})-(\d{2})-(\d{2})[_T](\d{2})-(\d{2})-(\d{2})/;
    const match2 = name.match(pattern2);
    if (match2) {
        const [_, year, month, day, hour, min, sec] = match2;
        const timestamp = new Date(year, month - 1, day, hour, min, sec).getTime();
        console.log(`  ✓ Matched pattern YYYY-MM-DD_HH-MM-SS: ${new Date(timestamp)}`);
        return timestamp;
    }

    console.log('  No pattern matched in folder name, trying modified_timestamp field');

    // Try using modified_timestamp (ISO format from SLMM - already in UTC)
    if (folder.modified_timestamp) {
        // SLMM returns timestamps in UTC format without 'Z' suffix
        // Append 'Z' to ensure browser parses as UTC
        let utcTimestamp = folder.modified_timestamp;
        if (!utcTimestamp.endsWith('Z')) {
            utcTimestamp = utcTimestamp + 'Z';
        }
        const timestamp = new Date(utcTimestamp).getTime();
        console.log(`  ✓ Using modified_timestamp (UTC): ${folder.modified_timestamp} → ${new Date(timestamp).toISOString()} → ${new Date(timestamp).toString()}`);
        return timestamp;
    }

    // Fallback to modified (string format)
    if (folder.modified) {
        const parsedTime = new Date(folder.modified).getTime();
        if (!isNaN(parsedTime)) {
            console.log(`  ✓ Using modified field: ${new Date(parsedTime)}`);
            return parsedTime;
        }
        console.log(`  ✗ Could not parse modified field: ${folder.modified}`);
    }

    // Could not parse
    console.log('  ✗ Could not parse any timestamp from folder');
    return null;
}


// Apply status data to the DOM (used by bootstrap data and live refresh)
function applyDeviceStatusData(data) {
    if (!data) {
        return;
    }

    const batteryLevelRaw = data.battery_level ?? '--';
    const batteryLevelElement = document.getElementById('battery-level');
    if (batteryLevelElement) {
        const displayBattery = batteryLevelRaw === '' || batteryLevelRaw === '--'
            ? '--'
            : `${batteryLevelRaw}%`;
        batteryLevelElement.textContent = displayBattery;
    }

    const batteryBar = document.getElementById('battery-bar');
    if (batteryBar && batteryLevelRaw !== '' && batteryLevelRaw !== '--') {
        const level = Number(batteryLevelRaw);
        if (!Number.isNaN(level)) {
            batteryBar.style.width = `${level}%`;
            if (level > 50) {
                batteryBar.className = 'bg-green-500 h-2 rounded-full transition-all';
            } else if (level > 20) {
                batteryBar.className = 'bg-yellow-500 h-2 rounded-full transition-all';
            } else {
                batteryBar.className = 'bg-red-500 h-2 rounded-full transition-all';
            }
        }
    }

    if (document.getElementById('power-source')) {
        document.getElementById('power-source').textContent = data.power_source || '--';
    }

    if (document.getElementById('sd-remaining')) {
        const sdRemainingRaw = data.sd_remaining_mb ?? '--';
        document.getElementById('sd-remaining').textContent = sdRemainingRaw === '--'
            ? '--'
            : `${sdRemainingRaw} MB`;
    }
    if (document.getElementById('sd-ratio')) {
        const sdRatioRaw = data.sd_free_ratio ?? '--';
        document.getElementById('sd-ratio').textContent = sdRatioRaw === '--'
            ? '--'
            : `${sdRatioRaw}% free`;
    }
}


// Auto-refresh status every 30 seconds
let refreshInterval;
const REFRESH_INTERVAL_MS = 30000; // 30 seconds
const unit_id = '{{ unit.id }}';

function updateDeviceStatus() {
    fetch(`/api/slmm/${unit_id}/live`)
        .then(response => response.json())
        .then(result => {
            if (result.status === 'ok' && result.data) {
                applyDeviceStatusData(result.data);

                if (document.getElementById('last-update')) {
                    const now = new Date();
                    document.getElementById('last-update').textContent = now.toLocaleTimeString();
                }
            }
        })
        .catch(error => {
            console.error('Failed to refresh device status:', error);
            // Update last update with error indicator
            if (document.getElementById('last-update')) {
                document.getElementById('last-update').textContent = 'Update failed';
            }
        });
}

// Start auto-refresh
function startAutoRefresh() {
    // Initial update
    updateDeviceStatus();

    // Set up interval
    refreshInterval = setInterval(updateDeviceStatus, REFRESH_INTERVAL_MS);
    console.log('Auto-refresh started (30s interval)');
}

// Stop auto-refresh
function stopAutoRefresh() {
    if (refreshInterval) {
        clearInterval(refreshInterval);
        refreshInterval = null;
        console.log('Auto-refresh stopped');
    }
}

// Bootstrap data from server
const SLM_BOOTSTRAP_DATA = JSON.parse(document.getElementById('slm-bootstrap-data').textContent);

// Initialize immediately when script loads (HTMX loads this partial after DOMContentLoaded)
(async function() {
    console.log('Initializing SLM live view...');

    const unitId = SLM_BOOTSTRAP_DATA.unit_id;
    const isMeasuring = SLM_BOOTSTRAP_DATA.is_measuring;
    const measurementStartTime = SLM_BOOTSTRAP_DATA.measurement_start_time;
    console.log('Is measuring:', isMeasuring);
    console.log('Measurement start time from backend:', measurementStartTime);

    // Start auto-refresh
    startAutoRefresh();

    // Load initial device settings with delays (NL-43 requires 1 second between commands)
    // These are background updates, so we can space them out
    setTimeout(() => getIndexNumber(unitId), 1500);
    setTimeout(() => getDeviceClock(unitId), 3000);
    setTimeout(() => getFrequencyWeighting(unitId), 4500);
    setTimeout(() => getTimeWeighting(unitId), 6000);

    // Initialize measurement timer if device is currently measuring
    if (isMeasuring && measurementStartTime) {
        // Backend has synced the start time from FTP, so database timestamp is now accurate
        let utcTimestamp = measurementStartTime;
        if (!utcTimestamp.endsWith('Z') && !utcTimestamp.includes('+') && !utcTimestamp.includes('-', 10)) {
            utcTimestamp = utcTimestamp + 'Z';
        }

        const startTimeMs = new Date(utcTimestamp).getTime();
        localStorage.setItem(TIMER_STORAGE_KEY + unitId, startTimeMs.toString());

        console.log('✓ Timer initialized from synced database timestamp');
        console.log('  Start time (UTC):', new Date(startTimeMs).toISOString());
        console.log('  Start time (Local):', new Date(startTimeMs).toString());

        startMeasurementTimer(unitId);
    } else if (isMeasuring && !measurementStartTime) {
        // Fallback: Measurement active but no start time - try FTP
        console.warn('⚠ Measurement active but no start time, fetching from FTP...');
        setTimeout(() => resumeMeasurementTimerIfNeeded(unitId, isMeasuring), 500);
    }
})();

// Cleanup on page unload
window.addEventListener('beforeunload', function() {
    if (window.currentWebSocket) {
        window.currentWebSocket.close();
    }
    // Timer will resume on next page load if measurement is still active
    stopMeasurementTimer();
});
// ========================================
// FTP Browser Modal
// ========================================
async function openFTPBrowser(unitId) {
    const modal = document.getElementById('ftp-modal');
    document.getElementById('ftp-unit-id').value = unitId;
    modal.classList.remove('hidden');

    // Check FTP status and update UI
    await updateFTPStatus(unitId);
    loadFTPFiles(unitId, '/');
}

async function updateFTPStatus(unitId) {
    const statusBadge = document.getElementById('ftp-status-badge');

    // Show checking state
    statusBadge.innerHTML = '<div class="animate-spin rounded-full h-3 w-3 border-b-2 border-gray-500 mr-2"></div>Checking...';
    statusBadge.className = 'flex items-center text-xs px-3 py-1 rounded bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-400';

    try {
        const response = await fetch(`/api/slmm/${unitId}/ftp/status`);
        const result = await response.json();

        if (result.status === 'ok' && result.ftp_enabled) {
            statusBadge.innerHTML = '<span class="w-2 h-2 bg-green-500 rounded-full mr-2"></span>FTP Enabled';
            statusBadge.className = 'flex items-center text-xs px-3 py-1 rounded bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400';
        } else {
            statusBadge.innerHTML = '<span class="w-2 h-2 bg-amber-500 rounded-full mr-2"></span>FTP Disabled';
            statusBadge.className = 'flex items-center text-xs px-3 py-1 rounded bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-400';
        }
    } catch (error) {
        statusBadge.innerHTML = '<span class="w-2 h-2 bg-gray-500 rounded-full mr-2"></span>Status Unknown';
        statusBadge.className = 'flex items-center text-xs px-3 py-1 rounded bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-400';
    }
}

function closeFTPBrowser() {
    document.getElementById('ftp-modal').classList.add('hidden');
}

async function loadFTPFiles(unitId, path) {
    const container = document.getElementById('ftp-files-list');
    const pathDisplay = document.getElementById('ftp-current-path');
    const errorDiv = document.getElementById('ftp-error');

    // Update path display
    pathDisplay.textContent = path || '/';

    // Show loading state
    container.innerHTML = '<div class="text-center py-8 text-gray-500"><div class="animate-spin rounded-full h-8 w-8 border-b-2 border-seismo-orange mx-auto mb-2"></div>Loading files...</div>';
    errorDiv.classList.add('hidden');

    try {
        const response = await fetch(`/api/slmm/${unitId}/ftp/files?path=${encodeURIComponent(path)}`);
        const result = await response.json();

        if (response.status === 502) {
            // FTP connection failed - likely not enabled or network issue
            const detail = result.detail || 'Connection failed';
            errorDiv.innerHTML = `
                <div>
                    <div class="flex items-center justify-between mb-3">
                        <div class="flex-1">
                            <p class="font-medium">FTP Connection Failed</p>
                            <p class="text-sm mt-1">${detail}</p>
                        </div>
                        <button onclick="enableFTP('${unitId}')"
                                class="px-4 py-2 bg-seismo-orange text-white rounded-lg hover:bg-orange-600 transition-colors whitespace-nowrap">
                            Enable FTP
                        </button>
                    </div>
                    <div class="text-xs bg-blue-50 dark:bg-blue-900/20 p-3 rounded">
                        <p class="font-medium text-blue-800 dark:text-blue-400 mb-1">Troubleshooting:</p>
                        <ul class="list-disc list-inside space-y-1 text-blue-700 dark:text-blue-300">
                            <li>Click "Enable FTP" to activate FTP on the device</li>
                            <li>Ensure the device is powered on and connected to the network</li>
                            <li>Check that port 21 (FTP) is not blocked by firewalls</li>
                            <li>Verify the modem/IP address is correct in unit settings</li>
                        </ul>
                    </div>
                </div>
            `;
            errorDiv.classList.remove('hidden');
            container.innerHTML = '';
            return;
        }

        if (result.status !== 'ok') {
            throw new Error(result.detail || 'Failed to list files');
        }

        // SLMM returns 'files' not 'data'
        const files = result.files || result.data || [];

        if (files.length === 0) {
            container.innerHTML = '<div class="text-center py-8 text-gray-500">No files found</div>';
            return;
        }

        // Sort: directories first, then by name
        files.sort((a, b) => {
            if (a.type === 'directory' && b.type !== 'directory') return -1;
            if (a.type !== 'directory' && b.type === 'directory') return 1;
            return a.name.localeCompare(b.name);
        });

        let html = '<div class="space-y-1">';

        // Add parent directory link if not at root
        if (path && path !== '/') {
            const parentPath = path.split('/').slice(0, -1).join('/') || '/';
            html += `
                <div class="flex items-center p-3 hover:bg-gray-50 dark:hover:bg-gray-700 rounded cursor-pointer" onclick="loadFTPFiles('${unitId}', '${parentPath}')">
                    <svg class="w-5 h-5 mr-3 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
                    </svg>
                    <span class="text-gray-600 dark:text-gray-400">..</span>
                </div>
            `;
        }

        // Generate unique ID for this folder listing
        const listingId = 'ftp-listing-' + Date.now();

        function escapeForAttribute(str) {
            return String(str).replace(/'/g, "\\'").replace(/"/g, '&quot;');
        }

        function getFileIcon(file) {
            if (file.is_dir || file.type === 'directory') {
                return '<svg class="w-5 h-5 mr-3 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path></svg>';
            } else if (file.name.toLowerCase().endsWith('.csv')) {
                return '<svg class="w-5 h-5 mr-3 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>';
            } else if (file.name.toLowerCase().match(/\.(txt|log)$/)) {
                return '<svg class="w-5 h-5 mr-3 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>';
            }
            return '<svg class="w-5 h-5 mr-3 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path></svg>';
        }

        // Add files and directories
        files.forEach(file => {
            const fullPath = file.path || (path === '/' ? `/${file.name}` : `${path}/${file.name}`);
            const isDir = file.is_dir || file.type === 'directory';
            const icon = getFileIcon(file);
            const sizeText = file.size ? formatFileSize(file.size) : '';
            const dateText = file.modified || file.modified_time || '';
            const canPreview = !isDir && (file.name.toLowerCase().match(/\.(csv|txt|log)$/));
            const folderId = 'folder-' + fullPath.replace(/[^a-zA-Z0-9]/g, '-');

            if (isDir) {
                // Collapsible folder row
                html += `
                    <div class="border border-gray-200 dark:border-gray-600 rounded mb-1">
                        <div class="flex items-center justify-between p-3 hover:bg-gray-50 dark:hover:bg-gray-700 rounded transition-colors cursor-pointer"
                             onclick="toggleFTPFolder('${unitId}', '${escapeForAttribute(fullPath)}', '${folderId}', this)">
                            <div class="flex items-center flex-1">
                                <svg class="w-4 h-4 mr-2 text-gray-400 transition-transform folder-chevron" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
                                </svg>
                                ${icon}
                                <span class="text-gray-900 dark:text-white font-medium">${escapeHtml(file.name)}</span>
                                <span class="ml-2 text-xs text-gray-400 folder-status"></span>
                            </div>
                            <div class="flex items-center gap-3 flex-shrink-0 ml-4">
                                <span class="text-xs text-gray-500 hidden sm:inline">${dateText}</span>
                                <button onclick="event.stopPropagation(); downloadFTPFolderModal('${unitId}', '${escapeForAttribute(fullPath)}', '${escapeForAttribute(file.name)}', this)"
                                        class="px-3 py-1 bg-blue-600 hover:bg-blue-700 text-white text-sm rounded transition-colors flex items-center"
                                        title="Download entire folder as ZIP">
                                    <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
                                    </svg>
                                    <span class="hidden lg:inline">Download ZIP</span>
                                </button>
                            </div>
                        </div>
                        <div id="${folderId}" class="hidden pl-6 pr-2 pb-2 border-t border-gray-100 dark:border-gray-700">
                            <div class="text-sm text-gray-500 py-2">Click to load contents...</div>
                        </div>
                    </div>
                `;
            } else {
                html += `
                    <div class="flex items-center justify-between p-3 hover:bg-gray-50 dark:hover:bg-gray-700 rounded transition-colors group">
                        <div class="flex items-center flex-1 min-w-0">
                            ${icon}
                            <span class="text-gray-900 dark:text-white truncate">${escapeHtml(file.name)}</span>
                        </div>
                        <div class="flex items-center gap-3 flex-shrink-0 ml-4">
                            <span class="text-xs text-gray-500 hidden sm:inline">${sizeText}</span>
                            <span class="text-xs text-gray-500 hidden md:inline">${dateText}</span>
                            ${canPreview ? `
                            <button onclick="previewFile('${unitId}', '${escapeForAttribute(fullPath)}', '${escapeForAttribute(file.name)}')"
                                    class="px-3 py-1 bg-blue-600 hover:bg-blue-700 text-white text-sm rounded transition-colors flex items-center"
                                    title="Preview file">
                                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
                                </svg>
                            </button>
                            ` : ''}
                            <button onclick="downloadFTPFile('${unitId}', '${escapeForAttribute(fullPath)}', '${escapeForAttribute(file.name)}')"
                                    class="px-3 py-1 bg-seismo-orange hover:bg-orange-600 text-white text-sm rounded transition-colors flex items-center"
                                    title="Download to your computer">
                                <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
                                </svg>
                                <span class="hidden lg:inline">Download</span>
                            </button>
                        </div>
                    </div>
                `;
            }
        });

        html += '</div>';
        container.innerHTML = html;

    } catch (error) {
        console.error('Failed to load FTP files:', error);
        errorDiv.textContent = error.message;
        errorDiv.classList.remove('hidden');
        container.innerHTML = '';
    }
}

// Toggle folder expand/collapse and load contents
async function toggleFTPFolder(unitId, folderPath, folderId, headerElement) {
    const contentDiv = document.getElementById(folderId);
    const chevron = headerElement.querySelector('.folder-chevron');
    const statusSpan = headerElement.querySelector('.folder-status');

    if (!contentDiv) return;

    const isExpanded = !contentDiv.classList.contains('hidden');

    if (isExpanded) {
        // Collapse
        contentDiv.classList.add('hidden');
        chevron.style.transform = 'rotate(0deg)';
    } else {
        // Expand and load contents if not already loaded
        contentDiv.classList.remove('hidden');
        chevron.style.transform = 'rotate(90deg)';

        // Check if already loaded
        if (contentDiv.dataset.loaded === 'true') {
            return;
        }

        // Show loading state
        contentDiv.innerHTML = '<div class="text-sm text-gray-500 py-2 flex items-center"><svg class="w-4 h-4 mr-2 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg>Loading...</div>';

        try {
            const response = await fetch(`/api/slmm/${unitId}/ftp/files?path=${encodeURIComponent(folderPath)}`);
            const result = await response.json();

            if (result.status !== 'ok') {
                throw new Error(result.detail || 'Failed to list files');
            }

            const files = result.files || [];

            if (files.length === 0) {
                contentDiv.innerHTML = '<div class="text-sm text-gray-500 py-2 italic">Empty folder</div>';
                statusSpan.textContent = '(empty)';
                contentDiv.dataset.loaded = 'true';
                return;
            }

            // Sort: directories first, then by name
            files.sort((a, b) => {
                if (a.type === 'directory' && b.type !== 'directory') return -1;
                if (a.type !== 'directory' && b.type === 'directory') return 1;
                return a.name.localeCompare(b.name);
            });

            // Update status with file count
            const dirCount = files.filter(f => f.type === 'directory' || f.is_dir).length;
            const fileCount = files.length - dirCount;
            let statusText = [];
            if (dirCount > 0) statusText.push(`${dirCount} folder${dirCount > 1 ? 's' : ''}`);
            if (fileCount > 0) statusText.push(`${fileCount} file${fileCount > 1 ? 's' : ''}`);
            statusSpan.textContent = `(${statusText.join(', ')})`;

            function escapeForAttribute(str) {
                return String(str).replace(/'/g, "\\'").replace(/"/g, '&quot;');
            }

            function escapeHtml(str) {
                const div = document.createElement('div');
                div.textContent = str;
                return div.innerHTML;
            }

            function getFileIcon(file) {
                if (file.is_dir || file.type === 'directory') {
                    return '<svg class="w-4 h-4 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path></svg>';
                } else if (file.name.toLowerCase().endsWith('.csv')) {
                    return '<svg class="w-4 h-4 mr-2 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>';
                } else if (file.name.toLowerCase().match(/\.(txt|log)$/)) {
                    return '<svg class="w-4 h-4 mr-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>';
                }
                return '<svg class="w-4 h-4 mr-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"></path></svg>';
            }

            let html = '<div class="space-y-1 mt-2">';

            files.forEach(file => {
                const fullPath = file.path || `${folderPath}/${file.name}`;
                const isDir = file.is_dir || file.type === 'directory';
                const icon = getFileIcon(file);
                const sizeText = file.size ? formatFileSize(file.size) : '';
                const dateText = file.modified || file.modified_time || '';
                const canPreview = !isDir && (file.name.toLowerCase().match(/\.(csv|txt|log)$/));
                const subFolderId = 'folder-' + fullPath.replace(/[^a-zA-Z0-9]/g, '-');

                if (isDir) {
                    // Nested collapsible folder
                    html += `
                        <div class="border border-gray-200 dark:border-gray-600 rounded">
                            <div class="flex items-center justify-between p-2 hover:bg-gray-50 dark:hover:bg-gray-700 rounded transition-colors cursor-pointer text-sm"
                                 onclick="toggleFTPFolder('${unitId}', '${escapeForAttribute(fullPath)}', '${subFolderId}', this)">
                                <div class="flex items-center flex-1">
                                    <svg class="w-3 h-3 mr-2 text-gray-400 transition-transform folder-chevron" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
                                    </svg>
                                    ${icon}
                                    <span class="text-gray-900 dark:text-white font-medium">${escapeHtml(file.name)}</span>
                                    <span class="ml-2 text-xs text-gray-400 folder-status"></span>
                                </div>
                                <div class="flex items-center gap-2 flex-shrink-0 ml-2">
                                    <button onclick="event.stopPropagation(); downloadFTPFolderModal('${unitId}', '${escapeForAttribute(fullPath)}', '${escapeForAttribute(file.name)}', this)"
                                            class="px-2 py-1 bg-blue-600 hover:bg-blue-700 text-white text-xs rounded transition-colors flex items-center"
                                            title="Download entire folder as ZIP">
                                        <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
                                        </svg>
                                    </button>
                                </div>
                            </div>
                            <div id="${subFolderId}" class="hidden pl-4 pr-2 pb-2 border-t border-gray-100 dark:border-gray-700">
                                <div class="text-sm text-gray-500 py-2">Click to load contents...</div>
                            </div>
                        </div>
                    `;
                } else {
                    html += `
                        <div class="flex items-center justify-between p-2 hover:bg-gray-50 dark:hover:bg-gray-700 rounded transition-colors text-sm">
                            <div class="flex items-center flex-1 min-w-0">
                                ${icon}
                                <span class="text-gray-900 dark:text-white truncate">${escapeHtml(file.name)}</span>
                            </div>
                            <div class="flex items-center gap-2 flex-shrink-0 ml-2">
                                <span class="text-xs text-gray-500 hidden sm:inline">${sizeText}</span>
                                ${canPreview ? `
                                <button onclick="previewFile('${unitId}', '${escapeForAttribute(fullPath)}', '${escapeForAttribute(file.name)}')"
                                        class="px-2 py-1 bg-blue-600 hover:bg-blue-700 text-white text-xs rounded transition-colors"
                                        title="Preview file">
                                    <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
                                    </svg>
                                </button>
                                ` : ''}
                                <button onclick="downloadFTPFile('${unitId}', '${escapeForAttribute(fullPath)}', '${escapeForAttribute(file.name)}')"
                                        class="px-2 py-1 bg-seismo-orange hover:bg-orange-600 text-white text-xs rounded transition-colors"
                                        title="Download to your computer">
                                    <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
                                    </svg>
                                </button>
                            </div>
                        </div>
                    `;
                }
            });

            html += '</div>';
            contentDiv.innerHTML = html;
            contentDiv.dataset.loaded = 'true';

        } catch (error) {
            console.error('Failed to load folder contents:', error);
            contentDiv.innerHTML = `<div class="text-sm text-red-500 py-2">Error: ${error.message}</div>`;
        }
    }
}

async function downloadFTPFile(unitId, filePath, fileName) {
    try {
        // Show download indicator
        const downloadBtn = event.target;
        const originalText = downloadBtn.innerHTML;
        downloadBtn.innerHTML = '<svg class="w-4 h-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg>';
        downloadBtn.disabled = true;

        const response = await fetch(`/api/slmm/${unitId}/ftp/download`, {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ remote_path: filePath })
        });

        if (!response.ok) {
            throw new Error('Download failed');
        }

        // The response is a file, so we need to create a download link
        const blob = await response.blob();
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = fileName || filePath.split('/').pop();
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        window.URL.revokeObjectURL(url);

        // Reset button
        downloadBtn.innerHTML = originalText;
        downloadBtn.disabled = false;

        // Show success message briefly
        const originalBtnClass = downloadBtn.className;
        downloadBtn.className = downloadBtn.className.replace('bg-seismo-orange', 'bg-green-600');
        setTimeout(() => {
            downloadBtn.className = originalBtnClass;
        }, 2000);

    } catch (error) {
        console.error('Failed to download file:', error);
        alert('Failed to download file: ' + error.message);
        // Reset button on error
        if (event.target) {
            event.target.innerHTML = originalText;
            event.target.disabled = false;
        }
    }
}

async function downloadFTPFolderModal(unitId, folderPath, folderName, btnElement) {
    // Get the button element - either passed as argument or from event
    const downloadBtn = btnElement || event.target;
    const originalText = downloadBtn.innerHTML;

    try {
        // Show download indicator
        downloadBtn.innerHTML = '<svg class="w-4 h-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg>';
        downloadBtn.disabled = true;

        const response = await fetch(`/api/slmm/${unitId}/ftp/download-folder`, {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ remote_path: folderPath })
        });

        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            throw new Error(errorData.detail || 'Folder download failed');
        }

        // The response is a ZIP file
        const blob = await response.blob();
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `${folderName}.zip`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        window.URL.revokeObjectURL(url);

        // Reset button
        downloadBtn.innerHTML = originalText;
        downloadBtn.disabled = false;

        // Show success message briefly
        const originalBtnClass = downloadBtn.className;
        downloadBtn.className = downloadBtn.className.replace('bg-blue-600', 'bg-green-600');
        setTimeout(() => {
            downloadBtn.className = originalBtnClass;
        }, 2000);

    } catch (error) {
        console.error('Failed to download folder:', error);
        alert('Failed to download folder: ' + error.message);
        // Reset button on error
        downloadBtn.innerHTML = originalText;
        downloadBtn.disabled = false;
    }
}

async function downloadToServer(unitId, filePath, fileName) {
    try {
        const response = await fetch(`/api/slmm/${unitId}/ftp/download`, {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ remote_path: filePath, save_to_server: true })
        });

        const result = await response.json();

        if (result.status === 'ok') {
            alert(`File saved to server at: ${result.local_path}`);
        } else {
            throw new Error(result.detail || 'Failed to save to server');
        }

    } catch (error) {
        console.error('Failed to save file to server:', error);
        alert('Failed to save file to server: ' + error.message);
    }
}

async function previewFile(unitId, filePath, fileName) {
    const modal = document.getElementById('preview-modal');
    const previewContent = document.getElementById('preview-content');
    const previewTitle = document.getElementById('preview-title');

    previewTitle.textContent = fileName;
    previewContent.innerHTML = '<div class="text-center py-8"><div class="animate-spin rounded-full h-8 w-8 border-b-2 border-seismo-orange mx-auto mb-2"></div>Loading preview...</div>';
    modal.classList.remove('hidden');

    try {
        const response = await fetch(`/api/slmm/${unitId}/ftp/download`, {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({ remote_path: filePath })
        });

        if (!response.ok) {
            throw new Error('Failed to load file');
        }

        const blob = await response.blob();
        const text = await blob.text();

        // Check file type for syntax highlighting
        const isCSV = fileName.toLowerCase().endsWith('.csv');
        const isTXT = fileName.toLowerCase().endsWith('.txt') || fileName.toLowerCase().endsWith('.log');

        if (isCSV) {
            // Parse and display CSV as table
            const lines = text.split('\n').filter(l => l.trim());
            if (lines.length > 0) {
                const headers = lines[0].split(',');
                let tableHTML = '<div class="overflow-x-auto"><table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700"><thead class="bg-gray-50 dark:bg-gray-800"><tr>';
                headers.forEach(h => {
                    tableHTML += `<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">${h.trim()}</th>`;
                });
                tableHTML += '</tr></thead><tbody class="bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700">';

                for (let i = 1; i < Math.min(lines.length, 101); i++) {
                    const cells = lines[i].split(',');
                    tableHTML += '<tr>';
                    cells.forEach(c => {
                        tableHTML += `<td class="px-4 py-2 text-sm text-gray-900 dark:text-gray-100">${c.trim()}</td>`;
                    });
                    tableHTML += '</tr>';
                }

                tableHTML += '</tbody></table></div>';
                if (lines.length > 101) {
                    tableHTML += `<p class="text-sm text-gray-500 mt-4 text-center">Showing first 100 rows of ${lines.length - 1} total rows</p>`;
                }
                previewContent.innerHTML = tableHTML;
            }
        } else {
            // Display as plain text with line numbers
            const lines = text.split('\n');
            const maxLines = 1000;
            const displayLines = lines.slice(0, maxLines);

            let preHTML = '<pre class="text-xs font-mono bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto"><code>';
            displayLines.forEach((line, i) => {
                preHTML += `<span class="text-gray-500">${String(i + 1).padStart(4, ' ')}</span>  ${escapeHtml(line)}\n`;
            });
            preHTML += '</code></pre>';

            if (lines.length > maxLines) {
                preHTML += `<p class="text-sm text-gray-500 mt-4 text-center">Showing first ${maxLines} lines of ${lines.length} total lines</p>`;
            }

            previewContent.innerHTML = preHTML;
        }
    } catch (error) {
        console.error('Failed to preview file:', error);
        previewContent.innerHTML = `<div class="text-center py-8 text-red-500">Failed to load preview: ${error.message}</div>`;
    }
}

function closePreviewModal() {
    document.getElementById('preview-modal').classList.add('hidden');
}

function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

async function enableFTP(unitId) {
    const errorDiv = document.getElementById('ftp-error');
    const container = document.getElementById('ftp-files-list');

    // Show loading state
    errorDiv.innerHTML = '<div class="flex items-center"><div class="animate-spin rounded-full h-5 w-5 border-b-2 border-seismo-orange mr-3"></div>Enabling FTP on device...</div>';
    errorDiv.classList.remove('hidden');

    try {
        const response = await fetch(`/api/slmm/${unitId}/ftp/enable`, {
            method: 'POST'
        });

        const result = await response.json();

        if (result.status !== 'ok') {
            throw new Error(result.detail || 'Failed to enable FTP');
        }

        // Success - wait a moment then try loading files again
        errorDiv.innerHTML = '<div class="flex items-center text-green-600 dark:text-green-400"><svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>FTP enabled successfully. Loading files...</div>';

        setTimeout(() => {
            loadFTPFiles(unitId, '/');
        }, 2000);

    } catch (error) {
        console.error('Failed to enable FTP:', error);
        errorDiv.innerHTML = `
            <div>
                <p class="font-medium text-red-600 dark:text-red-400">Failed to enable FTP</p>
                <p class="text-sm mt-1">${error.message}</p>
                <button onclick="loadFTPFiles('${unitId}', '/')"
                        class="mt-2 px-3 py-1 bg-gray-600 text-white text-sm rounded hover:bg-gray-700 transition-colors">
                    Retry Connection
                </button>
            </div>
        `;
        errorDiv.classList.remove('hidden');
    }
}

async function enableFTPFromHeader() {
    const unitId = document.getElementById('ftp-unit-id').value;
    const statusBadge = document.getElementById('ftp-status-badge');
    const errorDiv = document.getElementById('ftp-error');

    // Show enabling state
    statusBadge.innerHTML = '<div class="animate-spin rounded-full h-3 w-3 border-b-2 border-seismo-orange mr-2"></div>Enabling...';
    statusBadge.className = 'flex items-center text-xs px-3 py-1 rounded bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-400';
    errorDiv.classList.add('hidden');

    try {
        const response = await fetch(`/api/slmm/${unitId}/ftp/enable`, {
            method: 'POST'
        });
        const result = await response.json();

        if (result.status !== 'ok') {
            throw new Error(result.detail || 'Failed to enable FTP');
        }

        // Update status badge
        statusBadge.innerHTML = '<span class="w-2 h-2 bg-green-500 rounded-full mr-2"></span>FTP Enabled';
        statusBadge.className = 'flex items-center text-xs px-3 py-1 rounded bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400';

        // Show success message and refresh files
        errorDiv.innerHTML = '<div class="flex items-center text-green-600 dark:text-green-400"><svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>FTP enabled successfully</div>';
        errorDiv.classList.remove('hidden');

        setTimeout(() => {
            errorDiv.classList.add('hidden');
            loadFTPFiles(unitId, '/');
        }, 2000);

    } catch (error) {
        console.error('Failed to enable FTP:', error);
        statusBadge.innerHTML = '<span class="w-2 h-2 bg-red-500 rounded-full mr-2"></span>Enable Failed';
        statusBadge.className = 'flex items-center text-xs px-3 py-1 rounded bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400';

        errorDiv.innerHTML = `<p class="font-medium">Failed to enable FTP:</p><p class="text-sm mt-1">${error.message}</p>`;
        errorDiv.classList.remove('hidden');
    }
}

async function disableFTPFromHeader() {
    const unitId = document.getElementById('ftp-unit-id').value;
    const statusBadge = document.getElementById('ftp-status-badge');
    const errorDiv = document.getElementById('ftp-error');

    // Show disabling state
    statusBadge.innerHTML = '<div class="animate-spin rounded-full h-3 w-3 border-b-2 border-amber-500 mr-2"></div>Disabling...';
    statusBadge.className = 'flex items-center text-xs px-3 py-1 rounded bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-400';
    errorDiv.classList.add('hidden');

    try {
        const response = await fetch(`/api/slmm/${unitId}/ftp/disable`, {
            method: 'POST'
        });
        const result = await response.json();

        if (result.status !== 'ok') {
            throw new Error(result.detail || 'Failed to disable FTP');
        }

        // Update status badge
        statusBadge.innerHTML = '<span class="w-2 h-2 bg-amber-500 rounded-full mr-2"></span>FTP Disabled';
        statusBadge.className = 'flex items-center text-xs px-3 py-1 rounded bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-400';

        // Show success message and clear files
        errorDiv.innerHTML = '<div class="flex items-center text-amber-600 dark:text-amber-400"><svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg>FTP disabled successfully</div>';
        errorDiv.classList.remove('hidden');

        document.getElementById('ftp-files-list').innerHTML = '<div class="text-center py-8 text-gray-500">FTP is disabled. Enable it to browse files.</div>';

        setTimeout(() => {
            errorDiv.classList.add('hidden');
        }, 3000);

    } catch (error) {
        console.error('Failed to disable FTP:', error);
        statusBadge.innerHTML = '<span class="w-2 h-2 bg-red-500 rounded-full mr-2"></span>Disable Failed';
        statusBadge.className = 'flex items-center text-xs px-3 py-1 rounded bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400';

        errorDiv.innerHTML = `<p class="font-medium">Failed to disable FTP:</p><p class="text-sm mt-1">${error.message}</p>`;
        errorDiv.classList.remove('hidden');
    }
}

function refreshFTPFiles() {
    const unitId = document.getElementById('ftp-unit-id').value;
    const currentPath = document.getElementById('ftp-current-path').textContent;

    // Update status
    updateFTPStatus(unitId);

    // Reload files at current path
    loadFTPFiles(unitId, currentPath);
}

function formatFileSize(bytes) {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
}

// Close modals on Escape key
document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape') {
        closeSettingsModal();
        closeFTPBrowser();
    }
});

// Close modals when clicking outside
document.getElementById('settings-modal')?.addEventListener('click', function(e) {
    if (e.target === this) {
        closeSettingsModal();
    }
});

document.getElementById('ftp-modal')?.addEventListener('click', function(e) {
    if (e.target === this) {
        closeFTPBrowser();
    }
});

document.getElementById('preview-modal')?.addEventListener('click', function(e) {
    if (e.target === this) {
        closePreviewModal();
    }
});
</script>

<!-- FTP Browser Modal -->
<div id="ftp-modal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center">
    <div class="bg-white dark:bg-slate-800 rounded-xl shadow-2xl w-full max-w-4xl max-h-[90vh] overflow-hidden m-4 flex flex-col">
        <div class="p-6 border-b border-gray-200 dark:border-gray-700">
            <div class="flex items-center justify-between mb-4">
                <h3 class="text-xl font-bold text-gray-900 dark:text-white">FTP File Browser</h3>
                <button onclick="closeFTPBrowser()" class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
                    <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
                    </svg>
                </button>
            </div>

            <div class="flex items-center justify-between">
                <div class="flex items-center gap-4">
                    <p class="text-sm text-gray-600 dark:text-gray-400">
                        Path: <span id="ftp-current-path" class="font-mono">/</span>
                    </p>
                    <div id="ftp-status-badge" class="flex items-center text-xs px-3 py-1 rounded bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-400">
                        <div class="animate-spin rounded-full h-3 w-3 border-b-2 border-gray-500 mr-2"></div>
                        Checking...
                    </div>
                </div>

                <div class="flex items-center gap-2">
                    <button id="ftp-enable-btn" onclick="enableFTPFromHeader()"
                            class="px-3 py-1.5 bg-green-600 hover:bg-green-700 text-white text-sm rounded-lg flex items-center transition-colors">
                        <svg class="w-4 h-4 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
                        </svg>
                        Enable FTP
                    </button>

                    <button id="ftp-disable-btn" onclick="disableFTPFromHeader()"
                            class="px-3 py-1.5 bg-amber-600 hover:bg-amber-700 text-white text-sm rounded-lg flex items-center transition-colors">
                        <svg class="w-4 h-4 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
                        </svg>
                        Disable FTP
                    </button>

                    <button id="ftp-refresh-btn" onclick="refreshFTPFiles()"
                            class="px-3 py-1.5 bg-seismo-orange hover:bg-orange-600 text-white text-sm rounded-lg flex items-center transition-colors">
                        <svg class="w-4 h-4 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
                        </svg>
                        Refresh
                    </button>
                </div>
            </div>
        </div>

        <div class="flex-1 overflow-y-auto p-6">
            <input type="hidden" id="ftp-unit-id">

            <div id="ftp-error" class="hidden mb-4 p-4 bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400 rounded-lg text-sm"></div>

            <div id="ftp-files-list">
                <!-- Files will be loaded here -->
            </div>
        </div>
    </div>
</div>

<!-- File Preview Modal -->
<div id="preview-modal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
    <div class="bg-white dark:bg-slate-800 rounded-xl shadow-2xl w-full max-w-6xl max-h-[90vh] overflow-hidden flex flex-col">
        <div class="p-6 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between flex-shrink-0">
            <h3 class="text-xl font-bold text-gray-900 dark:text-white flex items-center">
                <svg class="w-6 h-6 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
                </svg>
                <span id="preview-title">File Preview</span>
            </h3>
            <button onclick="closePreviewModal()" class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
                </svg>
            </button>
        </div>

        <div class="flex-1 overflow-y-auto p-6 bg-gray-50 dark:bg-gray-900" id="preview-content">
            <!-- Preview content will be loaded here -->
        </div>
    </div>
</div>

<!-- Unified SLM Settings Modal -->
{% include 'partials/slm_settings_modal.html' %}
