import * as loader from "tc-loader";
import {Stage} from "tc-loader";
import {getMenuBarDriver, MenuBarEntry} from "tc-shared/ui/frames/menu-bar/index";
import {ClientIcon} from "svg-sprites/client-icons";
import {global_client_actions} from "tc-shared/events/GlobalEvents";
import {server_connections} from "tc-shared/ConnectionManager";
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
import {
    add_server_to_bookmarks,
    Bookmark,
    bookmarkEvents,
    bookmarks,
    BookmarkType,
    boorkmak_connect,
    DirectoryBookmark
} from "tc-shared/bookmarks";
import {getBackend} from "tc-shared/backend";
import {tr} from "tc-shared/i18n/localize";

function renderConnectionItems() {
    const items: MenuBarEntry[] = [];

    const currentConnectionConnected = !!server_connections.getActiveConnectionHandler()?.connected;
    items.push({
        type: "normal",
        label: tr("Connect to a server"),
        icon: ClientIcon.Connect,
        click: () => global_client_actions.fire("action_open_window_connect", { newTab: currentConnectionConnected })
    });

    items.push({
        type: "normal",
        label: tr("Disconnect from current server"),
        icon: ClientIcon.Disconnect,
        disabled: !currentConnectionConnected,
        click: () => server_connections.getActiveConnectionHandler()?.disconnectFromServer()
    });

    items.push({
        type: "normal",
        label: tr("Disconnect from all servers"),
        icon: ClientIcon.Disconnect,
        disabled: server_connections.getAllConnectionHandlers().findIndex(e => e.connected) === -1,
        click: () => server_connections.getAllConnectionHandlers().forEach(connection => connection.disconnectFromServer())
    });

    if(__build.target === "client") {
        items.push({ type: "separator" });
        items.push({
            type: "normal",
            label: tr("Quit"),
            icon: ClientIcon.CloseButton,
            click: () => getBackend("native").quit()
        });
    }

    return items;
}

function renderBookmarkItems() {
    const items: MenuBarEntry[] = [];

    const renderBookmark = (bookmark: Bookmark | DirectoryBookmark): MenuBarEntry => {
        if(bookmark.type === BookmarkType.ENTRY) {
            return {
                type: "normal",
                label: bookmark.display_name,
                click: () => boorkmak_connect(bookmark),
                icon: bookmark.last_icon_id ? { serverUniqueId: bookmark.last_icon_server_id, iconId: bookmark.last_icon_id } : undefined
            };
        } else {
            return {
                type: "normal",
                label: bookmark.display_name,
                icon: ClientIcon.Folder,
                children: bookmark.content.map(renderBookmark)
            }
        }
    }

    items.push({
        type: "normal",
        icon: ClientIcon.BookmarkManager,
        label: tr("Manage bookmarks"),
        click: () => global_client_actions.fire("action_open_window", { window: "bookmark-manage" })
    });

    items.push({
        type: "normal",
        icon: ClientIcon.BookmarkAdd,
        label: tr("Add current server to bookmarks"),
        disabled: !server_connections.getActiveConnectionHandler()?.connected,
        click: () => add_server_to_bookmarks(server_connections.getActiveConnectionHandler())
    });

    const rootMarks = bookmarks().content;
    if(rootMarks.length !== 0) {
        items.push({ type: "separator" });
        items.push(...rootMarks.map(renderBookmark));
    }

    return items;
}

function renderPermissionItems() : MenuBarEntry[] {
    const items: MenuBarEntry[] = [];

    const currentConnectionConnected = !!server_connections.getActiveConnectionHandler()?.connected;
    items.push({
        type: "normal",
        label: tr("Server Groups"),
        icon: ClientIcon.PermissionServerGroups,
        click: () => global_client_actions.fire("action_open_window_permissions", { defaultTab: "groups-server" }),
        disabled: !currentConnectionConnected
    });

    items.push({
        type: "normal",
        label: tr("Client Permissions"),
        icon: ClientIcon.PermissionClient,
        click: () => global_client_actions.fire("action_open_window_permissions", { defaultTab: "client" }),
        disabled: !currentConnectionConnected
    });

    items.push({
        type: "normal",
        label: tr("Channel Client Permissions"),
        icon: ClientIcon.PermissionClient,
        click: () => global_client_actions.fire("action_open_window_permissions", { defaultTab: "client-channel" }),
        disabled: !currentConnectionConnected
    });

    items.push({
        type: "normal",
        label: tr("Channel Groups"),
        icon: ClientIcon.PermissionChannel,
        click: () => global_client_actions.fire("action_open_window_permissions", { defaultTab: "groups-channel" }),
        disabled: !currentConnectionConnected
    });

    items.push({
        type: "normal",
        label: tr("Channel Permissions"),
        icon: ClientIcon.PermissionChannel,
        click: () => global_client_actions.fire("action_open_window_permissions", { defaultTab: "channel" }),
        disabled: !currentConnectionConnected
    });

    items.push({ type: "separator" });

    items.push({
        type: "normal",
        label: tr("List Privilege Keys"),
        icon: ClientIcon.Token,
        click: () => global_client_actions.fire("action_open_window", { window: "token-list" }),
        disabled: !currentConnectionConnected
    });

    items.push({
        type: "normal",
        label: tr("Use Privilege Key"),
        icon: ClientIcon.TokenUse,
        click: () => global_client_actions.fire("action_open_window", { window: "token-use" }),
        disabled: !currentConnectionConnected
    });

    return items;
}

