import { openModal, closeModal } from '@vizality/modal';
import { getModuleByDisplayName, getModule, instance } from '@vizality/webpack';
import { SettingsContextMenu } from '@vizality/components/vizality';
import { Content, Layout } from '@vizality/components/dashboard';
import { toPlural, toTitleCase } from '@vizality/util/string';
import { Confirm, ContextMenu, Modal } from '@vizality/components';
import { joinClassNames } from '@vizality/util/dom';
import { patch, unpatch } from '@vizality/patcher';
import { Builtin } from '@vizality/entities';
import { Messages } from '@vizality/i18n';
import React from 'react';

import SettingsPage from './components/Settings';

/**
 * Contributed by DoggyBootsy, originally written by Strencher.
 */
{
  const modules = Object.values(instance.m).filter(e => e.toString().search(/openContextMenuLazy[)(]/) > -1);
  const regex = [
    {
      regex: /return Promise\.all\(\[(.*?)\]\)\.then\(\D+(.+?)\)\)/,
      parse (match) {
        return {
          imports: matchAll(/\(([\de]+)\)/g, match[0]).map(e => Number(e)),
          main: match[1]
        };
      }
    },
    {
      regex: /return Promise\.resolve\(\)\.then\(\D+(.+?)\)/,
      parse (match) {
        return {
          imports: [],
          main: match[0]
        };
      }
    },
    {
      regex: /return [rn]\.e\((\d+)\)\.then\(\D+(\d+)\)\)/,
      parse (match) {
        return {
          imports: [ match[0] ],
          main: match[0]
        };
      }
    }
  ];

  function matchAll (regex, input, parent = false) {
    const output = [];
    let matches,
      lastIndex = 0;
    while (matches = regex.exec(input.slice(lastIndex))) {
      if (!regex.global) lastIndex += matches.index + matches[0].length;
      if (parent) output.push(matches);
      else {
        const [ , ...match ] = matches;
        output.push(match);
      }
    }
    return output;
  }

  const found = [];

  for (let i = 0; i < modules.length; i++) {
    const str = modules[i].toString();

    for (let i2 = 0; i2 < regex.length; i2++) {
      const { regex: reg, parse } = regex[i2];
      if (!reg.test(str)) continue;
      const result = matchAll(reg, str).map(res => ({ ...parse(res), module: modules[i], reg }));
      found.push(...result);

      break;
    }
  }

  Promise.all(found.map(item => {
    try {
      const imports = item.imports.map(i => instance.e(i));
      return Promise.all(imports).then(instance.bind(instance, item.main)).catch(() => void 0);
    } catch (error) {
      return Promise.resolve();
    }
  }));
}

/**
 * The settings page categories.
 */
const categories = [
  'general',
  'account',
  'appearance',
  'notifications',
  'keybinds',
  'commands',
  'developer',
  'advanced'
];

const content = {
  header: 'Settings',
  icon: 'gear'
};

export default class Settings extends Builtin {
  start () {
    this.pie = [];
    this.injectStyles('styles/main.scss');
    /**
     * Register a route for each of the settings categories.
     */
    categories.forEach(category =>
      vizality.api.routes.registerRoute({
        id: `settings/${category}`,
        path: `/settings/${category}`,
        render: props => (
          <Layout>
            <Content
              header={content.header}
              Separator={false}
              icon={content.icon}
              vz-builtin={this.addonId}
              vz-section={category}
            >
              <SettingsPage
                {...props}
                builtin={this}
                section={category}
              />
            </Content>
          </Layout>
        )
      })
    );

    vizality.api.settings._registerBuiltinSection({
      header: 'Settings',
      icon: content.icon,
      render: props => <SettingsPage {...props} builtin={this} section='general' />
    });

    vizality.api.actions.registerAction('CONFIRM_RESTART', () => this.confirmRestart());

    this.patchSettingsContextMenu();
    this.patchSettingsContextMenuAddonItem();
    this.patchSettingsContextMenuAddonCheckboxItem();
  }

  stop () {
    categories.forEach(category => vizality.api.routes.unregisterRoute(`settings/${category}`));
    vizality.api.routes.unregisterRoute('settings');
    vizality.api.actions.unregisterAction('CONFIRM_RESTART');
    unpatch('vz-settings-context-menu');
    unpatch('vz-settings-context-menu-addon-items');
    unpatch('vz-settings-context-menu-addon-checkbox-items');
  }

