const { app, shell, Menu, Tray } = require('electron');
const { is, fixPathForAsarUnpack } = require('electron-util');
const fs = require('fs');
const path = require('path');
const ConfigManager = require('./config.js');
const Util = require('./util.js');
const Separator = { type: 'separator' };

const DEFAULT_SHORTCUTS = {
	createObject: [ 'CmdOrCtrl', 'N' ],
	undo: [ 'CmdOrCtrl', 'Z' ],
	redo: [ 'CmdOrCtrl', 'Shift', 'Z' ],
	selectAll: [ 'CmdOrCtrl', 'A' ],
	searchText: [ 'CmdOrCtrl', 'F' ],
	print: [ 'CmdOrCtrl', 'P' ],
	newWindow: [ 'CmdOrCtrl', 'Shift', 'N' ],
	zoomIn: [ 'CmdOrCtrl', '=' ],
	zoomOut: [ 'CmdOrCtrl', '-' ],
	zoomReset: [ 'CmdOrCtrl', '0' ],
	toggleFullscreen: [ 'CmdOrCtrl', 'Shift', 'F' ],
	shortcut: [ 'Ctrl', 'Space' ],
	close: [ 'CmdOrCtrl', 'Q' ],
};

class MenuManager {

	win = null;
	menu = null;
	tray = null;
	store = null;

	setWindow (win) {
		this.win = win;
	};

	initShortcuts () {
		this.shortcuts = this.store.get('shortcuts') || {};
	};

	getAccelerator (id) {
		let keys = this.shortcuts[id];

		if (undefined === keys) {
			return (DEFAULT_SHORTCUTS[id] || []).join('+');
		};

		keys = keys || [];

		const ret = [];
		for (const key of keys) {
			if ((key == 'ctrl') || (key == 'cmd')) {
				ret.push('CmdOrCtrl');
			} else
			if (key == 'shift') {
				ret.push('Shift');
			} else
			if (key == 'alt') {
				ret.push('Alt');
			} else 
			if (key == '+') {
				ret.push('Plus');
			} else {
				ret.push(key.toUpperCase());
			};
		};
		return ret.join('+');
	};

