import HAClient from './ha-client.js';

class GridStabilizer {
    constructor(config) {
        this.config = config;
        this.haClient = new HAClient(config.HA_URL, config.HA_TOKEN);

        // State
        this.timeLeft = config.TIMER_DURATION;
        this.sliders = { A: 200, B: 200, C: 200 };
        this.prevSliders = { ...this.sliders };
        this.stabilityTimer = 0;
        this.isStarted = false;
        this.isGameOver = false;
        this.isSuccess = false;
        this.bgm = null;

        // UI Elements
        this.elements = {
            batteryLevel: document.getElementById('battery-level'),
            batteryText: document.getElementById('battery-text'),
            timerDisplay: document.getElementById('timer-display'),
            sliderA: document.getElementById('slider-a'),
            sliderB: document.getElementById('slider-b'),
            sliderC: document.getElementById('slider-c'),
            powerValue: document.getElementById('power-value'),
            stabilityProgress: document.getElementById('stability-progress'),
            terminal: document.getElementById('terminal'),
            overlay: document.getElementById('overlay'),
            initBtn: document.getElementById('init-btn')
        };

        this.initEventListeners();
        this.loadState();
    }

    initEventListeners() {
        this.elements.initBtn.addEventListener('click', () => this.startSystem());

        ['A', 'B', 'C'].forEach(id => {
            const el = this.elements[`slider${id}`];
            el.addEventListener('input', (e) => this.handleSliderInput(id, parseInt(e.target.value)));
        });

        // Prevention of accidental refresh
        window.addEventListener('beforeunload', (e) => {
            if (this.isStarted && !this.isGameOver) {
                e.preventDefault();
                e.returnValue = '';
            }
        });
    }

    log(message, type = 'info') {
        const line = document.createElement('div');
        line.className = `terminal-line ${type}`;
        line.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
        this.elements.terminal.appendChild(line);
        this.elements.terminal.scrollTop = this.elements.terminal.scrollHeight;
    }

    async startSystem() {
        if (this.isStarted) return;
        this.isStarted = true;
        this.elements.overlay.classList.add('hidden');

        // Request fullscreen
        try {
            if (document.documentElement.requestFullscreen) {
                await document.documentElement.requestFullscreen();
            }
        } catch (e) {
            console.warn("Fullscreen denied");
        }

        this.log("SYSTEM INITIALIZATION SEQUENCE STARTED...");
        this.haClient.triggerScene(this.config.SCENES.init)
            .then(() => this.log("HA SCENE: INITIALIZED", "success"))
            .catch(e => this.log("HA SCENE ERROR: " + e.message, "critical"));

        this.haClient.triggerWebhook(this.config.WEBHOOKS.init)
            .then(() => this.log("HA WEBHOOK: INITIALIZED", "success"))
            .catch(e => this.log("HA WEBHOOK ERROR: " + e.message, "critical"));

        this.checkAudioTimeline(); // Trigger initial audio (T-200)
        this.startTimer();
        this.startDrift();
        this.startAdaptiveDifficulty(); // Make it harder over time
        this.updateUI();
    }

    startAdaptiveDifficulty() {
        this.difficultyInterval = setInterval(() => {
            if (this.isGameOver) return;

            // Increase drift speed as time runs out
            const timePassed = this.config.TIMER_DURATION - this.timeLeft;
            const progress = timePassed / this.config.TIMER_DURATION;

            this.currentDriftSpeed = this.config.DRIFT_SPEED * (1 + progress * 3);
            this.currentSurgeStrength = this.config.SURGE_STRENGTH * (1 + progress * 2);

            // Occasionally "Jitter" the target power to confuse the user
            if (Math.random() > 0.95) {
                this.tempTargetOffset = (Math.random() - 0.5) * 15;
                setTimeout(() => this.tempTargetOffset = 0, 2000);
            }

            // Chaos: Update subsystem monitors with random numbers
            this.updateMonitors();
            this.updateFrequency();
            this.updateDataStream();

            // Random Terminal Noise
            if (Math.random() > 0.7) {
                const noise = [
                    "SCANNING SECTOR " + Math.floor(Math.random() * 9999),
                    "PACKET FLOW: " + (Math.random() * 100).toFixed(2) + " MB/s",
                    "OSCILLATION DETECTED IN NODE " + String.fromCharCode(65 + Math.floor(Math.random() * 26)),
                    "BUFFER OVERFLOW RECOVERY: COMPLETE",
                    "LATENCY SHIFT: " + (Math.random() * 50).toFixed(0) + "ms"
                ];
                this.log(noise[Math.floor(Math.random() * noise.length)]);
            }
        }, 1000);
    }

