<template>
    <div style="display: flex;flex-direction:column;height:100%" :class="getThemeClass()" @auxclick.prevent>
        <div v-html="styling"></div>
        <div style="display:flex;align-items:stretch;border-bottom-width:1px" class="border-bottom" id="window-tabs">
            <h4 style="padding:2px 0">F-Chat</h4>
            <div class="btn" :class="'btn-' + (hasUpdate ? 'warning' : 'light')" @click="openMenu" id="settings">
                <i class="fa fa-cog"></i>
            </div>
            <ul class="nav nav-tabs" style="border-bottom:0;margin-bottom:-1px;margin-top:1px" ref="tabs">
                <li v-for="(tab,index) in tabs" :key="'tab-' + index" class="nav-item" @click.middle="remove(tab)">
                    <a href="#" @click.prevent="show(tab)" class="nav-link tab"
                        :class="{active: tab === activeTab, hasNew: tab.hasNew && tab !== activeTab}">
                        <img v-if="tab.user" :src="'https://static.f-list.net/images/avatar/' + tab.user.toLowerCase() + '.png'"/>
                        <span class="d-sm-inline d-none">{{tab.user || l('window.newTab')}}</span>
                        <a href="#" :aria-label="l('action.close')" style="margin-left:10px;padding:0;color:inherit;text-decoration:none"
                            @click.stop="remove(tab)"><i class="fa fa-times"></i>
                        </a>
                    </a>
                </li>
                <li v-show="(canOpenTab && hasCompletedUpgrades)" class="addTab nav-item" id="addTab">
                    <a href="#" @click.prevent="addTab()" class="nav-link"><i class="fa fa-plus"></i></a>
                </li>
            </ul>
            <div style="flex:1;display:flex;justify-content:flex-end;-webkit-app-region:drag" class="btn-group"
                id="windowButtons">
                <i class="far fa-window-minimize btn btn-light" @click.stop="minimize()"></i>
                <i class="far btn btn-light" :class="'fa-window-' + (isMaximized ? 'restore' : 'maximize')" @click="maximize()"></i>
                <span class="btn btn-light" @click.stop="close()">
                    <i class="fa fa-times fa-lg"></i>
                </span>
            </div>
        </div>
    </div>
</template>

