const { default: installExtension, REACT_DEVELOPER_TOOLS } = require('electron-devtools-installer');
const { join, dirname, normalize, sep } = require('path');
const electron = require('electron');
const Module = require('module');

require('./ipc');

let reactDeveloperTools = false;
let smoothScrolling = true;
let settings = {};

try {
  settings = require(join(__dirname, '..', 'settings', 'settings.json'));
  ({ reactDeveloperTools, smoothScrolling } = settings);
} catch (err) {
  // @todo Consider handling this.
}

if (smoothScrolling === false) {
  electron.app.commandLine.appendSwitch('disable-smooth-scrolling');
}

let fakeAppSettings;
Object.defineProperty(global, 'appSettings', {
  get () {
    return fakeAppSettings;
  },
  set (value) {
    if (!value.hasOwnProperty('settings')) {
      value.settings = {};
    }
    value.settings.DANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOING = true;
    fakeAppSettings = value;
  }
});

const discordPath = join(dirname(require.main.filename), '..', 'app.asar');
const PatchedBrowserWindow = require('./browserwindow');
const electronPath = require.resolve('electron');

const electronExports = new Proxy(electron, {
  get (target, prop) {
    switch (prop) {
      case 'BrowserWindow': return PatchedBrowserWindow;
      default: return target[prop];
    }
  }
});

delete require.cache[electronPath].exports;
require.cache[electronPath].exports = electronExports;

/**
 * Register our protocol sceheme with elevated privileges.
 */
electron.protocol.registerSchemesAsPrivileged([
  {
    scheme: 'vizality',
    privileges: {
      supportFetchAPI: true,
      corsEnabled: true,
      standard: true,
      secure: true
    }
  }
]);

electron.app.once('ready', () => {
  if (reactDeveloperTools) {
    installExtension(REACT_DEVELOPER_TOOLS)
      .then(name => console.log(`Added Extension: ${name}`))
      .catch(err => console.error(`An error occurred: ${err}`));
  }
  /**
   * @todo Possibly add whitelists instead of just disabling CSP.
   */
  electron.session.defaultSession.webRequest.onHeadersReceived(({ responseHeaders }, done) => {
    Object.keys(responseHeaders)
      .filter(k => (/^content-security-policy/i).test(k) || (/^x-frame-options/i).test(k))
      .map(k => (delete responseHeaders[k]));

    done({ responseHeaders });
  });

  const urlRegex = /^(https:\/\/(?:canary|ptb)?.?discord(app)?\.com)\/vizality/;
  electron.session.defaultSession.webRequest.onBeforeRequest((details, done) => {
    if (urlRegex.test(details.url)) {
      /**
       * It should get restored to the Vizality URL later.
       */
      done({ redirectURL: `${details.url.match(urlRegex)[1]}/app` });
    } else {
      done({});
    }
  });

  /**
   * Now we can register the vizality:// file protocol to be able to conveniently
   * link to local files from within Discord.
   */
  electron.protocol.registerFileProtocol('vizality', (request, callback) => {
    /**
     * Seems to be a security thing to limit users from accessing things they shouldn't be.
     * We're splitting by ? because protocol file URLs can't seem to deal with queries.
     * https://security.stackexchange.com/a/123723
     */
    const [ url ] = normalize(request.url.replace('vizality://', '')).replace(/^(\.\.(\/|\\|$))+/, '').split('?');
    /**
     * Try to get the type of the asset.
     */
    const type = url.split(sep)[0];
    /**
     * Remove the type to determine the file path.
     */
    const path = url.replace(`${type}${sep}`, '');

    if (type === 'assets') {
      return callback({ path: join(__dirname, '..', 'assets', path) });
    } else if (type === 'plugins' || type === 'themes') {
      return callback({ path: join(__dirname, '..', 'addons', type, path) });
    } else if (type === 'builtins') {
      return callback({ path: join(__dirname, '..', 'renderer', 'src', 'builtins', path) });
    }
  });
});

const discordPackage = require(join(discordPath, 'package.json'));
electron.app.setAppPath(discordPath);
electron.app.name = discordPackage.name;

Module._load(join(discordPath, discordPackage.main), null, true);
