(function () {
    const init = window.__TLS_INIT__;
    if (!init) return;

    const phaseEl = document.getElementById("tls-phase");
    const barEl = document.getElementById("tls-progress-bar");
    const logEl = document.getElementById("tls-log");

    const SEV_COLOR = {
        good: "bright-green",
        normal: "bright-yellow",
        notgood: "bright-orange",
        bad: "bright-red",
        serious: "magenta",
        info: "tx",
    };

    let reconnectAttempts = 0;
    const MAX_RECONNECTS = 3;
    let ws = null;
    let closedByDone = false;

    function appendLog(phase, detail, severity) {
        if (!logEl) return;
        const row = document.createElement("div");
        row.className = "tls-log-row";
        const label = document.createElement("span");
        label.className = "text-tx-alt font-small";
        label.textContent = `[${phase}] `;
        const msg = document.createElement("span");
        msg.className = `text-${SEV_COLOR[severity] || "tx"}`;
        msg.textContent = detail || "";
        row.appendChild(label);
        row.appendChild(msg);
        logEl.appendChild(row);
        logEl.scrollTop = logEl.scrollHeight;
    }

    function setProgress(value, phase) {
        if (barEl) barEl.style.width = `${Math.max(0, Math.min(1, value)) * 100}%`;
        if (phaseEl && phase) phaseEl.textContent = phase;
    }

    function connect() {
        try {
            ws = new WebSocket(init.wsUrl);
        } catch (e) {
            scheduleReconnect();
            return;
        }
        ws.onmessage = (ev) => {
            let msg;
            try {
                msg = JSON.parse(ev.data);
            } catch (_) {
                return;
            }
            if (msg.type === "history") {
                (msg.entries || []).forEach((e) => appendLog(e.phase, e.detail, e.severity));
                if (msg.status === "done") {
                    closedByDone = true;
                    location.replace(init.resultsUrl);
                }
                return;
            }
            if (msg.type === "progress") {
                appendLog(msg.phase, msg.detail, msg.severity);
                if (typeof msg.progress === "number") {
                    setProgress(msg.progress, msg.detail || msg.phase);
                }
                return;
            }
            if (msg.type === "finding") {
                const f = msg.finding || {};
                appendLog(f.category || "finding", `${f.severity_label || ""} ${f.title || ""} ${f.detail ? "— " + f.detail : ""}`.trim(), f.severity || "info");
                return;
            }
            if (msg.type === "done") {
                closedByDone = true;
                setProgress(1.0, `done (rank ${msg.rank}, score ${msg.score})`);
                location.replace(msg.redirect || init.resultsUrl);
                return;
            }
            if (msg.type === "error") {
                appendLog("error", msg.message || "engine failed", "serious");
                return;
            }
            if (msg.type === "started") {
                appendLog("started", msg.target || "", "info");
                return;
            }
        };
        ws.onclose = () => {
            if (!closedByDone) scheduleReconnect();
        };
        ws.onerror = () => {
            try { ws.close(); } catch (_) {}
        };
    }

    function scheduleReconnect() {
        if (closedByDone) return;
        if (reconnectAttempts >= MAX_RECONNECTS) {
            appendLog("ws", "WebSocket 接続が切断されました。ページをリロードしてください。", "bad");
            return;
        }
        const delay = Math.min(10_000, 1000 * Math.pow(2, reconnectAttempts));
        reconnectAttempts += 1;
        setTimeout(connect, delay);
    }

    window.addEventListener("beforeunload", () => {
        closedByDone = true;
        try { ws && ws.close(); } catch (_) {}
    });

    connect();
})();
