import {
    app,
    BrowserWindow,
    clipboard,
    dialog,
    ipcMain,
    Menu,
    MenuItem,
    MenuItemConstructorOptions,
    shell,
} from 'electron';

import { Main } from '../main';

import { BaseMenu } from 'jslib/electron/baseMenu';

import { isMacAppStore, isSnapStore, isWindowsStore } from 'jslib/electron/utils';

import { ConstantsService } from 'jslib/services/constants.service';

export class MenuMain extends BaseMenu {
    menu: Menu;
    updateMenuItem: MenuItem;
    addNewLogin: MenuItem;
    addNewItem: MenuItem;
    addNewFolder: MenuItem;
    syncVault: MenuItem;
    exportVault: MenuItem;
    settings: MenuItem;
    lockNow: MenuItem;
    logOut: MenuItem;
    twoStepLogin: MenuItem;
    fingerprintPhrase: MenuItem;
    changeMasterPass: MenuItem;
    premiumMembership: MenuItem;
    passwordGenerator: MenuItem;
    passwordHistory: MenuItem;
    searchVault: MenuItem;
    copyUsername: MenuItem;
    copyPassword: MenuItem;
    unlockedRequiredMenuItems: MenuItem[] = [];

    constructor(private main: Main) {
        super(main.i18nService, main.windowMain);
    }

    init() {
        this.initProperties();
        this.initContextMenu();
        this.initApplicationMenu();

        this.updateMenuItem = this.menu.getMenuItemById('checkForUpdates');
        this.addNewLogin = this.menu.getMenuItemById('addNewLogin');
        this.addNewItem = this.menu.getMenuItemById('addNewItem');
        this.addNewFolder = this.menu.getMenuItemById('addNewFolder');
        this.syncVault = this.menu.getMenuItemById('syncVault');
        this.exportVault = this.menu.getMenuItemById('exportVault');
        this.settings = this.menu.getMenuItemById('settings');
        this.lockNow = this.menu.getMenuItemById('lockNow');
        this.logOut = this.menu.getMenuItemById('logOut');
        this.twoStepLogin = this.menu.getMenuItemById('twoStepLogin');
        this.fingerprintPhrase = this.menu.getMenuItemById('fingerprintPhrase');
        this.changeMasterPass = this.menu.getMenuItemById('changeMasterPass');
        this.premiumMembership = this.menu.getMenuItemById('premiumMembership');
        this.passwordGenerator = this.menu.getMenuItemById('passwordGenerator');
        this.passwordHistory = this.menu.getMenuItemById('passwordHistory');
        this.searchVault = this.menu.getMenuItemById('searchVault');
        this.copyUsername = this.menu.getMenuItemById('copyUsername');
        this.copyPassword = this.menu.getMenuItemById('copyPassword');

        this.unlockedRequiredMenuItems = [
            this.addNewLogin, this.addNewItem, this.addNewFolder,
            this.syncVault, this.exportVault, this.settings, this.lockNow, this.twoStepLogin, this.fingerprintPhrase,
            this.changeMasterPass, this.premiumMembership, this.passwordGenerator, this.passwordHistory,
            this.searchVault, this.copyUsername, this.copyPassword];
        this.updateApplicationMenuState(false, true);
    }

    updateApplicationMenuState(isAuthenticated: boolean, isLocked: boolean) {
        this.unlockedRequiredMenuItems.forEach((mi: MenuItem) => {
            if (mi != null) {
                mi.enabled = isAuthenticated && !isLocked;
            }
        });

        if (this.logOut != null) {
            this.logOut.enabled = isAuthenticated;
        }
    }

