// web/src/app.ts - Оркестратор приложения

import {
    fetchHealth,
    fetchHistory
} from "./data.js";
import {
    state,
    addSignals,
    resetBufferTracking,
    updatePeakHolder,
    updateSignalPeakHolder,
    setPeakHolderListener
} from "./state.js";
import {
    initDOM,
    setServerTime,
    setStatus,
    setMeta,
    setBars,
    setSignal,
    setAudioIndicator,
    DOM,
    setChannelValue,
    setChannelCurrentValue,
    channelElements
} from "./ui.js";
import { initAccordion } from "./accordion.js";
import { drawChart } from "./chart.js";
import { initResize } from "./layout.js";
import { initCamera } from "./camera.js";
import { audioEngine } from "./audio.js";

let lastChart: number = 0;
let connectionLost: boolean = false;
let consecutiveErrors: number = 0;
const MAX_ERRORS: number = 3;
let pollTimer: number | null = null;
let lastSignalLevel: number = 0;

// ===== ИНИЦИАЛИЗАЦИЯ РЕГУЛЯТОРА ГРОМКОСТИ =====
function initVolumeControl(): void {
    const slider = document.getElementById('volumeSlider') as HTMLInputElement | null;
    const trackFill = document.getElementById('volumeTrackFill') as HTMLElement | null;
    const indicator = document.getElementById('audio-indicator');
    const wrapper = document.getElementById('audioWrapper');

    if (!slider || !trackFill || !indicator) return;

    // Функция обновления заливки
    function updateTrackFill(volume: number): void {
        if (trackFill) {
            trackFill.style.width = `${volume}%`;
        }
    }

    // Функция обновления индикатора в зависимости от громкости и уровня сигнала
    function updateIndicator(volume: number, signalLevel: number): void {
        if (!indicator) return;

        if (volume === 0) {
            indicator.textContent = '🔇';
            indicator.classList.add('muted');
            indicator.classList.remove('active');
        } else if (signalLevel > 0) {
            indicator.textContent = '🔊';
            indicator.classList.remove('muted');
            indicator.classList.add('active');
        } else {
            indicator.textContent = '🔇';
            indicator.classList.add('muted');
            indicator.classList.remove('active');
        }
    }

    // Устанавливаем начальное состояние (звук выключен)
    audioEngine.setVolume(0);
    updateTrackFill(0);
    lastSignalLevel = 0;
    updateIndicator(0, 0);

    // Обработчик изменения громкости
    slider.addEventListener('input', () => {
        const volume = parseInt(slider.value);

        updateTrackFill(volume);
        audioEngine.setVolume(volume);

        if (volume === 0) {
            // Громкость 0 - звук выключен
            updateIndicator(0, 0);
            if (lastSignalLevel > 0) {
                audioEngine.updateLevel(0);
            }
        } else {
            // Громкость > 0 - показываем состояние сигнала
            updateIndicator(volume, lastSignalLevel);
            if (lastSignalLevel > 0) {
                audioEngine.updateLevel(lastSignalLevel);
            }
        }
    });

    // Для тач-устройств
    if (wrapper) {
        wrapper.addEventListener('click', (e) => {
            const control = document.getElementById('volumeControl');
            if (control && window.innerWidth <= 768) {
                control.classList.toggle('visible');
                e.stopPropagation();
            }
        });

        document.addEventListener('click', (e) => {
            const control = document.getElementById('volumeControl');
            if (control && window.innerWidth <= 768) {
                if (!wrapper.contains(e.target as Node)) {
                    control.classList.remove('visible');
                }
            }
        });
    }

    // Сохраняем настройки
    const savedVolume = localStorage.getItem('gport_volume');
    if (savedVolume) {
        const vol = parseInt(savedVolume);
        if (vol >= 0 && vol <= 100) {
            slider.value = String(vol);
            slider.dispatchEvent(new Event('input'));
        }
    }

    slider.addEventListener('change', () => {
        localStorage.setItem('gport_volume', slider.value);
    });
}