    updateMonitors() {
        const core = Math.floor(Math.random() * (99 - 85) + 85);
        const heat = Math.floor(Math.random() * (65 - 40) + 40);
        const volt = Math.floor(Math.random() * (245 - 220) + 220);
        const flows = ['NOMINAL', 'STABLE', 'FLUCTUATING', 'OVERLOAD', 'DROPPING'];

        const monCore = document.getElementById('mon-core');
        const monHeat = document.getElementById('mon-heat');
        const monVolts = document.getElementById('mon-volts');
        const monFlow = document.getElementById('mon-flow');

        if (monCore) monCore.textContent = `CORE: ${core}%`;
        if (monHeat) monHeat.textContent = `HEAT: ${heat}C`;
        if (monVolts) monVolts.textContent = `VOLT: ${volt}V`;
        if (monFlow) monFlow.textContent = `FLOW: ${flows[Math.floor(Math.random() * flows.length)]}`;

        // Randomly pulse topology nodes
        const nodes = document.querySelectorAll('.topo-node');
        nodes.forEach(n => {
            if (Math.random() > 0.7) n.classList.toggle('active');
        });
    }

    updateFrequency() {
        const freq = (49.5 + Math.random()).toFixed(2);
        const bar = document.getElementById('freq-bar');
        const val = document.getElementById('freq-val');
        if (bar) {
            const offset = (freq - 50) * 100 + 50; // Map 49.5-50.5 to 0-100%
            bar.style.left = `${Math.max(0, Math.min(100, offset))}%`;
            bar.style.background = Math.abs(freq - 50) > 0.2 ? 'var(--danger-neon)' : 'var(--success-neon)';
        }
        if (val) val.textContent = `${freq} Hz`;
    }

    updateDataStream() {
        const stream = document.getElementById('data-stream');
        if (!stream) return;
        const chars = "0123456789ABCDEF!@#$%^&*()_+-=[]{}|;:,.<>?";
        let out = "";
        for (let i = 0; i < 200; i++) {
            out += chars[Math.floor(Math.random() * chars.length)];
        }
        stream.textContent = out;
    }

    startDrift() {
        this.velocities = { A: 0, B: 0, C: 0 };
        this.currentDriftSpeed = this.config.DRIFT_SPEED;

        this.driftInterval = setInterval(() => {
            if (this.isGameOver) return;

            ['A', 'B', 'C'].forEach(id => {
                const impulse = (Math.random() - 0.5) * this.currentDriftSpeed;
                this.velocities[id] += impulse;
                this.velocities[id] *= 0.96;

                const maxVel = 8.0;
                this.velocities[id] = Math.max(-maxVel, Math.min(maxVel, this.velocities[id]));

                this.sliders[id] = Math.max(0, Math.min(500, this.sliders[id] + this.velocities[id]));
            });

            this.syncSliderInputs();
            this.checkStability();
        }, 40);
    }