    private initApplicationMenu() {
        const accountSubmenu: MenuItemConstructorOptions[] = [
            {
                label: this.main.i18nService.t('changeMasterPass'),
                id: 'changeMasterPass',
                click: async () => {
                    const result = await dialog.showMessageBox(this.main.windowMain.win, {
                        title: this.main.i18nService.t('changeMasterPass'),
                        message: this.main.i18nService.t('changeMasterPass'),
                        detail: this.main.i18nService.t('changeMasterPasswordConfirmation'),
                        buttons: [this.main.i18nService.t('yes'), this.main.i18nService.t('no')],
                        cancelId: 1,
                        defaultId: 0,
                        noLink: true,
                    });
                    if (result.response === 0) {
                        await this.openWebVault();
                    }
                },
            },
            {
                label: this.main.i18nService.t('twoStepLogin'),
                id: 'twoStepLogin',
                click: async () => {
                    const result = await dialog.showMessageBox(this.main.windowMain.win, {
                        title: this.main.i18nService.t('twoStepLogin'),
                        message: this.main.i18nService.t('twoStepLogin'),
                        detail: this.main.i18nService.t('twoStepLoginConfirmation'),
                        buttons: [this.main.i18nService.t('yes'), this.main.i18nService.t('no')],
                        cancelId: 1,
                        defaultId: 0,
                        noLink: true,
                    });
                    if (result.response === 0) {
                        await this.openWebVault();
                    }
                },
            },
            {
                label: this.main.i18nService.t('fingerprintPhrase'),
                id: 'fingerprintPhrase',
                click: () => this.main.messagingService.send('showFingerprintPhrase'),
            },
            { type: 'separator' },
            {
                label: this.i18nService.t('logOut'),
                id: 'logOut',
                click: async () => {
                    const result = await dialog.showMessageBox(this.windowMain.win, {
                        title: this.i18nService.t('logOut'),
                        message: this.i18nService.t('logOut'),
                        detail: this.i18nService.t('logOutConfirmation'),
                        buttons: [this.i18nService.t('logOut'), this.i18nService.t('cancel')],
                        cancelId: 1,
                        defaultId: 0,
                        noLink: true,
                    });
                    if (result.response === 0) {
                        this.main.messagingService.send('logout');
                    }
                },
            },
        ];

        this.editMenuItemOptions.submenu = (this.editMenuItemOptions.submenu as MenuItemConstructorOptions[]).concat([
            { type: 'separator' },
            {
                label: this.main.i18nService.t('copyUsername'),
                id: 'copyUsername',
                click: () => this.main.messagingService.send('copyUsername'),
                accelerator: 'CmdOrCtrl+U',
            },
            {
                label: this.main.i18nService.t('copyPassword'),
                id: 'copyPassword',
                click: () => this.main.messagingService.send('copyPassword'),
                accelerator: 'CmdOrCtrl+P',
            },
        ]);

        if (!isWindowsStore() && !isMacAppStore()) {
            accountSubmenu.unshift({
                label: this.main.i18nService.t('premiumMembership'),
                click: () => this.main.messagingService.send('openPremium'),
                id: 'premiumMembership',
            });
        }

        let helpSubmenu: MenuItemConstructorOptions[] = [
            {
                label: this.main.i18nService.t('emailUs'),
                click: () => shell.openExternal('mailTo:hello@bitwarden.com'),
            },
            {
                label: this.main.i18nService.t('visitOurWebsite'),
                click: () => shell.openExternal('https://bitwarden.com/contact'),
            },
            {
                label: this.main.i18nService.t('fileBugReport'),
                click: () => shell.openExternal('https://github.com/bitwarden/desktop'),
            },
        ];

        if (isMacAppStore()) {
            helpSubmenu.push({
                label: this.main.i18nService.t('legal'),
                submenu: [
                    {
                        label: this.main.i18nService.t('termsOfService'),
                        click: () => shell.openExternal('https://bitwarden.com/terms/'),
                    },
                    {
                        label: this.main.i18nService.t('privacyPolicy'),
                        click: () => shell.openExternal('https://bitwarden.com/privacy/'),
                    },
                ],
            });
        }

        helpSubmenu = helpSubmenu.concat([
            { type: 'separator' },
            {
                label: this.main.i18nService.t('followUs'),
                submenu: [
                    {
                        label: this.main.i18nService.t('blog'),
                        click: () => shell.openExternal('https://blog.bitwarden.com'),
                    },
                    {
                        label: 'Twitter',
                        click: () => shell.openExternal('https://twitter.com/bitwarden'),
                    },
                    {
                        label: 'Facebook',
                        click: () => shell.openExternal('https://www.facebook.com/bitwarden/'),
                    },
                    {
                        label: 'GitHub',
                        click: () => shell.openExternal('https://github.com/bitwarden'),
                    },
                ],
            },
            { type: 'separator' },
            {
                label: this.main.i18nService.t('goToWebVault'),
                click: async () => await this.openWebVault(),
            },
        ]);

        if (!isWindowsStore()) {
            helpSubmenu.push({
                label: this.main.i18nService.t('getMobileApp'),
                submenu: [
                    {
                        label: 'iOS',
                        click: () => {
                            shell.openExternal('https://itunes.apple.com/app/' +
                                'bitwarden-free-password-manager/id1137397744?mt=8');
                        },
                    },
                    {
                        label: 'Android',
                        click: () => {
                            shell.openExternal('https://play.google.com/store/apps/' +
                                'details?id=com.x8bit.bitwarden');
                        },
                    },
                ],
            });
            helpSubmenu.push({
                label: this.main.i18nService.t('getBrowserExtension'),
                submenu: [
                    {
                        label: 'Chrome',
                        click: () => {
                            shell.openExternal('https://chrome.google.com/webstore/detail/' +
                                'bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb');
                        },
                    },
                    {
                        label: 'Firefox',
                        click: () => {
                            shell.openExternal('https://addons.mozilla.org/firefox/addon/' +
                                'bitwarden-password-manager/');
                        },
                    },
                    {
                        label: 'Opera',
                        click: () => {
                            shell.openExternal('https://addons.opera.com/extensions/details/' +
                                'bitwarden-free-password-manager/');
                        },
                    },
                    {
                        label: 'Edge',
                        click: () => {
                            shell.openExternal('https://www.microsoft.com/store/p/' +
                                'bitwarden-free-password-manager/9p6kxl0svnnl');
                        },
                    },
                    {
                        label: 'Safari',
                        click: () => {
                            shell.openExternal('https://bitwarden.com/download/');
                        },
                    },
                ],
            });
        }

        const template: MenuItemConstructorOptions[] = [
            {
                label: this.main.i18nService.t('file'),
                submenu: [
                    {
                        label: this.main.i18nService.t('addNewLogin'),
                        click: () => this.main.messagingService.send('newLogin'),
                        accelerator: 'CmdOrCtrl+N',
                        id: 'addNewLogin',
                    },
                    {
                        label: this.main.i18nService.t('addNewItem'),
                        id: 'addNewItem',
                        submenu: [
                            {
                                label: this.main.i18nService.t('typeLogin'),
                                click: () => this.main.messagingService.send('newLogin'),
                                accelerator: 'CmdOrCtrl+Shift+L',
                            },
                            {
                                label: this.main.i18nService.t('typeCard'),
                                click: () => this.main.messagingService.send('newCard'),
                                accelerator: 'CmdOrCtrl+Shift+C',
                            },
                            {
                                label: this.main.i18nService.t('typeIdentity'),
                                click: () => this.main.messagingService.send('newIdentity'),
                                accelerator: 'CmdOrCtrl+Shift+I',
                            },
                            {
                                label: this.main.i18nService.t('typeSecureNote'),
                                click: () => this.main.messagingService.send('newSecureNote'),
                                accelerator: 'CmdOrCtrl+Shift+S',
                            },
                        ],
                    },
                    {
                        label: this.main.i18nService.t('addNewFolder'),
                        id: 'addNewFolder',
                        click: () => this.main.messagingService.send('newFolder'),
                    },
                    { type: 'separator' },
                    {
                        label: this.main.i18nService.t('syncVault'),
                        id: 'syncVault',
                        click: () => this.main.messagingService.send('syncVault'),
                    },
                    {
                        label: this.main.i18nService.t('exportVault'),
                        id: 'exportVault',
                        click: () => this.main.messagingService.send('exportVault'),
                    },
                ],
            },
            this.editMenuItemOptions,
            {
                label: this.main.i18nService.t('view'),
                submenu: ([
                    {
                        label: this.main.i18nService.t('searchVault'),
                        id: 'searchVault',
                        click: () => this.main.messagingService.send('focusSearch'),
                        accelerator: 'CmdOrCtrl+F',
                    },
                    { type: 'separator' },
                    {
                        label: this.main.i18nService.t('passwordGenerator'),
                        id: 'passwordGenerator',
                        click: () => this.main.messagingService.send('openPasswordGenerator'),
                        accelerator: 'CmdOrCtrl+G',
                    },
                    {
                        label: this.main.i18nService.t('passwordHistory'),
                        id: 'passwordHistory',
                        click: () => this.main.messagingService.send('openPasswordHistory'),
                    },
                    { type: 'separator' },
                ] as MenuItemConstructorOptions[]).concat(this.viewSubMenuItemOptions),
            },
            {
                label: this.main.i18nService.t('account'),
                submenu: accountSubmenu,
            },
            this.windowMenuItemOptions,
            {
                label: this.main.i18nService.t('help'),
                role: 'help',
                submenu: helpSubmenu,
            },
        ];

        const firstMenuOptions: MenuItemConstructorOptions[] = [
            { type: 'separator' },
            {
                label: this.main.i18nService.t(process.platform === 'darwin' ? 'preferences' : 'settings'),
                id: 'settings',
                click: () => this.main.messagingService.send('openSettings'),
                accelerator: 'CmdOrCtrl+,',
            },
            {
                label: this.main.i18nService.t('lockNow'),
                id: 'lockNow',
                click: () => this.main.messagingService.send('lockVault'),
                accelerator: 'CmdOrCtrl+L',
            },
        ];

        const updateMenuItem = {
            label: this.main.i18nService.t('checkForUpdates'),
            click: () => this.main.updaterMain.checkForUpdate(true),
            id: 'checkForUpdates',
        };

        if (process.platform === 'darwin') {
            const firstMenuPart: MenuItemConstructorOptions[] = [
                {
                    label: this.main.i18nService.t('aboutBitwarden'),
                    role: 'about',
                },
            ];

            if (!isMacAppStore()) {
                firstMenuPart.push(updateMenuItem);
            }

            template.unshift({
                label: 'Bitwarden',
                submenu: firstMenuPart.concat(firstMenuOptions, [
                    { type: 'separator' },
                ], this.macAppMenuItemOptions),
            });

            // Window menu
            template[template.length - 2].submenu = this.macWindowSubmenuOptions;
        } else {
            // File menu
            template[0].submenu = (template[0].submenu as MenuItemConstructorOptions[]).concat(
                firstMenuOptions, {
                label: this.i18nService.t('quitBitwarden'),
                role: 'quit',
            });

            // About menu
            const aboutMenuAdditions: MenuItemConstructorOptions[] = [
                { type: 'separator' },
            ];

            if (!isWindowsStore() && !isSnapStore()) {
                aboutMenuAdditions.push(updateMenuItem);
            }

            aboutMenuAdditions.push({
                label: this.i18nService.t('aboutBitwarden'),
                click: async () => {
                    const aboutInformation = this.i18nService.t('version', app.getVersion()) +
                        '\nShell ' + process.versions.electron +
                        '\nRenderer ' + process.versions.chrome +
                        '\nNode ' + process.versions.node +
                        '\nArchitecture ' + process.arch;
                    const result = await dialog.showMessageBox(this.windowMain.win, {
                        title: 'Bitwarden',
                        message: 'Bitwarden',
                        detail: aboutInformation,
                        type: 'info',
                        noLink: true,
                        buttons: [this.i18nService.t('ok'), this.i18nService.t('copy')],
                    });
                    if (result.response === 1) {
                        clipboard.writeText(aboutInformation);
                    }
                },
            });

            template[template.length - 1].submenu =
                (template[template.length - 1].submenu as MenuItemConstructorOptions[]).concat(aboutMenuAdditions);
        }

        (template[template.length - 2].submenu as MenuItemConstructorOptions[]).splice(1, 0,
            {
                label: this.main.i18nService.t(process.platform === 'darwin' ? 'hideToMenuBar' : 'hideToTray'),
                click: () => this.main.messagingService.send('hideToTray'),
                accelerator: 'CmdOrCtrl+Shift+M',
            },
            {
                type: 'checkbox',
                label: this.main.i18nService.t('alwaysOnTop'),
                checked: this.windowMain.win.isAlwaysOnTop(),
                click: () => this.main.windowMain.toggleAlwaysOnTop(),
                accelerator: 'CmdOrCtrl+Shift+T',
            });
        this.menu = Menu.buildFromTemplate(template);
        Menu.setApplicationMenu(this.menu);
    }

    private async openWebVault() {
        let webUrl = 'https://vault.bitwarden.com';
        const urlsObj: any = await this.main.storageService.get(ConstantsService.environmentUrlsKey);
        if (urlsObj != null) {
            if (urlsObj.base != null) {
                webUrl = urlsObj.base;
            } else if (urlsObj.webVault != null) {
                webUrl = urlsObj.webVault;
            }
        }
        shell.openExternal(webUrl);
    }
}
