const API = "https://api.anjuma-crew.de";
const WS_URL = "wss://api.anjuma-crew.de";
const STREAM_URL = "https://stream.anjuma-crew.de/anjuma/";

const MAX_POINTS = 40;
const SCENES = ["Starting", "Live1", "Live2", "Low", "Offline"];

let ws;
let reconnectTimeout = null;
let retryDelay = 1500;

let lowThreshold = 1000;

// ===== FIX STATE =====
let isFixing = false;

// ===== OBS STATE =====
let obsStarting = false;

// ===== DATA =====
const data = [];

// ===== PREVIEW STATE =====
const previewState = {
    live1: false,
    live2: false
};

// ===== DOM CACHE =====
const el = {};

// ===== INIT =====
window.addEventListener("load", () => {
    cacheDOM();
    connectWS();
});

// ===== CACHE DOM =====
function cacheDOM() {

    el.scene = document.getElementById("scene");
    el.live1 = document.getElementById("live1");
    el.live2 = document.getElementById("live2");
    el.chart = document.getElementById("chart");

    el.obsStartBtn = document.getElementById("obsStartBtn");
    el.obsStatus = document.getElementById("obsStatus");

    el.fixBtn = document.getElementById("fixBtn");
}

// ===== WS =====
function connectWS() {

    ws = new WebSocket(WS_URL);

    ws.onopen = () => {
        retryDelay = 1500;
        console.log("WS connected");
    };

    ws.onclose = () => scheduleReconnect();
    ws.onerror = () => scheduleReconnect();

    ws.onmessage = (msg) => {
        const packet = JSON.parse(msg.data);
        if (packet.type === "update") handle(packet.data);
    };
}

function scheduleReconnect() {

    if (reconnectTimeout) return;

    reconnectTimeout = setTimeout(() => {
        reconnectTimeout = null;
        retryDelay = Math.min(retryDelay * 1.5, 10000);
        connectWS();
    }, retryDelay);
}

// ===== OBS STATUS =====
function updateOBSStatus(d) {

    if (!el.obsStatus) return;

    if (d.obsConnected) {
        el.obsStatus.innerText = "🟢 Connected";
        el.obsStatus.className = "text-success";
    } else {
        el.obsStatus.innerText = "🔴 Disconnected";
        el.obsStatus.className = "text-danger";
    }
}

// ===== HANDLE =====
function handle(d) {

    evaluateStreams(d);
    updateOBSStatus(d);

    if (d.lowThreshold) {
        lowThreshold = parseInt(d.lowThreshold);
    }

    const v1 = d.streams?.live1?.bitrate || 0;
    const v2 = d.streams?.live2?.bitrate || 0;

    data.push({ live1: v1, live2: v2 });

    if (data.length > MAX_POINTS) {
        data.shift();
    }

    updateUI(d);
    scheduleDraw();

    updatePreview("live1", v1);
    updatePreview("live2", v2);

    updateFixState(d);
}

// ===== OBS START (WOL) =====
function startOBS() {

    if (obsStarting) return;

    obsStarting = true;

    if (el.obsStartBtn) {
        el.obsStartBtn.innerText = "Starting OBS...";
        el.obsStartBtn.disabled = true;
    }

    const timeout = setTimeout(() => {
        reset();
    }, 20000);

    fetch(`${API}/obs/start`, {
        method: "POST"
    })
    .then(res => res.json())
    .then(data => {
        console.log("OBS WOL:", data);
    })
    .catch(err => {
        console.error(err);
        reset();
    });

    function reset() {
        clearTimeout(timeout);

        obsStarting = false;

        if (el.obsStartBtn) {
            el.obsStartBtn.innerText = "OBS Starten";
            el.obsStartBtn.disabled = false;
        }
    }
}

// ===== FIX UI =====
function updateFixState(d) {

    if (!el.fixBtn) return;

    if (isFixing) return;

    if (d.isFixRunning) {

        isFixing = true;
        el.fixBtn.innerText = "FIXING...";
        el.fixBtn.disabled = true;

    } else {

        isFixing = false;
        el.fixBtn.innerText = "FIX STREAM";
        el.fixBtn.disabled = false;
    }
}