    startSurges() {
        this.currentSurgeStrength = this.config.SURGE_STRENGTH;
        const scheduleSurge = () => {
            if (this.isGameOver) return;

            const min = this.config.SURGE_INTERVAL[0];
            const max = this.config.SURGE_INTERVAL[1];
            // Surges become more frequent as time runs out
            const freqMultiplier = this.timeLeft / this.config.TIMER_DURATION;
            const nextSurge = (Math.random() * (max - min) + min) * Math.max(0.3, freqMultiplier);

            setTimeout(() => {
                if (this.isGameOver) return;

                const targetSlider = ['A', 'B', 'C'][Math.floor(Math.random() * 3)];
                const strength = (Math.random() > 0.5 ? 1 : -1) * this.currentSurgeStrength;

                this.log(`CRITICAL SURGE DETECTED IN PHASE ${targetSlider}!`, 'critical');
                this.velocities[targetSlider] += strength;

                document.body.classList.add('glitch-effect', 'emergency-state');
                const warning = document.getElementById('warning-panel');
                if (warning) {
                    warning.classList.add('active');
                    warning.querySelector('.warning-header').textContent = "!! CRITICAL OVERLOAD !!";
                    warning.querySelector('.warning-body').textContent = "UNSTABLE LOAD DETECTED";
                }

                setTimeout(() => {
                    document.body.classList.remove('glitch-effect', 'emergency-state');
                    if (warning) {
                        warning.classList.remove('active');
                        warning.querySelector('.warning-header').textContent = "LOAD BALANCER STATUS";
                        warning.querySelector('.warning-body').textContent = "GRID MONITORED - STABLE";
                    }
                }, 1200);

                scheduleSurge();
            }, nextSurge);
        };
        scheduleSurge();
    }

    handleSliderInput(id, value) {
        if (this.isGameOver) return;

        const delta = value - this.prevSliders[id];
        this.sliders[id] = value;

        // Interdependence logic based on prompt examples
        if (id === 'A') {
            this.updateSlider('B', -delta * 0.5);
            this.updateSlider('C', delta * 0.2);
        } else if (id === 'B') {
            this.updateSlider('A', delta * 0.3);
            this.updateSlider('C', -delta * 0.4);
        } else if (id === 'C') {
            this.updateSlider('A', -delta * 0.2);
            this.updateSlider('B', delta * 0.3);
        }

        this.prevSliders = { ...this.sliders };
        this.syncSliderInputs();
        this.checkStability();
    }

    updateSlider(id, amount) {
        this.sliders[id] = Math.max(0, Math.min(500, this.sliders[id] + amount));
    }

    syncSliderInputs() {
        ['A', 'B', 'C'].forEach(id => {
            this.elements[`slider${id}`].value = Math.round(this.sliders[id]);
            document.getElementById(`val-${id.toLowerCase()}`).textContent = Math.round(this.sliders[id]) + " KW";
        });

        const total = Math.round(this.sliders.A + this.sliders.B + this.sliders.C);
        this.elements.powerValue.textContent = total;

        // Visual feedback
        const diff = Math.abs(total - this.config.TARGET_POWER);
        if (diff <= this.config.TOLERANCE) {
            this.elements.powerValue.style.color = 'var(--success-neon)';
        } else {
            this.elements.powerValue.style.color = 'var(--primary-neon)';
        }
    }

    checkStability() {
        const total = this.sliders.A + this.sliders.B + this.sliders.C;
        const target = this.config.TARGET_POWER + (this.tempTargetOffset || 0);
        const diff = Math.abs(total - target);

        if (diff <= this.config.TOLERANCE) {
            if (this.stabilityInterval) return;

            this.log("GRID DETECTED. STABILIZING...", "warning");
            const start = Date.now();
            this.stabilityInterval = setInterval(() => {
                const elapsed = Date.now() - start;
                const progress = (elapsed / this.config.STABILITY_DURATION) * 100;
                this.elements.stabilityProgress.style.width = `${Math.min(100, progress)}%`;

                // RIGGED SABOTAGE: If they reach 80% stability, trigger a massive surge
                if (progress > 80 && !this.isGameOver) {
                    this.executeSabotageSurge();
                }

                if (elapsed >= this.config.STABILITY_DURATION) {
                    this.win();
                }

                const currentTotal = this.sliders.A + this.sliders.B + this.sliders.C;
                const currentTarget = this.config.TARGET_POWER + (this.tempTargetOffset || 0);
                if (Math.abs(currentTotal - currentTarget) > this.config.TOLERANCE) {
                    this.resetStability();
                }
            }, 50);
        } else {
            this.resetStability();
        }
    }