function renderToolItems() : MenuBarEntry[] {
    const items: MenuBarEntry[] = [];

    const currentConnectionConnected = !!server_connections.getActiveConnectionHandler()?.connected;
    if(__build.target === "web") {
        items.push({
            type: "normal",
            label: tr("Echo Test"),
            icon: ClientIcon.ActivateMicrophone,
            click: () => global_client_actions.fire("action_open_window", { window: "server-echo-test" }),
            disabled: !currentConnectionConnected
        });
    }

    items.push({
        type: "normal",
        label: tr("Ban List"),
        icon: ClientIcon.BanList,
        click: () => global_client_actions.fire("action_open_window", { window: "ban-list" }),
        disabled: !currentConnectionConnected
    });

    items.push({
        type: "normal",
        label: tr("Query List"),
        icon: ClientIcon.ServerQuery,
        click: () => global_client_actions.fire("action_open_window", { window: "query-manage" }),
        disabled: !currentConnectionConnected
    });

    items.push({
        type: "normal",
        label: tr("Query Create"),
        icon: ClientIcon.ServerQuery,
        click: () => global_client_actions.fire("action_open_window", { window: "query-create" }),
        disabled: !currentConnectionConnected
    });

    items.push({ type: "separator" });

    items.push({
        type: "normal",
        label: tr("Modify CSS variables"),
        click: () => global_client_actions.fire("action_open_window", { window: "css-variable-editor" })
    });

    items.push({
        type: "normal",
        label: tr("Open Registry"),
        click: () => global_client_actions.fire("action_open_window", { window: "settings-registry" })
    });

    items.push({ type: "separator" });

    items.push({
        type: "normal",
        label: tr("Settings"),
        click: () => global_client_actions.fire("action_open_window_settings")
    });

    return items;
}

function renderHelpItems() : MenuBarEntry[] {
    const items: MenuBarEntry[] = [];

    if(__build.target === "client") {
        items.push({
            type: "normal",
            label: tr("Check for updates"),
            icon: ClientIcon.CheckUpdate,
            click: () => getBackend("native").openClientUpdater()
        });

        items.push({
            type: "normal",
            label: tr("Open client changelog"),
            click: () => getBackend("native").openChangeLog()
        });
    }

    items.push({
        type: "normal",
        label: tr("Visit TeaSpeak.de"),
        click: () => window.open('https://teaspeak.de/', '_blank')
    });

    items.push({
        type: "normal",
        label: tr("Visit TeaSpeak forum"),
        click: () => window.open('https://forum.teaspeak.de/', '_blank')
    });

    if(__build.target === "client" && getBackend("native").showDeveloperOptions()) {
        items.push({ type: "separator" });
        items.push({
            type: "normal",
            label: tr("Open developer tools"),
            click: () => getBackend("native").openDeveloperTools()
        });

        items.push({
            type: "normal",
            label: tr("Reload UI"),
            click: () => getBackend("native").reloadWindow()
        });
    }
    items.push({ type: "separator" });

    items.push({
        type: "normal",
        label: __build.target === "web" ? tr("About TeaWeb") : tr("About TeaClient"),
        click: () => global_client_actions.fire("action_open_window", { window: "about" })
    });

    return items;
}

function updateMenuBar() {
    const items: MenuBarEntry[] = [];

    items.push({
        type: "normal",
        label: tr("Connection"),
        children: renderConnectionItems()
    });

    items.push({
        type: "normal",
        label: tr("Favorites"),
        children: renderBookmarkItems()
    });

    items.push({
        type: "normal",
        label: tr("Permissions"),
        children: renderPermissionItems()
    });

    items.push({
        type: "normal",
        label: tr("Tools"),
        children: renderToolItems()
    });

    items.push({
        type: "normal",
        label: tr("Help"),
        children: renderHelpItems()
    });

    /* TODO: Check if it's not exactly the same menu bar */
    getMenuBarDriver().setEntries(items);
}

let updateListener: MenuBarUpdateListener;
class MenuBarUpdateListener {
    private generalHandlerEvents: (() => void)[] = [];
    private registeredHandlerEvents: {[key: string]: (() => void)[]} = {};

    initializeListeners() {
        this.generalHandlerEvents.push(server_connections.events().on("notify_handler_created", event => {
            this.registerHandlerEvents(event.handler);
        }));
        this.generalHandlerEvents.push(server_connections.events().on("notify_handler_deleted", event => {
            this.registeredHandlerEvents[event.handlerId]?.forEach(callback => callback());
            delete this.registeredHandlerEvents[event.handlerId];
        }));
        this.generalHandlerEvents.push(server_connections.events().on("notify_active_handler_changed", () => {
            updateMenuBar();
        }));
        this.generalHandlerEvents.push(bookmarkEvents.on("notify_bookmarks_updated", () => {
            updateMenuBar();
        }))
        server_connections.getAllConnectionHandlers().forEach(handler => this.registerHandlerEvents(handler));
    }

    destroy() {
        this.generalHandlerEvents.forEach(callback => callback());
        Object.keys(this.registeredHandlerEvents).forEach(id => this.registeredHandlerEvents[id].forEach(callback => callback()));

        this.registeredHandlerEvents = {};
        this.generalHandlerEvents = [];
    }

    private registerHandlerEvents(handler: ConnectionHandler) {
        const events = this.registeredHandlerEvents[handler.handlerId] = [];
        events.push(handler.events().on("notify_connection_state_changed", () => {
            updateMenuBar();
        }));
    }
}

loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
    name: "menu bar entries init",
    function: async () => {
        updateMenuBar();

        updateListener = new MenuBarUpdateListener();
        updateListener.initializeListeners();
    },
    priority: 50
});