import { Menu, Tray, BrowserWindow } from "electron";
import path from "path";
import windowService from "./window.js";
import optionService from "./options.js";
import { fileURLToPath } from "url";
import type { KeyboardActionNames } from "./keyboard_actions_interface.js";
import date_notes from "./date_notes.js";
import type BNote from "../becca/entities/bnote.js";
import becca from "../becca/becca.js";
import becca_service from "../becca/becca_service.js";
import type BRecentNote from "../becca/entities/brecent_note.js";
import { ipcMain, nativeTheme } from "electron/main";
import { default as i18next, t } from "i18next";
import { isDev, isMac } from "./utils.js";
import cls from "./cls.js";

let tray: Tray;
// `mainWindow.isVisible` doesn't work with `mainWindow.show` and `mainWindow.hide` - it returns `false` when the window
// is minimized
let windowVisibilityMap: Record<number, boolean> = {};; // Dictionary for storing window ID and its visibility status

function getTrayIconPath() {
    let name: string;
    if (isMac) {
        name = "icon-blackTemplate";
    } else if (isDev) {
        name = "icon-purple";
    } else {
        name = "icon-color";
    }

    return path.join(path.dirname(fileURLToPath(import.meta.url)), "../..", "images", "app-icons", "tray", `${name}.png`);
}

function getIconPath(name: string) {
    const suffix = !isMac && nativeTheme.shouldUseDarkColors ? "-inverted" : "";
    return path.join(path.dirname(fileURLToPath(import.meta.url)), "../..", "images", "app-icons", "tray", `${name}Template${suffix}.png`);
}

function registerVisibilityListener(window: BrowserWindow) {
    if (!window) {
        return;
    }

    // They need to be registered before the tray updater is registered
    window.on("show", () => {
        windowVisibilityMap[window.id] = true;
        updateTrayMenu();
    });
    window.on("hide", () => {
        windowVisibilityMap[window.id] = false;
        updateTrayMenu();
    });

    window.on("minimize", updateTrayMenu);
    window.on("maximize", updateTrayMenu);
}

function getWindowTitle(window: BrowserWindow | null) {
    if (!window) {
        return;
    }
    const title = window.getTitle();
    const titleWithoutAppName = title.replace(/\s-\s[^-]+$/, ''); // Remove the name of the app

    // Limit title maximum length to 17
    if (titleWithoutAppName.length > 20) {
        return titleWithoutAppName.substring(0, 17) + '...';
    }

    return titleWithoutAppName;
}

function updateWindowVisibilityMap(allWindows: BrowserWindow[]) {
    const currentWindowIds: number[] = allWindows.map(window => window.id);

    // Deleting closed windows from windowVisibilityMap
    for (const [id, visibility] of Object.entries(windowVisibilityMap)) {
        const windowId = Number(id);
        if (!currentWindowIds.includes(windowId)) {
            delete windowVisibilityMap[windowId];
        }
    }

    // Iterate through allWindows to make sure the ID of each window exists in windowVisibilityMap
    allWindows.forEach(window => {
        const windowId = window.id;
        if (!(windowId in windowVisibilityMap)) {
            // If it does not exist, it is the newly created window
            windowVisibilityMap[windowId] = true;
            registerVisibilityListener(window);
        }
    });
}


