const {
  app,
  BrowserWindow,
  dialog,
  ipcMain,
  Menu,
  nativeImage,
  Tray
} = require('electron');
const AutoLaunch = require('auto-launch');
const Constants = require('../src/constants');
const fs = require('fs');
const helpers = require('../src/helpers');
const os = require('os');
const path = require('path');
const url = require('url');
const debug = require('electron-debug');
debug({
  devToolsMode: 'undocked',
  isEnabled: true,
  showDevTools: !!process.env.ELECTRON_START_URL,
});

require.extensions['.sh'] = function (module, filename) {
  module.exports = fs.readFileSync(filename, 'utf8');
};
const detectScript = require('./detect_linux.sh');

const AppIPC = require('../src/renderer/ipc/AppIPC');
const ConfigIPC = require('../src/renderer/ipc/ConfigIPC');
const DaemonIPC = require('../src/renderer/ipc/DaemonIPC');
const DependencyIPC = require('../src/renderer/ipc/DependencyIPC');
const DownloadIPC = require('../src/renderer/ipc/DownloadIPC');
const FilesystemIPC = require('../src/renderer/ipc/FilesystemIPC');
const MountsIPC = require('../src/renderer/ipc/MountsIPC');
const PlatformIPC = require('../src/renderer/ipc/PlatformIPC');
const ReleaseIPC = require('../src/renderer/ipc/ReleaseIPC');
const SkynetIPC = require('../src/renderer/ipc/SkynetIPC');
const StateIPC = require('../src/renderer/ipc/StateIPC');
const SystemIPC = require('../src/renderer/ipc/SystemIPC');
const UpgradeIPC = require('../src/renderer/ipc/UpgradeIPC');

const platform = os.platform();

const dimensions = {
  height: (platform === 'win32') ? 326 : (platform === 'darwin') ? 322 : 300,
  width: (platform === 'win32') ? 468 : 628,
};

let isShutdown = false;
let isQuiting = false;
let isInstalling = false;
let launchHidden = false;
let cleanupReleases = false;
let mainWindow;
let mainWindowTray;
let trayContextMenu;

const closeApplication = () => {
  if (!isShutdown) {
    isShutdown = true;
    if (mainWindowTray) {
      mainWindowTray.destroy();
    }
    app.quit();
  }
};

const configurePrimaryApp = () => {
  app.on('second-instance', () => {
    if (!isInstalling && mainWindow) {
      setWindowVisibility(true);
    }
  });

  app.on('ready', createWindow);

  app.on('window-all-closed', () => {
    closeApplication();
  });
};

const createWindow = () => {
  loadUiSettings();

  let extra = {};
  if (platform === 'linux') {
    extra = {
      icon: path.join(__dirname, '../build/', 'logo.png'),
    }
  }

  // Create the browser window.
  mainWindow = new BrowserWindow({
    height: dimensions.height,
    width: dimensions.width,
    fullscreen: false,
    resizable: false,
    show: !launchHidden,
    title: 'Repertory UI',
    ...extra,
    webPreferences: {
      nodeIntegration: true,
      webSecurity: !process.env.ELECTRON_START_URL
    }
  });
  if (platform === 'linux') {
    mainWindow.setMenuBarVisibility(false);
  } else {
    mainWindow.removeMenu();
  }
  if ((platform === 'darwin') && launchHidden) {
    app.dock.hide();
  }

  // and load the index.html of the app.
  const startUrl = process.env.ELECTRON_START_URL || url.format({
    pathname: path.join(__dirname, '../build/index.html'),
    protocol: 'file:',
    slashes: true
  });

  mainWindow.on('close', function (event) {
    if (!isQuiting) {
      event.preventDefault();
      if (mainWindow.isVisible()) {
        setWindowVisibility(false);
      }
      event.returnValue = false;
    }
  });

  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;

    MountsIPC.unmountAllDrives();
  });

  const appPath = (platform === 'win32') ? path.resolve(path.join(app.getAppPath(), '..\\..\\repertory-ui.exe')) :
    (platform === 'darwin') ? path.resolve(path.join(path.dirname(app.getAppPath()), '../MacOS/repertory-ui')) :
      process.env.APPIMAGE;

  const autoLauncher = new AutoLaunch({
    name: 'Repertory UI',
    path: appPath,
  });

  trayContextMenu = Menu.buildFromTemplate([
    {
      label: 'Visible', type: 'checkbox', click(item) {
        setWindowVisibility(item.checked);
      },
      checked: !launchHidden,
    },
    {
      type: 'separator'
    },
    {
      label: 'Auto-start', type: 'checkbox', click(item) {
        if (item.checked) {
          autoLauncher.enable();
        } else {
          autoLauncher.disable();
        }
      }
    },
    {
      label: 'Launch Hidden', type: 'checkbox', click(item) {
        launchHidden = !!item.checked;
        saveUiSettings();
      },
      checked: launchHidden,
    },
    {
      type: 'separator'
    },
    {
      label: 'Delete Old Releases', type: 'checkbox', click(item) {
        cleanupReleases = !!item.checked;
        saveUiSettings();
      },
      checked: cleanupReleases,
    },
    {
      type: 'separator'
    },
    {
      label: 'Exit and Unmount', click() {
        closeApplication();
      }
    }
  ]);

  const image = nativeImage.createFromPath(path.join(__dirname, (platform === 'darwin') ? '../build/logo_mac.png' : '../build/logo.png'));
  mainWindowTray = new Tray(image);

  autoLauncher
    .isEnabled()
    .then((enabled) => {
      trayContextMenu.items[2].checked = enabled;
      mainWindowTray.setToolTip('Repertory UI');
      mainWindowTray.setContextMenu(trayContextMenu)
    })
    .catch(() => {
      closeApplication();
    });

  mainWindow.loadURL(startUrl);
};