    executeSabotageSurge() {
        this.log("CRITICAL FEEDBACK LOOP DETECTED. EMERGENCY VENTING!", "critical");
        ['A', 'B', 'C'].forEach(id => {
            this.velocities[id] += (Math.random() - 0.5) * 100;
        });
        document.body.classList.add('glitch-effect', 'emergency-state');
        const warning = document.getElementById('warning-panel');
        if (warning) {
            warning.classList.add('active');
            warning.querySelector('.warning-header').textContent = "!! SYSTEM SABOTAGE !!";
            warning.querySelector('.warning-body').textContent = "EMERGENCY VENTING IN PROGRESS";
        }

        setTimeout(() => {
            document.body.classList.remove('glitch-effect', 'emergency-state');
            if (warning) {
                warning.classList.remove('active');
                warning.querySelector('.warning-header').textContent = "LOAD BALANCER STATUS";
                warning.querySelector('.warning-body').textContent = "GRID MONITORED - STABLE";
            }
        }, 1500);
        this.resetStability();
        this.saveState();
    }

    saveState() {
        const state = {
            timeLeft: this.timeLeft,
            sliders: this.sliders,
            isStarted: this.isStarted,
            isGameOver: this.isGameOver,
            isSuccess: this.isSuccess,
            logs: Array.from(this.elements.terminal.querySelectorAll('.terminal-line')).map(el => ({
                text: el.textContent,
                className: el.className
            }))
        };
        sessionStorage.setItem('grid_stabilizer_state', JSON.stringify(state));
    }

    loadState() {
        const saved = sessionStorage.getItem('grid_stabilizer_state');
        if (!saved) return;

        try {
            const state = JSON.parse(saved);
            this.timeLeft = state.timeLeft || this.timeLeft;
            this.sliders = state.sliders || this.sliders;
            this.isStarted = state.isStarted || false;
            this.isGameOver = state.isGameOver || false;
            this.isSuccess = state.isSuccess || false;

            // Restore Logs
            if (state.logs) {
                state.logs.forEach(log => {
                    const line = document.createElement('div');
                    line.className = log.className;
                    line.textContent = log.text;
                    this.elements.terminal.appendChild(line);
                });
                this.elements.terminal.scrollTop = this.elements.terminal.scrollHeight;
            }

            if (this.isStarted && !this.isGameOver) {
                this.elements.overlay.classList.add('hidden');
                this.resumeSystem();
            } else if (this.isGameOver) {
                this.elements.overlay.classList.add('hidden');
                if (this.isSuccess) {
                    document.querySelectorAll('.dashboard > div').forEach(el => el.classList.add('success-state'));
                } else {
                    document.querySelectorAll('.dashboard > div').forEach(el => el.classList.add('fail-state'));
                }
            }

            this.updateUI();
            this.syncSliderInputs();
        } catch (e) {
            console.error("Failed to load state:", e);
        }
    }

    clearState() {
        sessionStorage.removeItem('grid_stabilizer_state');
    }

    resumeSystem() {
        this.startTimer();
        this.startDrift();
        this.startSurges();
        this.startAdaptiveDifficulty();
        this.updateUI();
    }

    resetStability() {
        if (this.stabilityInterval) {
            clearInterval(this.stabilityInterval);
            this.stabilityInterval = null;
            this.elements.stabilityProgress.style.width = '0%';
            this.log("STABILITY LOST. RE-SYNC REQUIRED.", "critical");
        }
    }

    startTimer() {
        this.timerInterval = setInterval(() => {
            this.timeLeft--;
            this.updateUI();
            this.checkAudioTimeline();
            this.saveState();

            if (this.timeLeft <= 0) {
                this.fail();
            }

            // Effects at 15%
            const pct = (this.timeLeft / this.config.TIMER_DURATION) * 100;
            if (pct <= 15) {
                document.body.classList.add('shake-screen');
                this.elements.batteryLevel.classList.add('critical');
                if (this.timeLeft % 10 === 0) this.log("CRITICAL ENERGY LEVEL", "critical");
            } else if (pct <= 40) {
                this.elements.batteryLevel.classList.add('warning');
            }
        }, 1000);
    }

