import {sendApiPost, TesoftComponent} from "../scripts/main.ts";
import {TesoftButton} from "./button.ts";
import {TesoftInput} from "./input.ts";

export class TesoftNav extends TesoftComponent {
    private readonly smallMenuButton: TesoftButton;
    private readonly smallMenuButtonSpan: HTMLSpanElement;
    private readonly smallMenuDialog: HTMLDialogElement;
    private readonly smallMenuDiv: HTMLDivElement;
    private readonly execDialog: HTMLDialogElement;
    private readonly execInput: TesoftInput;
    private readonly execResultsDiv: HTMLDivElement;
    private readonly commands: Map<string, (text: string) => Promise<void>>;

    constructor() {
        super();

        const template = document.getElementById("tesoft-nav-template") as HTMLTemplateElement;
        const templateContent = template.content;

        const shadowRoot = this.attachShadow({mode: "open"});
        shadowRoot.appendChild(templateContent.cloneNode(true));

        this.smallMenuButton = shadowRoot.querySelector<TesoftButton>("tesoft-button.small-menu")!;
        this.smallMenuButtonSpan = shadowRoot.querySelector<HTMLSpanElement>("tesoft-button.small-menu span")!;
        this.smallMenuDialog = shadowRoot.querySelector<HTMLDialogElement>("dialog.small-menu")!;
        this.smallMenuDiv = shadowRoot.querySelector<HTMLDivElement>("dialog.small-menu > div")!;
        this.execDialog = shadowRoot.querySelector<HTMLDialogElement>("dialog.exec")!;
        this.execInput = shadowRoot.querySelector<TesoftInput>("dialog.exec tesoft-input")!;
        this.execResultsDiv = shadowRoot.querySelector<HTMLDivElement>("dialog.exec .results")!;
        this.commands = new Map<string, (text: string) => Promise<void>>([
            ["login", this.login.bind(this)],
            ["logout", this.logout.bind(this)],
        ]);

        this.smallMenuButton.addEventListener("click", () => {
            this.updateSmallMenu();
            this.smallMenuDialog.showModal();
            this.smallMenuDialog.style.left = `${this.smallMenuButton.offsetLeft}px`;
            this.smallMenuDialog.style.top = `${this.smallMenuButton.offsetTop}px`;
            this.smallMenuDialog.style.width = `${this.smallMenuButton.offsetWidth}px`;
        });

        this.execInput.addEventListener("keyup", async (event) => {
            if (event.key === "Enter") {
                await this.exec(this.execInput.value);
            }
        });

        shadowRoot.addEventListener("slotchange", () => {
            const selected = this.querySelector("[selected]");
            if (selected !== null) {
                this.smallMenuButtonSpan.textContent = selected.textContent;
            }
        });

        document.addEventListener("keyup", async (event) => {
            if (event.ctrlKey && event.key === "p") {
                event.preventDefault();

                await this.exec("");
                this.execDialog.showModal();
                this.execInput.value = "";
                this.execInput.focus();
            }
        });
    }

    private updateSmallMenu() {
        this.smallMenuDiv.innerHTML = "";

        for (const child of this.children) {
            const button = document.createElement("tesoft-button") as TesoftButton;
            button.innerText = child.textContent.trim();
            button.transparent = "";
            this.smallMenuDiv.appendChild(button);

            button.href = (child as HTMLAnchorElement).href;
            if (child.hasAttribute("selected")) {
                button.selected = "1";
            }
        }
    }

    private async exec(text: string) {
        this.setResultText("Press enter to send command.");

        if (text) {
            const spaceIndex = text.indexOf(" ");
            const prefix = spaceIndex === -1 ? text : text.substring(0, spaceIndex);

            const command = this.commands.get(prefix);
            if (command === undefined) {
                this.setResultText("Unknown command.");
                return;
            }
            await command(text.substring(prefix.length).trimStart());
        }
    }

    private async login(text: string) {
        const response = await sendApiPost("login", {
            password: text,
        });

        if (response.ok) {
            this.setResultText("Login successful.");
        } else {
            const body = await response.json();
            this.setResultText(`Login failed: ${body.message ?? body}`);
        }
    }

    private async logout(_text: string) {
        const response = await sendApiPost("logout", {});

        if (response.ok) {
            this.setResultText("Logout successful.");
        } else {
            const body = await response.json();
            this.setResultText(`Logout failed: ${body.message ?? body}`);
        }
    }

    private setResultText(text: string) {
        this.execResultsDiv.innerHTML = "";

        if (text) {
            const div = document.createElement("div");
            div.textContent = text;
            this.execResultsDiv.appendChild(div);
        }
    }
}

customElements.define("tesoft-nav", TesoftNav);