// ================= INIT =================
window.addEventListener("DOMContentLoaded", () => {
    initDOM();
    initAccordion();
    initResize();
    initCamera();
    initVolumeControl();

    document.addEventListener('click', () => {
        audioEngine.updateLevel(0);
    }, { once: true });

    setPeakHolderListener(() => {
        if (!connectionLost) {
            setBars(state.peakValue);
            setSignal(state.peakSignalLevel);

            const signalLevel = state.peakSignalLevel;
            const currentVolume = audioEngine.getVolume();

            if (signalLevel !== lastSignalLevel) {
                lastSignalLevel = signalLevel;

                // Обновляем индикатор в зависимости от громкости и уровня сигнала
                const indicator = document.getElementById('audio-indicator');
                if (indicator) {
                    if (currentVolume > 0 && signalLevel > 0) {
                        indicator.textContent = '🔊';
                        indicator.classList.remove('muted');
                        indicator.classList.add('active');
                        audioEngine.updateLevel(signalLevel);
                    } else if (currentVolume > 0 && signalLevel === 0) {
                        indicator.textContent = '🔇';
                        indicator.classList.add('muted');
                        indicator.classList.remove('active');
                        audioEngine.updateLevel(0);
                    } else {
                        indicator.textContent = '🔇';
                        indicator.classList.add('muted');
                        indicator.classList.remove('active');
                        audioEngine.updateLevel(0);
                    }
                }
                setAudioIndicator(signalLevel > 0 && currentVolume > 0, signalLevel);
            }
        }
    });
});

document.addEventListener('DOMContentLoaded', () => {
    const closeBtn = document.getElementById('camCloseBtn');
    const toggleBtn = document.getElementById('camToggle');

    if (closeBtn) {
        closeBtn.addEventListener('click', () => {
            if (toggleBtn) {
                toggleBtn.click();
            }
        });
    }
});

document.addEventListener("keydown", (e: KeyboardEvent) => {
    const leftPanel = document.getElementById("leftPanel");
    const rightPanel = document.getElementById("rightPanel");

    switch (e.key.toLowerCase()) {
        case 'c':
            const camBtn = document.getElementById('camToggle');
            if (camBtn) camBtn.click();
            break;
        case 'f':
            if (leftPanel) {
                leftPanel.style.width = "100%";
                if (rightPanel) rightPanel.style.display = "none";
            }
            break;
        case 'escape':
            if (rightPanel) rightPanel.style.display = "flex";
            if (leftPanel && rightPanel) {
                const total = window.innerWidth;
                const leftWidth = total * 0.6;
                leftPanel.style.flex = `0 0 ${leftWidth}px`;
                rightPanel.style.flex = `0 0 ${total - leftWidth}px`;
            }
            break;
        case 'm':
            if (lastSignalLevel > 0 && audioEngine.getVolume() > 0) {
                audioEngine.updateLevel(0);
                setAudioIndicator(false);
                window._mutedLevel = lastSignalLevel;
                lastSignalLevel = 0;
            } else {
                const level = window._mutedLevel || state.peakSignalLevel;
                if (level > 0 && audioEngine.getVolume() > 0) {
                    audioEngine.updateLevel(level);
                    lastSignalLevel = level;
                    setAudioIndicator(true, level);
                }
            }
            break;
    }
});

