"use strict";

import * as USIMP from "./usimp.js";

export class App {
    account;
    defaultLocation;
    main;
    windows;
    session;

    constructor() {
        if (localStorage.session === undefined) {
            this.defaultLocation = '/welcome';
            this.account = null;
        } else {
            let session = JSON.parse(localStorage.session);
            this.defaultLocation = '/';
            this.account = session.account;
        }

        this.main = document.getElementsByTagName("main")[0];
        this.windows = document.getElementById("windows");

        window.addEventListener("hashchange", event => {
            this.handleUrl(event.newURL);
        });

        this.handleUrl(document.URL);
    }

    setHash(hash) {
        let url = new URL(document.URL);
        url.hash = hash;
        location.href = url.toString();
    }

    handleUrl(url) {
        this.handleHash(new URL(url).hash);
    }

    handleHash(hash) {
        if (hash[0] === '#') hash = hash.substr(1);

        let defaultCase = () => {
            history.replaceState(null, null, `#${this.defaultLocation}`);
            this.handleHash(this.defaultLocation);
        }

        switch (hash) {
            case "/":
                if (!this.session) {
                    return defaultCase();
                }
                this.hideWindows();
                this.showMain();
                this.removeAllWindows();
                this.setupMain();
                break;
            case "/welcome":
                this.hideMain();
                this.showWindows();
                this.removeAllWindows();
                this.addWelcomeWindow();
                break;
            case "/login":
                if (this.session) {
                    return defaultCase();
                }
                this.hideMain();
                this.showWindows();
                this.removeAllWindows();
                this.addLoginWindow();
                break;
            default:
                console.warn(`Invalid url hash #${hash}`);
                return defaultCase();
        }

        //this.setHash(hash);
    }

    async login(accountName, domainName, password) {
        let domain;
        try {
            domain = await USIMP.Domain.fromName(domainName);
        } catch (error) {
            if (error instanceof DOMException) {
                throw Error("Connection timed out");
            } else {
                throw Error("Invalid USIMP domain");
            }
        }

        let session = new USIMP.Session(domain);
        let rtt = await session.chooseDomainServer();
        console.log(rtt);

        let response = await session.authenticate(accountName, password);
        if (response.status === "success") {
            this.session = session;
            this.defaultLocation = "/";
            this.setHash("/");
        } else {
            throw Error(response.message);
        }
    }

    hideMain() {
        this.main.style.visibility = "hidden";
    }

    showMain() {
        this.main.style.visibility = "visible";
    }

    hideWindows() {
        this.windows.style.visibility = "hidden";
    }

    showWindows() {
        this.windows.style.visibility = "visible";
    }

    removeAllWindows() {
        while (this.windows.lastChild) this.windows.removeChild(this.windows.lastChild);
    }

    addWelcomeWindow() {
        let win = document.createElement("div");
        win.classList.add("window-welcome");

        win.innerHTML = `
            <h1>Welcome to Locutus!</h1>
            <a href="#/login" class="button">Login</a>`;

        this.windows.appendChild(win);
    }

    addMessage(message) {
        let msg = document.createElement("div");
        msg.classList.add("message");

        msg.innerText = message;

        let chat = this.main.getElementsByClassName("chat-history")[0];
        chat.appendChild(msg);
        chat.scrollTop = chat.scrollHeight;
    }

    addLoginWindow() {
        let win = document.createElement("div");
        win.classList.add("window-login");

        win.innerHTML = `
            <h1>Login to USIMP Account</h1>
            <form>
                <input name="account" placeholder="Account name" type="text" required/>
                <input name="domain" placeholder="Domain" type="text" pattern="([a-zA-Z0-9_-]+\\.)+[a-zA-Z]{2,}" required/>
                <input name="password" placeholder="Password" type="password" required/>
                <button type="submit">Login</button>
            </form>`;

        win.getElementsByTagName("form")[0].addEventListener("submit", async (evt) => {
            evt.preventDefault();
            let form = evt.target;
            for (let e of form) e.disabled = true;

            for (let d of form.getElementsByTagName("div")) {
                form.removeChild(d);
            }

            function formError(msg) {
                let div = document.createElement("div");
                div.classList.add("error");
                div.innerText = msg;
                form.appendChild(div);
            }

            try {
                await this.login(form.account.value, form.domain.value, form.password.value);
            } catch (error) {
                if (error.toString() === "Error: unable to authenticate") {
                    document.getElementsByName("account")[0].setAttribute("invalid", "invalid");
                } else {
                    document.getElementsByName("domain")[0].setAttribute("invalid", "invalid");
                }
                formError(error.toString());
                console.error(error);
            } finally {
                for (let e of form) e.disabled = false;
            }
        });

        this.windows.appendChild(win);

        document.getElementsByName("domain")[0].addEventListener("input", (event) => {
            event.target.removeAttribute("invalid");
        });

        document.getElementsByName("account")[0].addEventListener("input", (event) => {
            event.target.removeAttribute("invalid");
        });

        document.getElementsByName("account")[0].focus();
    }

    setupMain() {
        this.main.innerHTML = `
            <div class="chat">
                <div class="chat-history"></div>
                <div class="chat-input-wrapper">
                    <input name="message" type="text" autocomplete="off"/>
                </div>
            </div>`;

        let input = document.getElementsByName("message")[0];
        input.addEventListener("keyup", (event) => {
            if (event.key === "Enter" && input.value.length > 0) {
                this.session.sendEvent("60nc0XXDIYUh6QzX4p0rMpCdzDmxghZLZk8dLuQh628", {
                    message: input.value,
                });
                this.addMessage(input.value);
                input.value = "";
            }
        });

        this.session.subscribe(response => {
            this.addMessage(response.data.event.data.message);
        });
    }
}
