// file: kb_demo_app/frontend/ts/demo_ws.ts

import * as bootstrap from "bootstrap";
import "simplebar";
import ResizeObserver from "resize-observer-polyfill";
import { invoke } from "@tauri-apps/api/core";
import { listen, type UnlistenFn } from "@tauri-apps/api/event";
import { debug, takeoverConsole } from "@fltsci/tauri-plugin-tracing";
import { DemoWsEndpointSummary } from './bindings/DemoWsEndpointSummary.ts';
import { DemoWsStatusPayload } from './bindings/DemoWsStatusPayload.ts';
import { DemoWsSubscribeRequest } from './bindings/DemoWsSubscribeRequest.ts';

(window as Window & typeof globalThis & { bootstrap?: typeof bootstrap }).bootstrap = bootstrap;
(window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver;


function shortenLine(line: string, maxChars = 3000): string {
    if (line.length <= maxChars) {
        return line;
    }

    return `${line.slice(0, maxChars)} …[truncated ${line.length - maxChars} chars]`;
}

function appendLogLine(textarea: HTMLTextAreaElement, line: string): void {
    const now = new Date();
    const timestamp = now.toLocaleTimeString("fr-CH", { hour12: false });
    const safeLine = shortenLine(line, 3000);

    const existingLines = textarea.value === "" ? [] : textarea.value.split("\n");
    existingLines.push(`[${timestamp}] ${safeLine}`);

    const maxLines = 800;
    const trimmedLines = existingLines.length > maxLines
        ? existingLines.slice(existingLines.length - maxLines)
        : existingLines;

    textarea.value = trimmedLines.join("\n");
    textarea.scrollTop = textarea.scrollHeight;
}

function setStatusBadge(badge: HTMLSpanElement, state: string): void {
    badge.textContent = state;

    if (state === "Connected") {
        badge.className = "badge text-bg-success";
        return;
    }

    if (state === "Connecting" || state === "Disconnecting") {
        badge.className = "badge text-bg-warning";
        return;
    }

    badge.className = "badge text-bg-secondary";
}

function methodSupportsTypedMode(method: string): boolean {
    return ["account", "block", "logs", "program", "signature"].includes(method);
}

function methodNeedsTarget(method: string): boolean {
    return ["account", "program", "signature"].includes(method);
}

function methodNeedsFilter(method: string): boolean {
    return ["block", "logs"].includes(method);
}

function methodNeedsConfig(method: string): boolean {
    return ["account", "block", "logs", "program", "signature"].includes(method);
}

function targetLabelForMethod(method: string): string {
    if (method === "account") return "Account pubkey";
    if (method === "program") return "Program id";
    if (method === "signature") return "Signature";
    return "Target";
}

function methodPreset(method: string, mode: string): {
    target: string;
    filterJson: string;
    configJson: string;
} {
    if (method === "account") {
        return {
            target: "11111111111111111111111111111111",
            filterJson: "",
            configJson: mode === "typed"
                ? `{"encoding":"base64","commitment":"confirmed"}`
                : `{"encoding":"base64","commitment":"confirmed"}`,
        };
    }

    if (method === "block") {
        return {
            target: "",
            filterJson: `{"mentionsAccountOrProgram":"11111111111111111111111111111111"}`,
            configJson: mode === "typed"
                ? `{"commitment":"confirmed","encoding":"base64","transactionDetails":"signatures","showRewards":false,"maxSupportedTransactionVersion":0}`
                : `{"commitment":"confirmed","encoding":"base64","transactionDetails":"signatures","showRewards":false,"maxSupportedTransactionVersion":0}`,
        };
    }

    if (method === "logs") {
        return {
            target: "",
            filterJson: `{"mentions":["11111111111111111111111111111111"]}`,
            configJson: `{"commitment":"confirmed"}`,
        };
    }

    if (method === "program") {
        return {
            target: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
            filterJson: "",
            configJson: mode === "typed"
                ? `{"encoding":"base64","commitment":"confirmed","filters":[]}`
                : `{"encoding":"base64","commitment":"confirmed","filters":[]}`,
        };
    }

    if (method === "signature") {
        return {
            target: "2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b",
            filterJson: "",
            configJson: `{"commitment":"confirmed","enableReceivedNotification":true}`,
        };
    }

    return {
        target: "",
        filterJson: "",
        configJson: "",
    };
}

function updateFormVisibility(
    methodSelect: HTMLSelectElement,
    modeSelect: HTMLSelectElement,
    targetGroup: HTMLDivElement,
    targetLabel: HTMLLabelElement,
    targetInput: HTMLInputElement,
    filterGroup: HTMLDivElement,
    filterTextarea: HTMLTextAreaElement,
    configGroup: HTMLDivElement,
    configTextarea: HTMLTextAreaElement,
): void {
    const method = methodSelect.value;
    const supportsTypedMode = methodSupportsTypedMode(method);

    modeSelect.disabled = !supportsTypedMode;
    if (!supportsTypedMode) {
        modeSelect.value = "typed";
    }

    targetGroup.style.display = methodNeedsTarget(method) ? "" : "none";
    filterGroup.style.display = methodNeedsFilter(method) ? "" : "none";
    configGroup.style.display = methodNeedsConfig(method) ? "" : "none";

    targetLabel.textContent = targetLabelForMethod(method);

    const preset = methodPreset(method, modeSelect.value);
    targetInput.value = preset.target;
    filterTextarea.value = preset.filterJson;
    configTextarea.value = preset.configJson;
}

function applyStatusToUi(
    status: DemoWsStatusPayload,
    statusBadge: HTMLSpanElement,
    stateText: HTMLSpanElement,
    endpointText: HTMLSpanElement,
    subscriptionText: HTMLSpanElement,
    eventCountText: HTMLSpanElement,
    notificationCountText: HTMLSpanElement,
    uiLogCountText: HTMLSpanElement,
    suppressedLogCountText: HTMLSpanElement,
    lastEventKindText: HTMLSpanElement,
    connectButton: HTMLButtonElement,
    disconnectButton: HTMLButtonElement,
    subscribeButton: HTMLButtonElement,
    unsubscribeButton: HTMLButtonElement,
): void {
    setStatusBadge(statusBadge, status.connectionState);
    stateText.textContent = status.connectionState;
    endpointText.textContent = status.endpointName && status.endpointUrl
        ? `${status.endpointName} (${status.endpointUrl})`
        : "-";

    if (status.currentSubscriptionId !== null) {
        subscriptionText.textContent =
            `${status.currentSubscribeMethod ?? "?"} / #${status.currentSubscriptionId} / ${status.currentNotificationMethod ?? "?"}`;
    } else {
        subscriptionText.textContent = "-";
    }

    eventCountText.textContent = String(status.eventCountTotal);
    notificationCountText.textContent = String(status.notificationCountTotal);
    uiLogCountText.textContent = String(status.uiLogCount);
    suppressedLogCountText.textContent = String(status.suppressedLogCount);
    lastEventKindText.textContent = status.lastEventKind ?? "-";

    const isConnected = status.connectionState === "Connected";
    const isBusy = status.connectionState === "Connecting" || status.connectionState === "Disconnecting";

    connectButton.disabled = isConnected || isBusy;
    disconnectButton.disabled = !isConnected && status.connectionState !== "Disconnecting";
    subscribeButton.disabled = !isConnected || isBusy;
    unsubscribeButton.disabled = !isConnected || isBusy || status.currentSubscriptionId === null;
}

document.addEventListener("DOMContentLoaded", async () => {
    void takeoverConsole();

    debug("demo_ws window loaded");

    const sidebarToggle = document.querySelector<HTMLButtonElement>('#sidebarToggle');
    if (sidebarToggle) {
        // restaurer l’état depuis localStorage
        if (localStorage.getItem('sidebar-toggle') === 'true') {
            document.body.classList.add('sidenav-toggled');
        }

        sidebarToggle.addEventListener('click', (event) => {
            event.preventDefault();
            document.body.classList.toggle('sidenav-toggled');
            localStorage.setItem('sidebar-toggle', document.body.classList.contains('sidenav-toggled') ? 'true' : 'false');
        });
    }

    const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
    Array.from(tooltipTriggerList).map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
    const toastElList = document.querySelectorAll('.toast');
    Array.from(toastElList).map(toastEl => new bootstrap.Toast(toastEl));
    const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]');
    Array.from(popoverTriggerList).map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl));

    const gobackto = location.pathname + location.search;

    document.querySelectorAll<HTMLAnchorElement>('a[data-setlang]').forEach((a) => {
        const href = a.getAttribute("href");
        if (!href) return; // pas de href => on ignore

        const url = new URL(href, location.origin);
        url.searchParams.set("gobackto", gobackto);

        // conserve une URL relative (path + query)
        a.setAttribute("href", url.pathname + "?" + url.searchParams.toString());
    });

    const endpointSelect = document.querySelector<HTMLSelectElement>("#demoWsEndpointSelect");
    const methodSelect = document.querySelector<HTMLSelectElement>("#demoWsMethodSelect");
    const modeSelect = document.querySelector<HTMLSelectElement>("#demoWsModeSelect");
    const targetGroup = document.querySelector<HTMLDivElement>("#demoWsTargetGroup");
    const targetLabel = document.querySelector<HTMLLabelElement>("#demoWsTargetLabel");
    const targetInput = document.querySelector<HTMLInputElement>("#demoWsTargetInput");
    const filterGroup = document.querySelector<HTMLDivElement>("#demoWsFilterGroup");
    const filterTextarea = document.querySelector<HTMLTextAreaElement>("#demoWsFilterTextarea");
    const configGroup = document.querySelector<HTMLDivElement>("#demoWsConfigGroup");
    const configTextarea = document.querySelector<HTMLTextAreaElement>("#demoWsConfigTextarea");
    const statusBadge = document.querySelector<HTMLSpanElement>("#demoWsStatusBadge");
    const stateText = document.querySelector<HTMLSpanElement>("#demoWsStateText");
    const endpointText = document.querySelector<HTMLSpanElement>("#demoWsEndpointText");
    const subscriptionText = document.querySelector<HTMLSpanElement>("#demoWsSubscriptionText");
    const requestText = document.querySelector<HTMLSpanElement>("#demoWsRequestText");
    const eventCountText = document.querySelector<HTMLSpanElement>("#demoWsEventCountText");
    const notificationCountText = document.querySelector<HTMLSpanElement>("#demoWsNotificationCountText");
    const uiLogCountText = document.querySelector<HTMLSpanElement>("#demoWsUiLogCountText");
    const suppressedLogCountText = document.querySelector<HTMLSpanElement>("#demoWsSuppressedLogCountText");
    const lastEventKindText = document.querySelector<HTMLSpanElement>("#demoWsLastEventKindText");
    const connectButton = document.querySelector<HTMLButtonElement>("#demoWsConnectButton");
    const disconnectButton = document.querySelector<HTMLButtonElement>("#demoWsDisconnectButton");
    const subscribeButton = document.querySelector<HTMLButtonElement>("#demoWsSubscribeButton");
    const unsubscribeButton = document.querySelector<HTMLButtonElement>("#demoWsUnsubscribeButton");
    const clearLogButton = document.querySelector<HTMLButtonElement>("#demoWsClearLogButton");
    const logTextarea = document.querySelector<HTMLTextAreaElement>("#demoWsLogTextarea");

    if (
        !eventCountText || !notificationCountText || !uiLogCountText || !suppressedLogCountText || !lastEventKindText ||
        !endpointSelect || !methodSelect || !modeSelect || !targetGroup || !targetLabel || !targetInput ||
        !filterGroup || !filterTextarea || !configGroup || !configTextarea || !statusBadge ||
        !stateText || !endpointText || !subscriptionText || !requestText || !connectButton ||
        !disconnectButton || !subscribeButton || !unsubscribeButton || !clearLogButton || !logTextarea
    ) {
        debug("demo_ws UI controls not found");
        return;
    }

    let unlistenLogEvent: UnlistenFn | null = null;
    let unlistenStatusEvent: UnlistenFn | null = null;

    try {
        unlistenLogEvent = await listen<string>("demo-ws-log", (event) => {
            appendLogLine(logTextarea, event.payload);
        });

        unlistenStatusEvent = await listen<DemoWsStatusPayload>("demo-ws-status", (event) => {
            applyStatusToUi(
                event.payload,
                statusBadge,
                stateText,
                endpointText,
                subscriptionText,
                eventCountText,
                notificationCountText,
                uiLogCountText,
                suppressedLogCountText,
                lastEventKindText,
                connectButton,
                disconnectButton,
                subscribeButton,
                unsubscribeButton,
            );
        });
    } catch (error) {
        appendLogLine(logTextarea, `[ui] event listen error: ${String(error)}`);
    }

    try {
        const endpoints = await invoke<DemoWsEndpointSummary[]>("demo_ws_list_endpoints");

        endpointSelect.innerHTML = "";
        for (const endpoint of endpoints) {
            const option = document.createElement("option");
            option.value = endpoint.name;
            option.textContent = `${endpoint.name} — ${endpoint.provider} — ${endpoint.resolvedUrl}`;
            option.disabled = !endpoint.enabled;
            endpointSelect.appendChild(option);
        }
    } catch (error) {
        appendLogLine(logTextarea, `[ui] endpoint list error: ${String(error)}`);
    }

    updateFormVisibility(
        methodSelect,
        modeSelect,
        targetGroup,
        targetLabel,
        targetInput,
        filterGroup,
        filterTextarea,
        configGroup,
        configTextarea,
    );

    methodSelect.addEventListener("change", () => {
        updateFormVisibility(
            methodSelect,
            modeSelect,
            targetGroup,
            targetLabel,
            targetInput,
            filterGroup,
            filterTextarea,
            configGroup,
            configTextarea,
        );
    });

    modeSelect.addEventListener("change", () => {
        updateFormVisibility(
            methodSelect,
            modeSelect,
            targetGroup,
            targetLabel,
            targetInput,
            filterGroup,
            filterTextarea,
            configGroup,
            configTextarea,
        );
    });

    try {
        const status = await invoke<DemoWsStatusPayload>("demo_ws_get_status");
        applyStatusToUi(
            status,
            statusBadge,
            stateText,
            endpointText,
            subscriptionText,
            eventCountText,
            notificationCountText,
            uiLogCountText,
            suppressedLogCountText,
            lastEventKindText,
            connectButton,
            disconnectButton,
            subscribeButton,
            unsubscribeButton,
        );
    } catch (error) {
        appendLogLine(logTextarea, `[ui] initial status error: ${String(error)}`);
    }

    appendLogLine(logTextarea, "[ui] demo_ws window loaded");

    connectButton.addEventListener("click", async () => {
        try {
            const status = await invoke<DemoWsStatusPayload>("demo_ws_connect", {
                endpointName: endpointSelect.value,
            });

            applyStatusToUi(
                status,
                statusBadge,
                stateText,
                endpointText,
                subscriptionText,
                eventCountText,
                notificationCountText,
                uiLogCountText,
                suppressedLogCountText,
                lastEventKindText,
                connectButton,
                disconnectButton,
                subscribeButton,
                unsubscribeButton,
            );
        } catch (error) {
            appendLogLine(logTextarea, `[ui] connect error: ${String(error)}`);
        }
    });

    disconnectButton.addEventListener("click", async () => {
        try {
            const status = await invoke<DemoWsStatusPayload>("demo_ws_disconnect");

            applyStatusToUi(
                status,
                statusBadge,
                stateText,
                endpointText,
                subscriptionText,
                eventCountText,
                notificationCountText,
                uiLogCountText,
                suppressedLogCountText,
                lastEventKindText,
                connectButton,
                disconnectButton,
                subscribeButton,
                unsubscribeButton,
            );
        } catch (error) {
            appendLogLine(logTextarea, `[ui] disconnect error: ${String(error)}`);
        }
    });

    subscribeButton.addEventListener("click", async () => {
        const request: DemoWsSubscribeRequest = {
            method: methodSelect.value,
            mode: modeSelect.value,
            target: targetInput.value.trim() === "" ? null : targetInput.value.trim(),
            filterJson: filterTextarea.value.trim() === "" ? null : filterTextarea.value.trim(),
            configJson: configTextarea.value.trim() === "" ? null : configTextarea.value.trim(),
        };

        try {
            const requestId = await invoke<number>("demo_ws_subscribe", { request });
            requestText.textContent = `request_id=${requestId}`;
            appendLogLine(logTextarea, `[ui] subscribe request sent: request_id=${requestId}`);
        } catch (error) {
            appendLogLine(logTextarea, `[ui] subscribe error: ${String(error)}`);
        }
    });

    unsubscribeButton.addEventListener("click", async () => {
        try {
            const requestId = await invoke<number>("demo_ws_unsubscribe_current");
            requestText.textContent = `unsubscribe_request_id=${requestId}`;
            appendLogLine(logTextarea, `[ui] unsubscribe request sent: request_id=${requestId}`);
        } catch (error) {
            appendLogLine(logTextarea, `[ui] unsubscribe error: ${String(error)}`);
        }
    });

    clearLogButton.addEventListener("click", () => {
        logTextarea.value = "";
    });

    window.addEventListener("beforeunload", () => {
        if (unlistenLogEvent) {
            unlistenLogEvent();
        }

        if (unlistenStatusEvent) {
            unlistenStatusEvent();
        }
    });
});