/**
 * @file ui.js
 * @description This module manages all UI interactions and updates.
 * It bridges the gap between backend data (from API and WebSockets) and the user-facing components,
 * handling everything from theme changes to dynamic content updates.
 */

import * as bootstrap from 'bootstrap';
import * as dom from './dom.js';
import * as api from './api.js';
import {formatUptime, isMobile} from './utils.js';
import {applyTerminalTheme, fitTerminal} from './terminal.js';
import {applyChartsTheme, resizeCharts, updateCharts} from './chart.js';

// Instance of the Bootstrap Modal for Wi-Fi connection
let wifiModal;

/**
 * Initializes the UI components, such as the Bootstrap modal.
 */
export function initUI() {
    wifiModal = new bootstrap.Modal(dom.wifiModalEl);
}

/**
 * Applies the selected theme (light or dark) to the entire application.
 * @param {string} themeName - The name of the theme ('light' or 'dark').
 */
export function applyTheme(themeName) {
    const isDark = themeName === 'dark';
    dom.htmlEl.setAttribute('data-bs-theme', themeName);
    dom.themeIcon.className = isDark ? 'bi bi-moon-stars-fill' : 'bi bi-sun-fill';
    dom.themeToggle.checked = isDark;
    applyTerminalTheme(themeName);
    applyChartsTheme(themeName);
}

/**
 * Updates the UI with the latest sensor data.
 * @param {Object} data - The sensor data object from the WebSocket.
 */
export function updateSensorUI(data) {
    // Display VIN channel data in the header as a primary overview
    if (data.VIN) {
        dom.voltageDisplay.textContent = `${data.VIN.voltage.toFixed(2)} V`;
        dom.currentDisplay.textContent = `${data.VIN.current.toFixed(2)} A`;
        dom.powerDisplay.textContent = `${data.VIN.power.toFixed(2)} W`;
    }

    // Pass the entire multi-channel data object to the charts
    updateCharts(data);
}

/**
 * Updates the system uptime display in the UI.
 * @param {number} uptimeInSeconds - The system uptime in seconds.
 */
export function updateUptimeUI(uptimeInSeconds) {
    if (uptimeInSeconds !== undefined) {
        dom.uptimeDisplay.textContent = formatUptime(uptimeInSeconds);
    }
}

/**
 * Updates the power switch toggle states based on WebSocket data.
 * @param {Object} swStatus - The switch status object from the WebSocket message.
 */
export function updateSwitchStatusUI(swStatus) {
    if (swStatus) {
        if (swStatus.main !== undefined) {
            dom.mainPowerToggle.checked = swStatus.main;
        }
        if (swStatus.usb !== undefined) {
            dom.usbPowerToggle.checked = swStatus.usb;
        }
    }
}

/**
 * Updates the Wi-Fi status indicator in the header.
 * @param {Object} data - The Wi-Fi status object from the WebSocket.
 */
export function updateWifiStatusUI(data) {
    if (data.connected) {
        dom.wifiSsidStatus.textContent = data.ssid;
        dom.wifiStatus.title = `Signal Strength: ${data.rssi} dBm`;
        let iconClass = 'bi me-2 ';
        if (data.rssi >= -60) iconClass += 'bi-wifi';
        else if (data.rssi >= -75) iconClass += 'bi-wifi-2';
        else iconClass += 'bi-wifi-1';
        dom.wifiIcon.className = iconClass;
        dom.wifiStatus.classList.replace('text-muted', 'text-success');
        dom.wifiStatus.classList.remove('text-danger');
    } else {
        dom.wifiSsidStatus.textContent = 'Disconnected';
        dom.wifiStatus.title = '';
        dom.wifiIcon.className = 'bi bi-wifi-off me-2';
        dom.wifiStatus.classList.replace('text-success', 'text-muted');
        dom.wifiStatus.classList.remove('text-danger');
    }
}

/**
 * Initiates a Wi-Fi scan and updates the settings modal with the results.
 */