const getMainWindow = () => {
  return mainWindow;
};

const loadUiSettings = () => {
  const settingFile = path.join(helpers.resolvePath(Constants.DATA_LOCATIONS[platform]), 'ui.json');
  try {
    if (fs.statSync(settingFile).isFile()) {
      const settings = JSON.parse(fs.readFileSync(settingFile, 'utf8'));
      launchHidden = !!settings.launch_hidden;
      cleanupReleases = !!settings.cleanup_releases;
      PlatformIPC.setPlatformOverride(settings.platform_override);
    }
  } catch (e) {
  }
};

const saveUiSettings = () => {
  const settingFile = path.join(helpers.getDataDirectory(), 'ui.json');
  try {
    fs.writeFileSync(settingFile, JSON.stringify({
      cleanup_releases: cleanupReleases,
      launch_hidden: launchHidden,
      platform_override: PlatformIPC.getPlatformOverride(),
    }), 'utf-8');
  } catch (e) {
  }
};

const setIsInstalling = installing => {
  isInstalling = installing;
};

const setTrayImage = driveInUse => {
  let image;
  if (driveInUse) {
    image = nativeImage.createFromPath(path.join(__dirname, platform === 'darwin' ? '../build/logo_both_mac.png' : '../build/logo_both.png'));
  } else {
    image = nativeImage.createFromPath(path.join(__dirname, platform === 'darwin' ? '../build/logo_mac.png' : '../build/logo.png'));
  }
  mainWindowTray.setImage(image);
};

const setWindowVisibility = show => {
  if (show) {
    mainWindow.show();
    if (platform === 'darwin') {
      app.dock.show();
    } else if (platform === 'linux') {
      mainWindow.setSize(dimensions.width, dimensions.height);
    }

    if (mainWindow.isMinimized()) {
      mainWindow.restore();
    }
    mainWindow.focus();
  } else {
    mainWindow.hide();
    if (platform === 'darwin') {
      app.dock.hide();
    }
  }

  if (trayContextMenu && mainWindowTray) {
    trayContextMenu.items[0].checked = show;
    mainWindowTray.setContextMenu(trayContextMenu)
  }
};

const standardIPCReply = (event, channel, data, error) => {
  if (mainWindow) {
    event.sender.send(channel, {
      data: {
        ...data,
        Error: error instanceof Error ? error.toString() : error,
        Success: !error,
      }
    });
  }
};

app.on('before-quit', function () {
  isQuiting = true;
});

let instanceLock = app.requestSingleInstanceLock();
if (!instanceLock) {
  setTimeout(() => {
    if ((instanceLock = app.requestSingleInstanceLock())) {
      configurePrimaryApp();
    } else {
      closeApplication();
    }
  }, 3000);
} else {
  configurePrimaryApp();
}

const AppFunctions = {
  closeApplication,
  detectScript,
  dialog,
  getCleanupReleases: () => cleanupReleases,
  getMainWindow,
  saveUiSettings,
  setIsInstalling,
  setTrayImage,
  setWindowVisibility,
  standardIPCReply,
  unmountAllDrives: MountsIPC.unmountAllDrives,
};

AppIPC.addListeners(ipcMain, AppFunctions);
ConfigIPC.addListeners(ipcMain, AppFunctions);
DaemonIPC.addListeners(ipcMain, AppFunctions);
DependencyIPC.addListeners(ipcMain, AppFunctions);
DownloadIPC.addListeners(ipcMain, AppFunctions);
FilesystemIPC.addListeners(ipcMain, AppFunctions);
MountsIPC.addListeners(ipcMain, AppFunctions);
PlatformIPC.addListeners(ipcMain, AppFunctions);
ReleaseIPC.addListeners(ipcMain, AppFunctions);
SkynetIPC.addListeners(ipcMain, AppFunctions);
StateIPC.addListeners(ipcMain, AppFunctions);
SystemIPC.addListeners(ipcMain, AppFunctions);
UpgradeIPC.addListeners(ipcMain, AppFunctions);