<script lang="ts">
    import Sortable from 'sortablejs';
    import _ from 'lodash';

    import {Component, Hook} from '@f-list/vue-ts';
    import * as electron from 'electron';
    import * as remote from '@electron/remote';

    import * as fs from 'fs';
    import * as path from 'path';
    import * as url from 'url';
    import Vue from 'vue';
    import l from '../chat/localize';
    import {GeneralSettings} from './common';
    import { getSafeLanguages, updateSupportedLanguages } from './language';
    import log from 'electron-log';

    const browserWindow = remote.getCurrentWindow();

    // void browserWindow.webContents.setVisualZoomLevelLimits(1, 5);

    function getWindowBounds(): Electron.Rectangle {
        const bounds = browserWindow.getContentBounds();
        const height = document.body.offsetHeight;
        return {x: 0, y: height, width: bounds.width, height: bounds.height - height};
    }

    function destroyTab(tab: Tab): void {
        if(tab.user !== undefined) electron.ipcRenderer.send('disconnect', tab.user);
        tab.tray.destroy();

        tab.view.webContents.stop();
        tab.view.webContents.stopPainting();

        try {
          if ((tab.view.webContents as any).destroy) {
            (tab.view.webContents as any).destroy();
          }
        } catch (err) {
          console.log(err);
        }

        try {
          if ((tab.view.webContents as any).close) {
            (tab.view.webContents as any).close();
          }
        } catch (err) {
          console.log(err);
        }

        try {
          if ((tab.view as any).destroy) {
            (tab.view as any).destroy();
          }
        } catch (err) {
          console.log(err);
        }

        try {
          if ((tab.view as any).close) {
            (tab.view as any).close();
          }
        } catch (err) {
          console.log(err);
        }

        // tab.view.destroy();
        electron.ipcRenderer.send('tab-closed');
    }

    interface Tab {
        user: string | undefined,
        view: Electron.BrowserView
        hasNew: boolean
        tray: Electron.Tray
    }

    // console.log(require('./build/tray.png').default);

    //tslint:disable-next-line:no-require-imports no-unsafe-any
    const trayIcon = path.join(__dirname, <string>require('./build/tray.png').default);
    //path.join(__dirname, <string>require('./build/tray.png').default);

    @Component
    export default class Window extends Vue {
        settings!: GeneralSettings;
        tabs: Tab[] = [];
        activeTab: Tab | undefined;
        tabMap: {[key: number]: Tab} = {};
        isMaximized = false;
        canOpenTab = true;
        l = l;
        hasUpdate = false;
        platform = process.platform;
        lockTab = false;
        hasCompletedUpgrades = false;


        @Hook('mounted')
        async mounted(): Promise<void> {
            log.debug('init.window.mounting');
            // top bar devtools
            // browserWindow.webContents.openDevTools({ mode: 'detach' });

            if (remote.process.argv.includes('--devtools')) {
              browserWindow.webContents.openDevTools({ mode: 'detach' });
            }

            updateSupportedLanguages(browserWindow.webContents.session.availableSpellCheckerLanguages);

            log.debug('init.window.languages.supported');
            // console.log('MOUNT DICTIONARIES', getSafeLanguages(this.settings.spellcheckLang), this.settings.spellcheckLang);

            browserWindow.webContents.session.setSpellCheckerLanguages(getSafeLanguages(this.settings.spellcheckLang));

            log.debug('init.window.languages');

            electron.ipcRenderer.on('settings', (_e: Event, settings: GeneralSettings) => {
                log.debug('settings.update.window');

                this.settings = settings;

                log.transports.file.level = settings.risingSystemLogLevel;
                log.transports.console.level = settings.risingSystemLogLevel;
            });

            electron.ipcRenderer.on('rising-upgrade-complete', () => {
              // console.log('RISING COMPLETE RECV');
              this.hasCompletedUpgrades = true;
            });
            electron.ipcRenderer.on('allow-new-tabs', (_e: Event, allow: boolean) => this.canOpenTab = allow);
            electron.ipcRenderer.on('open-tab', () => this.addTab());
            electron.ipcRenderer.on('update-available', (_e: Event, available: boolean) => this.hasUpdate = available);
            electron.ipcRenderer.on('fix-logs', () => this.activeTab!.view.webContents.send('fix-logs'));
            electron.ipcRenderer.on('quit', () => this.destroyAllTabs());
            electron.ipcRenderer.on('reopen-profile', () => this.activeTab!.view.webContents.send('reopen-profile'));
            electron.ipcRenderer.on('update-dictionaries', (_e: Event, langs: string[]) => {
                // console.log('UPDATE DICTIONARIES', langs);

                browserWindow.webContents.session.setSpellCheckerLanguages(langs);

                for (const t of this.tabs) {
                    t.view.webContents.session.setSpellCheckerLanguages(langs);
                }
            });

            // electron.ipcRenderer.on('update-zoom', (_e: Event, zoomLevel: number) => {
            //   // log.info('WINDOWVUE ZOOM UPDATE', zoomLevel);
            //   // browserWindow.webContents.setZoomLevel(zoomLevel);
            // });

            electron.ipcRenderer.on('connect', (_e: Event, id: number, name: string) => {
                const tab = this.tabMap[id];
                tab.user = name;
                tab.tray.setToolTip(`${l('title')} - ${tab.user}`);
                const menu = this.createTrayMenu(tab);
                menu.unshift({label: tab.user, enabled: false}, {type: 'separator'});
                tab.tray.setContextMenu(remote.Menu.buildFromTemplate(menu));
            });
            electron.ipcRenderer.on('disconnect', (_e: Event, id: number) => {
                const tab = this.tabMap[id];
                if(tab.hasNew) {
                    tab.hasNew = false;
                    electron.ipcRenderer.send('has-new', this.tabs.reduce((cur, t) => cur || t.hasNew, false));
                }
                tab.user = undefined;
                tab.tray.setToolTip(l('title'));
                tab.tray.setContextMenu(remote.Menu.buildFromTemplate(this.createTrayMenu(tab)));
            });
            electron.ipcRenderer.on('has-new', (_e: Event, id: number, hasNew: boolean) => {
                const tab = this.tabMap[id];
                tab.hasNew = hasNew;
                electron.ipcRenderer.send('has-new', this.tabs.reduce((cur, t) => cur || t.hasNew, false));
            });
            browserWindow.on('maximize', () => this.isMaximized = true);
            browserWindow.on('unmaximize', () => this.isMaximized = false);
            electron.ipcRenderer.on('switch-tab', (_e: Event) => {
                const index = this.tabs.indexOf(this.activeTab!);
                this.show(this.tabs[index + 1 === this.tabs.length ? 0 : index + 1]);
            });
            electron.ipcRenderer.on('previous-tab', (_e: Event) => {
                const index = this.tabs.indexOf(this.activeTab!);
                this.show(this.tabs[index - 1 < 0 ? this.tabs.length - 1 : index - 1]);
            });
            electron.ipcRenderer.on('show-tab', (_e: Event, id: number) => {
                this.show(this.tabMap[id]);
            });
            document.addEventListener('click', () => this.activeTab!.view.webContents.focus());
            window.addEventListener('focus', () => this.activeTab!.view.webContents.focus());

            log.debug('init.window.listeners');

            await this.addTab();

            log.debug('init.window.tab');


            // console.log('SORTABLE', Sortable);

            Sortable.create(<HTMLElement>this.$refs['tabs'], {
                animation: 50,
                onEnd: (e) => {
                    // log.debug('ONEND', e);
                    if(e.oldIndex === e.newIndex) return;

                    // log.debug('PRE', this.tabs);
                    //
                    // const tab = this.tabs.splice(e.oldIndex!, 1)[0];
                    // this.tabs.splice(e.newIndex!, 0, tab);
                    //
                    // log.debug('POST', this.tabs);
                },
                onMove: (e: {related: HTMLElement}) => e.related.id !== 'addTab',
                filter: '.addTab'
            });

            window.onbeforeunload = () => {
                const isConnected = this.tabs.reduce((cur, tab) => cur || tab.user !== undefined, false);
                if(process.env.NODE_ENV !== 'production' || !isConnected) {
                    this.destroyAllTabs();
                    return;
                }
                if(!this.settings.closeToTray)
                    return setImmediate(() => {
                        if(confirm(l('chat.confirmLeave'))) {
                            this.destroyAllTabs();
                            browserWindow.close();
                        }
                    });
                browserWindow.hide();
                return false;
            };
            this.isMaximized = browserWindow.isMaximized();

            log.debug('init.window.mounted');
        }

        destroyAllTabs(): void {
            browserWindow.setBrowserView(null!); //tslint:disable-line:no-null-keyword
            this.tabs.forEach(destroyTab);
            this.tabs = [];
        }

        get styling(): string {
            try {
                return `<style>${fs.readFileSync(path.join(__dirname, `themes/${this.settings.theme}.css`), 'utf8').toString()}</style>`;
            } catch(e) {
                if((<Error & {code: string}>e).code === 'ENOENT' && this.settings.theme !== 'default') {
                    this.settings.theme = 'default';
                    return this.styling;
                }
                throw e;
            }
        }

        trayClicked(tab: Tab): void {
            browserWindow.show();
            if(this.isMaximized) browserWindow.maximize();
            this.show(tab);
        }

        createTrayMenu(tab: Tab): Electron.MenuItemConstructorOptions[] {
            return [
                {label: l('action.open'), click: () => this.trayClicked(tab)},
                {label: l('action.quit'), click: () => this.remove(tab, false)}
            ];
        }

        async addTab(): Promise<void> {
            if(this.lockTab) return;
            const tray = new remote.Tray(trayIcon);
            tray.setToolTip(l('title'));
            tray.on('click', (_e) => this.trayClicked(tab));

            const view = new remote.BrowserView(
              {
                webPreferences: {
                  webviewTag: true,
                  nodeIntegration: true,
                  nodeIntegrationInWorker: true,
                  spellcheck: true,
                  contextIsolation: false,
                  partition: 'persist:fchat',
                }
              }
            );

            const remoteMain = require("@electron/remote/main");
            remoteMain.enable(view.webContents);

            // tab devtools
            // view.webContents.openDevTools();

            if (remote.process.argv.includes('--devtools')) {
              view.webContents.openDevTools({ mode: 'detach' });
            }

            // console.log('ADD TAB LANGUAGES', getSafeLanguages(this.settings.spellcheckLang), this.settings.spellcheckLang);
            view.webContents.session.setSpellCheckerLanguages(getSafeLanguages(this.settings.spellcheckLang));

            view.setAutoResize({width: true, height: true});
            electron.ipcRenderer.send('tab-added', view.webContents.id);
            const tab = {active: false, view, user: undefined, hasNew: false, tray};
            tray.setContextMenu(remote.Menu.buildFromTemplate(this.createTrayMenu(tab)));
            this.tabs.push(tab);
            this.tabMap[view.webContents.id] = tab;
            this.show(tab);
            this.lockTab = true;

            log.debug('init.window.tab.load');

            const indexUrl = url.format({
                pathname: path.join(__dirname, 'index.html'),
                protocol: 'file:',
                slashes: true,
                query: {settings: JSON.stringify(this.settings), hasCompletedUpgrades: JSON.stringify(this.hasCompletedUpgrades)}
            });

            await view.webContents.loadURL(indexUrl);

            log.debug('init.window.tab.load.complete', indexUrl);

            tab.view.setBounds(getWindowBounds());
            this.lockTab = false;
        }

        show(tab: Tab): void {
            if(this.lockTab) return;
            this.activeTab = tab;
            browserWindow.setBrowserView(tab.view);
            tab.view.setBounds(getWindowBounds());
            tab.view.webContents.focus();

            // tab.view.webContents.send('active-tab', { webContentsId: tab.view.webContents.id });
            _.each(this.tabs, (t) => t.view.webContents.send(t === tab ? 'active-tab' : 'inactive-tab'));

            // electron.ipcRenderer.send('active-tab', { webContentsId: tab.view.webContents.id });
        }

        remove(tab: Tab, shouldConfirm: boolean = true): void {
            if(this.lockTab || shouldConfirm && tab.user !== undefined && !confirm(l('chat.confirmLeave'))) return;
            this.tabs.splice(this.tabs.indexOf(tab), 1);
            electron.ipcRenderer.send('has-new', this.tabs.reduce((cur, t) => cur || t.hasNew, false));
            delete this.tabMap[tab.view.webContents.id];
            if(this.tabs.length === 0) {
                browserWindow.setBrowserView(null!); //tslint:disable-line:no-null-keyword
                if(process.env.NODE_ENV === 'production') browserWindow.close();
            } else if(this.activeTab === tab) this.show(this.tabs[0]);
            destroyTab(tab);
        }

        minimize(): void {
            browserWindow.minimize();
        }

        maximize(): void {
            if(browserWindow.isMaximized()) browserWindow.unmaximize();
            else browserWindow.maximize();
        }

        close(): void {
            browserWindow.close();
        }

        openMenu(): void {
            remote.Menu.getApplicationMenu()!.popup({});
        }

        getThemeClass() {
          // console.log('getThemeClassWindow', this.settings?.risingDisableWindowsHighContrast);

          try {
            // Hack!
            if (process.platform === 'win32') {
              if (this.settings?.risingDisableWindowsHighContrast) {
                document.querySelector('html')?.classList.add('disableWindowsHighContrast');
              } else {
                document.querySelector('html')?.classList.remove('disableWindowsHighContrast');
              }
            }

            return {
              ['platform-' + this.platform]: true,
              disableWindowsHighContrast: this.settings?.risingDisableWindowsHighContrast || false
            };
          } catch (err) {
            return {
              ['platform-' + this.platform]: true
            };
          }
        }
    }