function updateTrayMenu() {
    const lastFocusedWindow = windowService.getLastFocusedWindow();
    const allWindows = windowService.getAllWindows();
    updateWindowVisibilityMap(allWindows);

    function ensureVisible(win: BrowserWindow) {
        if (win) {
            win.show();
            win.focus();
        }
    }

    function openNewWindow() {
        if (lastFocusedWindow){
            lastFocusedWindow.webContents.send("globalShortcut", "openNewWindow");
        }
    }

    function triggerKeyboardAction(actionName: KeyboardActionNames) {
        if (lastFocusedWindow){
            lastFocusedWindow.webContents.send("globalShortcut", actionName);
            ensureVisible(lastFocusedWindow);
        }
    }

    function openInSameTab(note: BNote | BRecentNote) {
        if (lastFocusedWindow){
            lastFocusedWindow.webContents.send("openInSameTab", note.noteId);
            ensureVisible(lastFocusedWindow);
        }
    }

    function buildBookmarksMenu() {
        const parentNote = becca.getNoteOrThrow("_lbBookmarks");
        const menuItems: Electron.MenuItemConstructorOptions[] = [];

        for (const bookmarkNote of parentNote?.children) {
            if (bookmarkNote.isLabelTruthy("bookmarkFolder")) {
                menuItems.push({
                    label: bookmarkNote.title,
                    type: "submenu",
                    submenu: bookmarkNote.children.map((subitem) => {
                        return {
                            label: subitem.title,
                            type: "normal",
                            click: () => openInSameTab(subitem)
                        };
                    })
                });
            } else {
                menuItems.push({
                    label: bookmarkNote.title,
                    type: "normal",
                    click: () => openInSameTab(bookmarkNote)
                });
            }
        }

        return menuItems;
    }

    function buildRecentNotesMenu() {
        const recentNotes = becca.getRecentNotesFromQuery(`
            SELECT recent_notes.*
            FROM recent_notes
            JOIN notes USING(noteId)
            WHERE notes.isDeleted = 0
            ORDER BY utcDateCreated DESC
            LIMIT 10
        `);
        const menuItems: Electron.MenuItemConstructorOptions[] = [];
        const formatter = new Intl.DateTimeFormat(undefined, {
            dateStyle: "short",
            timeStyle: "short"
        });

        for (const recentNote of recentNotes) {
            const date = new Date(recentNote.utcDateCreated);

            menuItems.push({
                label: becca_service.getNoteTitle(recentNote.noteId),
                type: "normal",
                sublabel: formatter.format(date),
                click: () => openInSameTab(recentNote)
            });
        }

        return menuItems;
    }

    const windowVisibilityMenuItems: Electron.MenuItemConstructorOptions[] = [];

    // Only call getWindowTitle if windowVisibilityMap has more than one window
    const showTitle = Object.keys(windowVisibilityMap).length > 1;

    for (const idStr in windowVisibilityMap) {
        const id = parseInt(idStr, 10); // Get the ID of the window and make sure it is a number
        const isVisible = windowVisibilityMap[id]; 
        const win = allWindows.find(w => w.id === id);
        if (!win) {
            continue;
        }
        windowVisibilityMenuItems.push({
            label: showTitle ? `${t("tray.show-windows")}: ${getWindowTitle(win)}` : t("tray.show-windows"),
            type: "checkbox",
            checked: isVisible,
            click: () => {
                if (isVisible) {
                    win.hide();
                    windowVisibilityMap[id] = false;
                } else {
                    ensureVisible(win);
                    windowVisibilityMap[id] = true;
                }
            }
        });
    }
    

    const contextMenu = Menu.buildFromTemplate([
        ...windowVisibilityMenuItems, 
        { type: "separator" },
        {
            label: t("tray.open_new_window"),
            type: "normal",
            icon: getIconPath("new-window"),
            click: () => openNewWindow()
        },
        {
            label: t("tray.new-note"),
            type: "normal",
            icon: getIconPath("new-note"),
            click: () => triggerKeyboardAction("createNoteIntoInbox")
        },
        {
            label: t("tray.today"),
            type: "normal",
            icon: getIconPath("today"),
            click: cls.wrap(() => openInSameTab(date_notes.getTodayNote()))
        },
        {
            label: t("tray.bookmarks"),
            type: "submenu",
            icon: getIconPath("bookmarks"),
            submenu: buildBookmarksMenu()
        },
        {
            label: t("tray.recents"),
            type: "submenu",
            icon: getIconPath("recents"),
            submenu: buildRecentNotesMenu()
        },
        { type: "separator" },
        {
            label: t("tray.close"),
            type: "normal",
            icon: getIconPath("close"),
            click: () => {
                const windows = BrowserWindow.getAllWindows();
                windows.forEach(window => {
                    window.close();
                });
            }
        }
    ]);

    tray?.setContextMenu(contextMenu);
}

function changeVisibility() {
    const lastFocusedWindow = windowService.getLastFocusedWindow();
    
    if (!lastFocusedWindow) {
        return;
    }

    // If the window is visible, hide it
    if (windowVisibilityMap[lastFocusedWindow.id]) {
        lastFocusedWindow.hide();
    } else {
        lastFocusedWindow.show();
        lastFocusedWindow.focus();
    }
}

function createTray() {
    if (optionService.getOptionBool("disableTray")) {
        return;
    }

    tray = new Tray(getTrayIconPath());
    tray.setToolTip(t("tray.tooltip"));
    // Restore focus
    tray.on("click", changeVisibility);
    updateTrayMenu();

    if (!isMac) {
        // macOS uses template icons which work great on dark & light themes.
        nativeTheme.on("updated", updateTrayMenu);
    }
    ipcMain.on("reload-tray", updateTrayMenu);
    i18next.on("languageChanged", updateTrayMenu);
}

export default {
    createTray,
    updateTrayMenu
};