export async function scanForWifi() {
    dom.scanWifiButton.disabled = true;
    dom.scanWifiButton.innerHTML = `<span class="spinner-border spinner-border-sm" aria-hidden="true"></span> Scanning...`;
    dom.wifiApList.innerHTML = '<tr><td colspan="3" class="text-center">Scanning for networks...</td></tr>';

    try {
        const apRecords = await api.fetchWifiScan();
        dom.wifiApList.innerHTML = ''; // Clear loading message

        if (apRecords.length === 0) {
            dom.wifiApList.innerHTML = '<tr><td colspan="3" class="text-center">No networks found.</td></tr>';
        } else {
            apRecords.forEach(ap => {
                const row = document.createElement('tr');
                row.className = 'wifi-ap-row';

                let rssiIcon;
                if (ap.rssi >= -60) rssiIcon = 'bi-wifi';
                else if (ap.rssi >= -75) rssiIcon = 'bi-wifi-2';
                else rssiIcon = 'bi-wifi-1';

                row.innerHTML = `
                    <td>${ap.ssid}</td>
                    <td class="text-center"><i class="bi ${rssiIcon}"></i></td>
                    <td>${ap.authmode}</td>
                `;

                row.addEventListener('click', () => {
                    dom.wifiSsidConnectInput.value = ap.ssid;
                    dom.wifiPasswordConnectInput.value = '';
                    wifiModal.show();
                    dom.wifiModalEl.addEventListener('shown.bs.modal', () => {
                        dom.wifiPasswordConnectInput.focus();
                    }, {once: true});
                });

                dom.wifiApList.appendChild(row);
            });
        }
    } catch (error) {
        console.error('Error scanning for Wi-Fi:', error);
        dom.wifiApList.innerHTML = `<tr><td colspan="3" class="text-center text-danger">Scan failed: ${error.message}</td></tr>`;
    } finally {
        dom.scanWifiButton.disabled = false;
        dom.scanWifiButton.innerHTML = 'Scan';
    }
}

/**
 * Handles the Wi-Fi connection process, sending credentials to the server.
 */
export async function connectToWifi() {
    const ssid = dom.wifiSsidConnectInput.value;
    const password = dom.wifiPasswordConnectInput.value;
    if (!ssid) return;

    dom.wifiConnectButton.disabled = true;
    dom.wifiConnectButton.innerHTML = `<span class="spinner-border spinner-border-sm" aria-hidden="true"></span> Connecting...`;

    try {
        const result = await api.postWifiConnect(ssid, password);
        if (result.status === 'connection_initiated') {
            wifiModal.hide();
            setTimeout(() => {
                alert(`Connection to "${ssid}" initiated. The device will try to reconnect. Please check the Wi-Fi status icon.`);
            }, 500);
        } else {
            throw new Error(result.message || 'Unknown server response.');
        }
    } catch (error) {
        console.error('Error connecting to Wi-Fi:', error);
        alert(`Failed to connect: ${error.message}`);
    } finally {
        dom.wifiConnectButton.disabled = false;
        dom.wifiConnectButton.innerHTML = 'Connect';
    }
}

/**
 * Applies network settings (Static IP or DHCP) by sending the configuration to the server.
 */
export async function applyNetworkSettings() {
    const useStatic = dom.staticIpToggle.checked;
    let payload;

    dom.networkApplyButton.disabled = true;
    dom.networkApplyButton.innerHTML = `<span class="spinner-border spinner-border-sm" aria-hidden="true"></span> Applying...`;

    if (useStatic) {
        const ip = dom.staticIpInput.value;
        const gateway = dom.staticGatewayInput.value;
        const subnet = dom.staticNetmaskInput.value;
        const dns1 = dom.dns1Input.value;
        const dns2 = dom.dns2Input.value;

        if (!ip || !gateway || !subnet || !dns1) {
            alert('For static IP, you must provide IP Address, Gateway, Netmask, and DNS Server.');
            dom.networkApplyButton.disabled = false;
            dom.networkApplyButton.innerHTML = 'Apply';
            return;
        }

        payload = {net_type: 'static', ip, gateway, subnet, dns1};
        if (dns2) payload.dns2 = dns2;
    } else {
        payload = {net_type: 'dhcp'};
    }

    try {
        await api.postNetworkSettings(payload);
        alert('Network settings applied. Reconnect to the network for changes to take effect.');
        initializeSettings();
    } catch (error) {
        console.error('Error applying network settings:', error);
        alert(`Failed to apply settings: ${error.message}`);
    } finally {
        dom.networkApplyButton.disabled = false;
        dom.networkApplyButton.innerHTML = 'Apply';
    }
}

/**
 * Applies AP Mode settings (AP+STA or STA) by sending the configuration to the server.
 */