</script>

<style lang="scss">
    #window-tabs {
        user-select: none;
        .btn {
            border: 0;
            border-radius: 0;
            padding: 0 18px;
            display: flex;
            align-items: center;
            line-height: 1;
            -webkit-app-region: no-drag;
            flex-grow: 0;
        }

        .btn-default {
            background: transparent;
        }

        li {
            height: 100%;
            a {
                display: flex;
                padding: 2px 10px;
                height: 100%;
                align-items: center;
                &:first-child {
                    border-top-left-radius: 0;
                }
            }

            img {
                height: 28px;
                margin: -5px 3px -5px -5px;
            }
        }

        h4 {
            margin: 0 10px;
            user-select: none;
            cursor: default;
            align-self: center;
            -webkit-app-region: drag;
        }

        .fa {
            line-height: inherit;
        }
    }

    #windowButtons .btn {
        border-top: 0;
        font-size: 14px;
    }

    .platform-darwin {
        #windowButtons .btn, #settings {
            display: none;
        }

        #window-tabs {
            h4 {
                margin: 0 15px 0 77px;
            }

            .btn, li a {
                padding-top: 6px;
                padding-bottom: 6px;
            }
        }
    }

    .disableWindowsHighContrast, .disableWindowsHighContrast * {
      forced-color-adjust: none;
    }
</style>