  confirmRestart () {
    const { colorStandard } = getModule('colorStandard');
    const { spacing } = getModule('spacing', 'message');
    const { size16 } = getModule('size16');

    openModal(() => props => (
      <Modal.Root {...props}>
        <Confirm
          {...props}
          red
          header={Messages.ERRORS_RESTART_APP}
          confirmText={Messages.BUNDLE_READY_RESTART}
          cancelText={Messages.BUNDLE_READY_LATER}
          onConfirm={() => DiscordNative.app.relaunch()}
          onCancel={closeModal}
        >
          <div className={joinClassNames(colorStandard, spacing, size16)}>
            {Messages.VIZALITY_SETTINGS_RESTART}
          </div>
        </Confirm>
      </Modal.Root>
    ));
  }

  async patchSettingsContextMenu () {
    const DiscordSettingsContextMenu = await getModule(m => m.default?.displayName === 'UserSettingsCogContextMenu', true);
    patch('vz-settings-context-menu', DiscordSettingsContextMenu, 'default', (_, res) => {
      const items = res.props.children.find(child => Array.isArray(child));
      items.push(
        <>
          <ContextMenu.Separator />
          <ContextMenu.Item
            id='vizality-dashboard'
            label='Vizality'
            action={() => vizality.api.routes.navigateTo('dashboard')}
          >
            {SettingsContextMenu.type().props.children}
          </ContextMenu.Item>
        </>
      );
    });
  }

  patchSettingsContextMenuAddonCheckboxItem () {
    const MenuCheckboxItem = getModule(m => m.default?.displayName === 'MenuCheckboxItem');
    patch('vz-settings-context-menu-addon-checkbox-items', MenuCheckboxItem, 'default', ([ props ], res) => {
      if (!res.props?.id) {
        return;
      }

      /**
       * If the ID doesn't start with one of the items we're targetting, don't patch it.
       */
      if ((res.props.id.indexOf('vizality-dashboard--plugins--') > 0 &&
           res.props.id.indexOf('vizality-dashboard--themes--') > 0) ||
           res.props['vz-addon-icon']
      ) return;

      /**
       *
       */
      const type =
        new RegExp(/(vizality-dashboard-?-plugins)/).test(res.props.id)
          ? 'plugin'
          : new RegExp(/(vizality-dashboard-?-themes)/).test(res.props.id)
            ? 'theme'
            : null;

      /**
       *
       */
      if (type !== 'plugin' && type !== 'theme') {
        return;
      }

      /**
       *
       */
      const addonId = res.props.id.replace(new RegExp(`(user-settings-cog-)?(vizality-dashboard-?-${toPlural(type)}--)`), '');

      /**
       *
       */
      if (!vizality.manager[toPlural(type)].isInstalled(addonId)) {
        return;
      }

      const addonIconUrl = props['vz-addon-icon'];
      res.props['vz-addon-icon'] = '';
      res.props['vz-addon-id'] = props.id;
      if (addonIconUrl) {
        res.props.style = { ...res.props.style, '--vz-addon-icon': `url('${addonIconUrl}')` };
      }
    });
  }

  patchSettingsContextMenuAddonItem () {
    const MenuItem = getModule(m => m.default?.displayName === 'MenuItem');
    patch('vz-settings-context-menu-addon-items', MenuItem, 'default', ([ props ], res) => {
      if (!res.props?.id) {
        return;
      }

      /**
       * If the ID doesn't start with one of the items we're targetting, don't patch it.
       */
      if ((res.props.id.indexOf('vizality-dashboard--plugins--') > 0 &&
           res.props.id.indexOf('vizality-dashboard--themes--') > 0) ||
           res.props['vz-addon-icon']
      ) return;

      /**
       *
       */
      const type =
        new RegExp(/(vizality-dashboard-?-plugins)/).test(res.props.id)
          ? 'plugin'
          : new RegExp(/(vizality-dashboard-?-themes)/).test(res.props.id)
            ? 'theme'
            : null;

      /**
       *
       */
      if (type !== 'plugin' && type !== 'theme') {
        return;
      }

      /**
       *
       */
      const addonId = res.props.id.replace(new RegExp(`(user-settings-cog-)?(vizality-dashboard-?-${toPlural(type)}--)`), '');

      /**
       *
       */
      if (!vizality.manager[toPlural(type)].isInstalled(addonId)) {
        return;
      }

      const addonIconUrl = props['vz-addon-icon'];
      res.props['vz-addon-icon'] = '';
      res.props['vz-addon-id'] = props.id;
      if (addonIconUrl) {
        res.props.style = { ...res.props.style, '--vz-addon-icon': `url('${addonIconUrl}')` };
      }
    });
  }
}