// ===== FIX ACTION =====
async function fixStream() {

    if (isFixing) return;

    isFixing = true;

    if (el.fixBtn) {
        el.fixBtn.innerText = "FIXING...";
        el.fixBtn.disabled = true;
    }

    try {

        const res = await fetch(`${API}/fix`, {
            method: "POST"
        });

        const result = await res.json();

        console.log("FIX RESULT:", result);

    } catch (e) {
        console.error(e);
    }

    setTimeout(() => {

        isFixing = false;

        if (el.fixBtn) {
            el.fixBtn.innerText = "FIX STREAM";
            el.fixBtn.disabled = false;
        }

    }, 2000);
}

// ===== UI =====
function updateUI(d) {

    if (el.scene) {
        el.scene.innerText = d.currentScene || "-";
    }

    if (el.live1) {
        el.live1.innerText = (d.streams?.live1?.bitrate || 0) + " kbps";
    }

    if (el.live2) {
        el.live2.innerText = (d.streams?.live2?.bitrate || 0) + " kbps";
    }

    SCENES.forEach(s => {

        const btn = document.getElementById("scene-" + s);
        if (!btn) return;

        btn.classList.remove("active");

        if (d.currentScene === s) {
            btn.classList.add("active");
        }
    });
}

// ===== PREVIEW =====
function updatePreview(stream, bitrate) {

    const frame = document.getElementById("preview-" + stream);
    const offline = document.getElementById("offline-" + stream);

    if (!frame || !offline) return;

    if (bitrate > 0) {

        if (!previewState[stream]) {

            frame.src = STREAM_URL + stream;
            frame.style.display = "block";
            offline.style.display = "none";

            previewState[stream] = true;
        }

    } else {

        if (previewState[stream]) {

            frame.src = "";
            frame.style.display = "none";

            previewState[stream] = false;
        }

        offline.style.display = "flex";
    }
}

// ===== CHART =====
let drawPending = false;

function scheduleDraw() {

    if (drawPending) return;

    drawPending = true;

    requestAnimationFrame(() => {
        draw();
        drawPending = false;
    });
}

function draw() {

    const canvas = el.chart;
    if (!canvas) return;

    const ctx = canvas.getContext("2d");

    const w = canvas.width = canvas.offsetWidth;
    const h = canvas.height = canvas.offsetHeight;

    ctx.clearRect(0, 0, w, h);

    const values = data.flatMap(d => [d.live1, d.live2, lowThreshold]);
    const maxVal = Math.ceil(Math.max(...values, 100) * 1.15);

    ctx.strokeStyle = "#e5e7eb";
    ctx.lineWidth = 1;

    for (let i = 0; i <= 5; i++) {

        const y = (h / 5) * i;

        ctx.beginPath();
        ctx.moveTo(0, y);
        ctx.lineTo(w, y);
        ctx.stroke();

        const label = Math.round(maxVal * (1 - i / 5));

        ctx.fillStyle = "#666";
        ctx.font = "11px Arial";
        ctx.fillText(label + " kbps", 5, y - 3);
    }

    const lowY = h - (lowThreshold / maxVal) * h;

    ctx.fillStyle = "rgba(239,68,68,0.08)";
    ctx.fillRect(0, lowY, w, h - lowY);

    ctx.beginPath();
    ctx.strokeStyle = "#f59e0b";
    ctx.setLineDash([8, 4]);
    ctx.moveTo(0, lowY);
    ctx.lineTo(w, lowY);
    ctx.stroke();
    ctx.setLineDash([]);

    ctx.fillStyle = "#f59e0b";
    ctx.font = "bold 11px Arial";
    ctx.fillText(`LOW (${lowThreshold})`, w - 140, lowY - 6);

    drawLine(ctx, data.map(d => d.live1), "#22c55e", w, h, maxVal);
    drawLine(ctx, data.map(d => d.live2), "#3b82f6", w, h, maxVal);
}

function drawLine(ctx, arr, color, w, h, maxVal) {

    if (arr.length < 2) return;

    ctx.beginPath();
    ctx.strokeStyle = color;
    ctx.lineWidth = 3;

    arr.forEach((v, i) => {

        const x = (i / (arr.length - 1)) * w;
        const y = h - (v / maxVal) * h;

        if (i === 0) ctx.moveTo(x, y);
        else ctx.lineTo(x, y);
    });

    ctx.stroke();
}

// ===== ACTIONS =====
function setScene(scene) {
    fetch(`${API}/scene`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ scene })
    }).catch(console.error);
}

function startStream() {
    fetch(`${API}/stream/start`, { method: "POST" });
}

function stopStream() {
    fetch(`${API}/stream/stop`, { method: "POST" });
}