	initMenu () {
		this.initShortcuts();

		const { config } = ConfigManager;
		const Api = require('./api.js');
		const WindowManager = require('./window.js');
		const UpdateManager = require('./update.js');
		const isAllowedUpdate = UpdateManager.isAllowed();

		config.debug = config.debug || {};
		config.flagsMw = config.flagsMw || {};

		const menuParam = [
			{
				label: 'Anytype',
				submenu: [
					{ label: Util.translate('electronMenuAbout'), click: () => Util.send(this.win, 'popup', 'about', {}, true) },

					Separator,

					{ role: 'hide', label: Util.translate('electronMenuHide') },
					{ role: 'hideothers', label: Util.translate('electronMenuHideOthers') },
					{ role: 'unhide', label: Util.translate('electronMenuUnhide') },

					{ type: 'separator', visible: isAllowedUpdate },
					{ label: Util.translate('electronMenuCheckUpdates'), click: () => Api.updateCheck(this.win), visible: isAllowedUpdate },

					Separator,

					{ label: Util.translate('commonSettings'), submenu: this.menuSettings() },

					Separator,

					{ label: Util.translate('electronMenuQuit'), accelerator: this.getAccelerator('close'), click: () => Api.exit(this.win, false) },
				]
			},
			{
				role: 'fileMenu', label: Util.translate('electronMenuFile'),
				submenu: [
					{ label: Util.translate('commonNewObject'), accelerator: this.getAccelerator('createObject'), click: () => Util.send(this.win, 'commandGlobal', 'createObject') },
					{ label: Util.translate('commonNewSpace'), click: () => Util.send(this.win, 'commandGlobal', 'createSpace') },

					Separator,

					{ label: Util.translate('electronMenuImport'), click: () => this.openSettings('importIndex') },
					{ label: Util.translate('electronMenuExport'), click: () => this.openSettings('exportIndex') },
					{ label: Util.translate('electronMenuSaveAs'), click: () => Util.send(this.win, 'commandGlobal', 'save') },

					Separator,

					{ 
						label: Util.translate('electronMenuOpen'), submenu: [
							{ label: Util.translate('electronMenuWorkDirectory'), click: () => shell.openPath(Util.userPath()) },
							{ label: Util.translate('electronMenuDataDirectory'), click: () => shell.openPath(Util.dataPath()) },
							{ label: Util.translate('electronMenuConfigDirectory'), click: () => shell.openPath(Util.defaultUserDataPath()) },
							{ label: Util.translate('electronMenuLogsDirectory'), click: () => shell.openPath(Util.logPath()) },
							{ 
								label: Util.translate('electronMenuCustomCss'),
								click: () => {
									const fp = path.join(Util.userPath(), 'custom.css');

									if (!fs.existsSync(fp)) {
										fs.writeFileSync(fp, '');
									};

									shell.openPath(fp);
								},
							},
						] 
					},

					Separator,

					{ 
						label: Util.translate('electronMenuApplyCustomCss'), type: 'checkbox', checked: !config.disableCss,
						click: () => {
							config.disableCss = !config.disableCss;
							Api.setConfig(this.win, { disableCss: config.disableCss }, () => {
								WindowManager.reloadAll();
							});
						},
					},

					Separator,

					{ role: 'close', label: Util.translate('electronMenuClose') },
				]
			},
			{
				label: Util.translate('electronMenuEdit'),
				submenu: [
					{
						label: Util.translate('electronMenuUndo'), accelerator: this.getAccelerator('undo'),
						click: () => { 
							if (this.win) {
								this.win.webContents.undo();
								Util.send(this.win, 'commandGlobal', 'undo');
							};
						}
					},
					{
						label: Util.translate('electronMenuRedo'), accelerator: this.getAccelerator('redo'),
						click: () => {
							if (this.win) {
								this.win.webContents.redo();
								Util.send(this.win, 'commandGlobal', 'redo');
							};
						}
					},

					Separator,

					{ label: Util.translate('electronMenuCopy'), role: 'copy' },
					{ label: Util.translate('electronMenuCut'), role: 'cut' },
					{ label: Util.translate('electronMenuPaste'), role: 'paste' },
					{ 
						label: Util.translate('electronMenuPastePlain'), accelerator: 'CmdOrCtrl+Shift+V',
						click: () => {
							if (is.macos) {
								Util.send(this.win, 'commandEditor', 'pastePlain');
							};
						},
					},

					Separator,

					{
						label: Util.translate('electronMenuSelectAll'), accelerator: this.getAccelerator('selectAll'),
						click: () => {
							if (this.win) {
								this.win.webContents.selectAll();
								Util.send(this.win, 'commandEditor', 'selectAll');
							};
						}
					},
					{ label: Util.translate('electronMenuSearch'), accelerator: this.getAccelerator('searchText'), click: () => Util.send(this.win, 'commandGlobal', 'search') },

					Separator,

					{ label: Util.translate('electronMenuPrint'), accelerator: this.getAccelerator('print'), click: () => Util.send(this.win, 'commandGlobal', 'print') },
				]
			},
			{
				role: 'windowMenu', label: Util.translate('electronMenuWindow'),
				submenu: [
					{ label: Util.translate('electronMenuNewWindow'), accelerator: this.getAccelerator('newWindow'), click: () => WindowManager.createMain({ isChild: true }) },

					Separator,

					{ role: 'minimize', label: Util.translate('electronMenuMinimise') },
					{ label: Util.translate('electronMenuZoomIn'), accelerator: this.getAccelerator('zoomIn'), click: () => Api.setZoom(this.win, this.win.webContents.getZoomLevel() + 1) },
					{ label: Util.translate('electronMenuZoomOut'), accelerator: this.getAccelerator('zoomOut'), click: () => Api.setZoom(this.win, this.win.webContents.getZoomLevel() - 1) },
					{ label: Util.translate('electronMenuZoomDefault'), accelerator: this.getAccelerator('zoomReset'), click: () => Api.setZoom(this.win, 0) },
					{
						label: Util.translate('electronMenuFullscreen'), accelerator: this.getAccelerator('toggleFullscreen'), type: 'checkbox', checked: this.win.isFullScreen(),
						click: () => this.win.setFullScreen(!this.win.isFullScreen())
					},
					{ label: Util.translate('electronMenuReload'), accelerator: 'CmdOrCtrl+R', click: () => this.win.reload() }
				]
			},
			{
				label: Util.translate('electronMenuHelp'),
				submenu: [
					{
						label: `${Util.translate('electronMenuReleaseNotes')} (${app.getVersion()})`,
						click: () => Util.send(this.win, 'popup', 'help', { data: { document: 'whatsNew' } })
					},
					{
						label: Util.translate('electronMenuShortcuts'), accelerator: this.getAccelerator('shortcut'),
						click: () => Util.send(this.win, 'commandGlobal', 'shortcut')
					},

					Separator,

					{ label: Util.translate('electronMenuGallery'), click: () => Util.send(this.win, 'commandGlobal', 'gallery') },
					{ label: Util.translate('electronMenuCommunity'), click: () => Util.send(this.win, 'commandGlobal', 'community') },
					{ label: Util.translate('electronMenuTutorial'), click: () => Util.send(this.win, 'commandGlobal', 'tutorial') },
					{ label: Util.translate('electronMenuContact'), click: () => Util.send(this.win, 'commandGlobal', 'contact') },
					{ label: Util.translate('electronMenuTech'), click: () => Util.send(this.win, 'commandGlobal', 'tech') },

					Separator,

					{ label: Util.translate('electronMenuTerms'), click: () => Util.send(this.win, 'commandGlobal', 'terms') },
					{ label: Util.translate('electronMenuPrivacy'), click: () => Util.send(this.win, 'commandGlobal', 'privacy') },

				]
			},
		];

		const flags = { 
			ui: Util.translate('electronMenuFlagInterface'), 
			hiddenObject: Util.translate('electronMenuFlagHidden'), 
			analytics: Util.translate('electronMenuFlagAnalytics'),
		};

		const flagsMw = {
			request: Util.translate('electronMenuFlagMwRequest'),
			subscribe: Util.translate('electronMenuFlagMwSubscribe'),
			event: Util.translate('electronMenuFlagMwEvent'),
			sync: Util.translate('electronMenuFlagMwSync'),
			file: Util.translate('electronMenuFlagMwFile'),
			time: Util.translate('electronMenuFlagMwTime'),
			json: Util.translate('electronMenuFlagMwJson'),
		};

		const flagMenu = [];
		const flagMwMenu = [];

		for (const i in flags) {
			flagMenu.push({
				label: flags[i], type: 'checkbox', checked: config.debug[i],
				click: () => {
					config.debug[i] = !config.debug[i];
					Api.setConfig(this.win, { debug: config.debug });
					
					if ([ 'hiddenObject' ].includes(i)) {
						this.win.reload();
					};
				}
			});
		};

		for (const i in flagsMw) {
			flagMwMenu.push({
				label: flagsMw[i], type: 'checkbox', checked: config.flagsMw[i],
				click: () => {
					config.flagsMw[i] = !config.flagsMw[i];
					Api.setConfig(this.win, config);
				}
			});
		};

		flagMenu.push(Separator);
		flagMenu.push({
			label: Util.translate('electronMenuFlagMw'),
			submenu: flagMwMenu,
		});

		menuParam.push({
			label: Util.translate('electronMenuDebug'),
			submenu: [
				{ label: Util.translate('electronMenuFlags'), submenu: flagMenu },

				Separator,

				{ label: Util.translate('electronMenuDebugSpace'), click: () => Util.send(this.win, 'commandGlobal', 'debugSpace') },
				{ label: Util.translate('electronMenuDebugObject'), click: (item, window, event) => {
					const unanonymized = event && event.altKey;
					
					if (unanonymized) {
						const { dialog } = require('electron');
						const result = dialog.showMessageBoxSync(this.win, {
							type: 'warning',
							buttons: [ 'Cancel', 'OK' ],
							defaultId: 0,
							title: 'Debug without anonymization',
							message: 'You are exporting this object and all its history of changes without anonymization.',
							detail: 'This file will contain sensitive data. Only proceed if you understand the privacy implications.'
						});
						
						if (!result) {
							return; // User clicked Cancel
						};
					};
					
					Util.send(this.win, 'commandGlobal', 'debugTree', { unanonymized });
				}},
				{ label: Util.translate('electronMenuDebugProcess'), click: () => Util.send(this.win, 'commandGlobal', 'debugProcess') },
				{ label: Util.translate('electronMenuDebugStat'), click: () => Util.send(this.win, 'commandGlobal', 'debugStat') },
				{ label: Util.translate('electronMenuDebugReconcile'), click: () => Util.send(this.win, 'commandGlobal', 'debugReconcile') },
				{ label: Util.translate('electronMenuDebugNet'), click: () => Util.send(this.win, 'commandGlobal', 'debugNet') },
				{ label: Util.translate('electronMenuDebugLog'), click: () => Util.send(this.win, 'commandGlobal', 'debugLog') },
				{ label: Util.translate('electronMenuDebugProfiler'), click: () => Util.send(this.win, 'commandGlobal', 'debugProfiler') },

				Separator,

				{ label: Util.translate('electronMenuDevTools'), accelerator: 'Alt+CmdOrCtrl+I', click: () => this.win.toggleDevTools() },
			]
		});

		const channels = ConfigManager.getChannels().map(it => {
			it.click = () => { 
				if (!UpdateManager.isUpdating) {
					Util.send(this.win, 'commandGlobal', 'releaseChannel', it.id);
				};
			};
			return it;
		}); 

		if (channels.length > 1) {
			menuParam.push({ label: Util.translate('electronMenuVersion'), submenu: channels });
		};

		const menuSudo = { 
			label: 'Sudo',
			submenu: [
				Separator,

				{
					label: 'Experimental features', type: 'checkbox', checked: config.experimental,
					click: () => { 
						Api.setConfig(this.win, { experimental: !config.experimental });
						this.win.reload();
					}
				},

				Separator,

				{
					label: 'Test payments', type: 'checkbox', checked: config.testPayment,
					click: () => {
						Api.setConfig(this.win, { testPayment: !config.testPayment });
						this.win.reload();
					}
				},

				Separator,

				{ label: 'Export templates', click: () => Util.send(this.win, 'commandGlobal', 'exportTemplates') },
				{ label: 'Export objects', click: () => Util.send(this.win, 'commandGlobal', 'exportObjects') },
				{ label: 'Export localstore', click: () => Util.send(this.win, 'commandGlobal', 'exportLocalstore') },

				Separator,

				{ label: 'Reset onboarding', click: () => Util.send(this.win, 'commandGlobal', 'resetOnboarding') },
				{ label: 'Read all messages', click: () => Util.send(this.win, 'commandGlobal', 'readAllMessages') },

				Separator,

				{ label: 'Relaunch', click: () => Api.exit(this.win, true) },
			]
		};

		if (config.sudo) {
			menuParam.push(menuSudo);
		};

		this.menu = Menu.buildFromTemplate(menuParam);
		Menu.setApplicationMenu(this.menu);
	};