export async function applyApModeSettings() {
    const mode = dom.apModeToggle.checked ? 'apsta' : 'sta';
    let payload = {mode};

    dom.apModeApplyButton.disabled = true;
    dom.apModeApplyButton.innerHTML = `<span class="spinner-border spinner-border-sm" aria-hidden="true"></span> Applying...`;

    if (mode === 'apsta') {
        const ap_ssid = dom.apSsidInput.value;
        const ap_password = dom.apPasswordInput.value;

        if (!ap_ssid) {
            alert('AP SSID cannot be empty when enabling APSTA mode.');
            dom.apModeApplyButton.disabled = false;
            dom.apModeApplyButton.innerHTML = 'Apply';
            return;
        }
        payload.ap_ssid = ap_ssid;
        if (ap_password) {
            payload.ap_password = ap_password;
        }
    }

    try {
        await api.postNetworkSettings(payload); // Reuses the same API endpoint
        alert(`Successfully switched mode to ${mode}. The device will now reconfigure.`);
        initializeSettings();
    } catch (error) {
        console.error('Error switching Wi-Fi mode:', error);
        alert(`Failed to switch mode: ${error.message}`);
    } finally {
        dom.apModeApplyButton.disabled = false;
        dom.apModeApplyButton.innerHTML = 'Apply';
    }
}

/**
 * Applies the selected UART baud rate by sending it to the server.
 */
export async function applyBaudRateSettings() {
    const baudrate = dom.baudRateSelect.value;
    dom.baudRateApplyButton.disabled = true;
    dom.baudRateApplyButton.innerHTML = `<span class="spinner-border spinner-border-sm" aria-hidden="true"></span> Applying...`;

    try {
        await api.postBaudRateSetting(baudrate);
    } catch (error) {
        console.error('Error applying baud rate:', error);
    } finally {
        dom.baudRateApplyButton.disabled = false;
        dom.baudRateApplyButton.innerHTML = 'Apply';
    }
}

/**
 * Fetches and displays the current network and device settings in the settings modal.
 */
export async function initializeSettings() {
    try {
        const data = await api.fetchSettings();

        // Wi-Fi Connection Status
        if (data.connected) {
            dom.currentWifiSsid.textContent = data.ssid;
            dom.currentWifiIp.textContent = `IP Address: ${data.ip ? data.ip.ip : 'N/A'}`;
        } else {
            dom.currentWifiSsid.textContent = 'Not Connected';
            dom.currentWifiIp.textContent = 'IP Address: -';
        }

        // Network (Static/DHCP) Settings
        if (data.ip) {
            dom.staticIpInput.value = data.ip.ip || '';
            dom.staticGatewayInput.value = data.ip.gateway || '';
            dom.staticNetmaskInput.value = data.ip.subnet || '';
            dom.dns1Input.value = data.ip.dns1 || '';
            dom.dns2Input.value = data.ip.dns2 || '';
        }
        dom.staticIpToggle.checked = data.net_type === 'static';
        dom.staticIpConfig.style.display = dom.staticIpToggle.checked ? 'block' : 'none';

        // AP Mode Settings
        dom.apModeToggle.checked = data.mode === 'apsta';
        dom.apModeConfig.style.display = dom.apModeToggle.checked ? 'block' : 'none';
        dom.apSsidInput.value = ''; // For security, don't pre-fill
        dom.apPasswordInput.value = '';

        // Device Settings
        if (data.baudrate) {
            dom.baudRateSelect.value = data.baudrate;
        }

    } catch (error) {
        console.error('Error initializing settings:', error);
        // Reset fields on error
        dom.currentWifiSsid.textContent = 'Status Unknown';
        dom.currentWifiIp.textContent = 'IP Address: -';
        dom.staticIpToggle.checked = false;
        dom.staticIpConfig.style.display = 'none';
        dom.apModeToggle.checked = false;
        dom.apModeConfig.style.display = 'none';
    }
}

/**
 * Fetches and updates the status of the power control toggles.
 */
export async function updateControlStatus() {
    try {
        const status = await api.fetchControlStatus();
        dom.mainPowerToggle.checked = status.load_12v_on;
        dom.usbPowerToggle.checked = status.load_5v_on;
    } catch (error) {
        console.error('Error fetching control status:', error);
    }
}

/**
 * Handles window resize events to make components responsive.
 */
export function handleResize() {
    if (isMobile()) {
        fitTerminal();
    }
    resizeCharts();
}

/**
 * Updates the WebSocket connection status indicator in the header.
 * @param {boolean} isConnected - True if the WebSocket is connected, false otherwise.
 */
export function updateWebsocketStatus(isConnected) {
    if (isConnected) {
        dom.websocketStatusText.textContent = 'Online';
        dom.websocketIcon.className = 'bi bi-check-circle-fill me-2';
        dom.websocketStatus.classList.remove('text-danger');
        dom.websocketStatus.classList.add('text-success');
    } else {
        dom.websocketStatusText.textContent = 'Offline';
        dom.websocketIcon.className = 'bi bi-x-circle-fill me-2';
        dom.websocketStatus.classList.remove('text-success');
        dom.websocketStatus.classList.add('text-danger');
    }
}