// ================= UPDATE =================
async function update(): Promise<void> {
    try {
        const [health, history] = await Promise.all([
            fetchHealth(),
            fetchHistory()
        ]);

        consecutiveErrors = 0;

        if (health.server_time) {
            setServerTime(health.server_time);
        }

        const isOnline = health.pipe_alive && health.has_data;

        if (isOnline) {
            setStatus("На связи");
            connectionLost = false;
        } else {
            setStatus("Нет связи", true);
            if (!connectionLost) resetBufferTracking();
            connectionLost = true;
            if (lastSignalLevel > 0) {
                lastSignalLevel = 0;
                audioEngine.updateLevel(0);
                setAudioIndicator(false);
            }
        }

        const arr = Array.isArray(history.bytes) ? history.bytes : [];
        const raw = arr[arr.length - 1] ?? 0;

        if (arr.length > 0 && isOnline) {
            const bufferSize = health.stats?.filled ?? 0;
            addSignals(arr, bufferSize);
        }

        // ===== НАХОДИМ МАКСИМУМ ИЗ БУФЕРА =====
        let maxSignal = 0;
        let maxLevel = 0;
        let currentSignal = 0;
        let currentLevel = 0;

        if (isOnline && arr.length > 0) {
            for (const byte of arr) {
                const signal = byte & 0x3F;
                const amp = (byte >> 6) & 0x3;

                if (signal > maxSignal) {
                    maxSignal = signal;
                }
                if (amp > maxLevel) {
                    maxLevel = amp;
                }
            }

            currentSignal = raw & 0x3F;
            currentLevel = (raw >> 6) & 0x3;
        }

        const percent = (maxSignal / 63) * 100;

        // ===== ОБНОВЛЯЕМ КАНАЛЫ =====
        if (isOnline && arr.length > 0) {
            setChannelValue(0, maxSignal, maxLevel);
            setChannelCurrentValue(0, currentSignal, currentLevel);

            for (let i = 1; i < 8; i++) {
                setChannelValue(i, 0, 0);
                setChannelCurrentValue(i, 0, 0);
                if (channelElements[i]) {
                    channelElements[i].item.classList.remove('channel-active');
                }
            }

            if (channelElements[0]) {
                channelElements[0].item.classList.add('channel-active');
            }

            if (DOM.lastByte) {
                DOM.lastByte.textContent = currentSignal.toString();
            }
        } else {
            for (let i = 0; i < 8; i++) {
                setChannelValue(i, 0, 0);
                setChannelCurrentValue(i, 0, 0);
                if (channelElements[i]) {
                    channelElements[i].item.classList.remove('channel-active');
                }
            }
            if (DOM.lastByte) {
                DOM.lastByte.textContent = '--';
            }
        }

        if (isOnline) {
            updatePeakHolder(percent);
            updateSignalPeakHolder(maxLevel);
        } else {
            setBars(0, true);
            setSignal(0, true);
            if (lastSignalLevel > 0) {
                lastSignalLevel = 0;
                audioEngine.updateLevel(0);
                setAudioIndicator(false);
            }
        }

        const uptime = Math.round(health.uptime_sec || 0);
        const filled = health.stats?.filled ?? 0;
        const Bps = Math.round(health.stats?.bytes_per_sec ?? 0);

        setMeta(`Работа: ${uptime}s | Буфер: ${filled} | Приём: ${Bps} B/s`);

        // ===== ИСТОРИЯ: НОВЫЕ СВЕРХУ =====
        if (DOM.history) {
            if (arr.length === 0) {
                DOM.history.innerHTML = 'Нет данных';
            } else {
                const reversed = [...arr].reverse();
                DOM.history.innerHTML = reversed
                    .map((b, i) => {
                        const originalIndex = arr.length - 1 - i;
                        const binary = (b & 0xFF).toString(2).padStart(8, "0");
                        return `[${originalIndex}] ${binary} = ${b & 0xFF}`;
                    })
                    .join("<br>");
            }
        }

        const now = performance.now();
        if (now - lastChart > 100 && DOM.canvas) {
            drawChart(DOM.canvas, state.signalHistory);
            lastChart = now;
        }

    } catch (e) {
        consecutiveErrors++;

        setStatus("СЕРВЕР НЕДОСТУПЕН", true);
        setServerTime("--:--:--");
        setBars(0, true);
        setSignal(0, true);
        resetBufferTracking();

        if (lastSignalLevel > 0) {
            lastSignalLevel = 0;
            audioEngine.updateLevel(0);
            setAudioIndicator(false);
        }

        if (DOM.lastByte) DOM.lastByte.textContent = "--";

        if (DOM.history) {
            DOM.history.innerHTML = "Ошибка загрузки данных";
        }

        if (consecutiveErrors >= MAX_ERRORS && pollTimer) {
            clearInterval(pollTimer);
        }
    }
}

function startPolling(): void {
    if (pollTimer) clearInterval(pollTimer);
    if (consecutiveErrors > 0) update();
    pollTimer = window.setInterval(update, 500);
}

window.addEventListener("focus", () => {
    if (consecutiveErrors >= MAX_ERRORS) {
        consecutiveErrors = 0;
        startPolling();
    }
});

window.addEventListener("beforeunload", () => {
    audioEngine.dispose();
});

declare global {
    interface Window {
        _mutedLevel?: number;
    }
}

startPolling();
update();