	initTray () {
		const { config } = ConfigManager;
		const WindowManager = require('./window.js');
		const Api = require('./api.js');
		const UpdateManager = require('./update.js');
		const isAllowedUpdate = UpdateManager.isAllowed();

		this.destroy();

		if (config.hideTray) {
			return;
		};

		const icon = this.getTrayIcon();

		this.tray = new Tray (icon);
		this.tray.setToolTip('Anytype');
		this.tray.setContextMenu(Menu.buildFromTemplate([
			{ label: Util.translate('electronMenuOpenApp'), click: () => this.winShow() },

			Separator,

			{ label: Util.translate('electronMenuNewWindow'), accelerator: this.getAccelerator('newWindow'), click: () => WindowManager.createMain({ isChild: true }) },

			Separator,

			{ label: Util.translate('electronMenuCheckUpdates'), click: () => { this.winShow(); Api.updateCheck(this.win); }, visible: isAllowedUpdate },
			{ label: Util.translate('commonSettings'), submenu: this.menuSettings() },
			
			Separator,

			{ label: Util.translate('electronMenuQuit'), click: () => { this.winHide(); Api.exit(this.win, '', false); } },
		]));

		// Force on top and focus because in some case Electron fail with this.winShow()
		this.tray.on('double-click', () => {
			if (this.win && !this.win.isDestroyed()) {
				this.win.setAlwaysOnTop(true);
				this.winShow();
				this.win.setAlwaysOnTop(false);
			};
		});
	};