    checkAudioTimeline() {
        const timeline = this.config.AUDIO_TIMELINE;
        if (timeline && timeline[this.timeLeft]) {
            const path = timeline[this.timeLeft];
            this.playAudio(path);
            this.log("SYSTEM MESSAGE: " + path.split('/').pop());
        }

        // BGM Logic
        if (this.timeLeft === 180 && !this.bgm) {
            this.bgm = this.playAudio(this.config.AUDIO_BGM);
            this.bgm.volume = 0.1;
            this.bgm.loop = false;
            this.log("BACKGROUND MUSIC ACTIVATED", "info");
        }
    }

    updateUI() {
        const m = Math.floor(this.timeLeft / 60);
        const s = this.timeLeft % 60;
        this.elements.timerDisplay.textContent = `${m}:${s.toString().padStart(2, '0')}`;

        const pct = (this.timeLeft / this.config.TIMER_DURATION) * 100;
        this.elements.batteryLevel.style.height = `${pct}%`;
    }

    playAudio(path) {
        const audio = new Audio(path);
        audio.play().catch(e => console.error("Audio play failed:", e));
        return audio;
    }

    async playSequence(key) {
        if (!this.config.AUDIO_PATHS || !this.config.AUDIO_PATHS[key]) return;
        const paths = this.config.AUDIO_PATHS[key];
        if (Array.isArray(paths)) {
            for (const path of paths) {
                const audio = this.playAudio(path);
                await new Promise(res => audio.onended = res);
            }
        } else {
            this.playAudio(paths);
        }
    }


    win() {
        if (this.isGameOver) return;
        this.isGameOver = true;
        this.isSuccess = true;
        clearInterval(this.timerInterval);
        if (this.stabilityInterval) clearInterval(this.stabilityInterval);
        if (this.bgm) this.bgm.pause();

        this.log("GRID STABILIZED. BLACKOUT AVERTED.", "success");
        document.body.classList.remove('shake-screen');
        document.querySelectorAll('.dashboard > div').forEach(el => el.classList.add('success-state'));

        this.playSequence('success');
        this.clearState();

        this.haClient.triggerScene(this.config.SCENES.success)
            .then(() => this.log("HA SCENE: SUCCESS TRIGGERED", "success"))
            .catch(e => this.log("HA SCENE ERROR: " + e.message, "critical"));

        this.haClient.triggerWebhook(this.config.WEBHOOKS.success)
            .then(() => this.log("HA WEBHOOK: SUCCESS TRIGGERED", "success"))
            .catch(e => this.log("HA WEBHOOK ERROR: " + e.message, "critical"));
    }

    fail() {
        if (this.isGameOver) return;
        this.isGameOver = true;
        clearInterval(this.timerInterval);
        if (this.bgm) this.bgm.pause();

        this.log("CRITICAL FAILURE. GRID COLLAPSED.", "critical");
        document.querySelectorAll('.dashboard > div').forEach(el => el.classList.add('fail-state'));

        this.playSequence('fail');
        this.clearState();

        // Delay external triggers by 5 seconds as requested
        setTimeout(() => {
            this.haClient.triggerScene(this.config.SCENES.fail)
                .then(() => this.log("HA SCENE: FAILURE TRIGGERED", "warning"))
                .catch(e => this.log("HA SCENE ERROR: " + e.message, "critical"));

            this.haClient.triggerWebhook(this.config.WEBHOOKS.fail)
                .then(() => this.log("HA WEBHOOK: FAILURE TRIGGERED", "warning"))
                .catch(e => this.log("HA WEBHOOK ERROR: " + e.message, "critical"));
        }, 5000);
    }
}

// Kickoff
window.addEventListener('DOMContentLoaded', async () => {
    const config = window.APP_CONFIG;
    window.game = new GridStabilizer(config);
});