	winShow () {
		if (this.win && !this.win.isDestroyed()) {
			this.win.show();
		};
	};

	winHide () {
		if (this.win && !this.win.isDestroyed()) {
			this.win.hide();
		};
	};

	menuSettings () {
		const { config } = ConfigManager;
		const Api = require('./api.js');
		const Locale = require('../../dist/lib/json/locale.json');
		const lang = Util.getLang();
		const langMenu = [];

		for (const key of Util.enabledLangs()) {
			langMenu.push({
				label: Locale[key], type: 'checkbox', checked: key == lang,
				click: () => Util.send(this.win, 'commandGlobal', 'interfaceLang', key)
			});
		};

		return [
			{ 
				label: Util.translate('electronMenuAccountSettings'), click: () => { 
					this.winShow(); 
					this.openSettings(''); 
				}
			},
			{ 
				label: Util.translate('electronMenuSpaceSettings'), click: () => { 
					this.winShow(); 
					this.openSettings('spaceIndex');
				}
			},

			Separator,

			{ 
				label: Util.translate('electronMenuImport'), click: () => { 
					this.winShow(); 
					this.openSettings('importIndex');
				} 
			},
			{ 
				label: Util.translate('electronMenuExport'), click: () => { 
					this.winShow(); 
					this.openSettings('exportIndex');
				} 
			},

			{ label: Util.translate('electronMenuLanguage'), submenu: langMenu },
			
			Separator,

			{ 
				label: Util.translate('electronMenuShowTray'), type: 'checkbox', checked: !config.hideTray, click: () => { 
					Api.setConfig(this.win, { hideTray: !config.hideTray });
					this.initTray();
				} 
			},

			(is.windows || is.linux) ? {
				label: Util.translate('electronMenuShowMenu'), type: 'checkbox', checked: config.showMenuBar, click: () => {
					const { config } = ConfigManager;

					Api.setMenuBarVisibility(this.win, !config.showMenuBar);
					this.initTray();
				}
			} : null,

			Separator,

			{ 
				label: Util.translate('commonNewObject'), accelerator:this.getAccelerator('createObject'), click: () => { 
					this.winShow();
					Util.send(this.win, 'commandGlobal', 'createObject'); 
				} 
			},
		].filter(it => it);
	};

	openSettings (page) {
		const Api = require('./api.js');

		if (Api.isPinChecked) {
			Util.send(this.win, 'route', '/main/settings/' + page);
		};
	};

	updateTrayIcon () {
		if (this.tray && this.tray.setImage) {
			const icon = this.getTrayIcon();
			if (icon) {
				this.tray.setImage(icon);
			};
		};
	};

	getTrayIcon () {
		let icon = '';

		if (is.windows) {
			icon = path.join('icons', '32x32.png');
		} else 
		if (is.linux) {
			const env = process.env.ORIGINAL_XDG_CURRENT_DESKTOP;
			const panelAlwaysDark = env.includes('GNOME') || (env == 'Unity'); // for GNOME shell env, including ubuntu -- the panel is always dark

            if (panelAlwaysDark) {
                icon = 'iconTrayWhite.png';
            } else 
			if (Util.getTheme() == 'dark') {
                icon = 'iconTrayWhite.png';
            } else {
                icon = 'iconTrayBlack.png';
            };
		} else 
		if (is.macos) {
			icon = `iconTrayTemplate.png`;
		};

		return icon ? fixPathForAsarUnpack(path.join(Util.imagePath(), icon)) : '';
	};

	destroy () {
		if (this.tray && !this.tray.isDestroyed()) {
			this.tray.destroy();
			this.tray = null;
		};
	};

};

module.exports = new MenuManager();
