import { SwitchItem, ButtonItem, Category } from '@vizality/components/settings';
import { Clickable, Button, FormNotice } from '@vizality/components';
import { Directories, Repositories } from '@vizality/constants';
import { removeDirRecursive } from '@vizality/util/file';
import React, { memo, useState, useEffect } from 'react';
import { Messages, chosenLocale } from '@vizality/i18n';
import { joinClassNames } from '@vizality/util/dom';
import { getModule } from '@vizality/webpack';
import { readdirSync, existsSync } from 'fs';
import { useFilter } from '@vizality/hooks';
import { clipboard } from 'electron';
import moment from 'moment';

export default memo(({ builtin, search = '' }) => {
  const [ copyText, setCopyText ] = useState(Messages.COPY);
  const [ pathsRevealed, setPathsRevealed ] = useState();
  const [ pluginsRevealed, setPluginsRevealed ] = useState();
  const [ transparentWindow, setTransparentWindow ] = vizality.api.settings.useSetting('transparentWindow', false);
  const [ isDiscordCacheCleared, setDiscordCacheCleared ] = useState(false);
  const [ isVizalityCacheCleared, setVizalityCacheCleared ] = useState(false);
  /**
   * Clears Discord's cache.
   * @returns {void}
   */
  const clearDiscordCache = () => {
    try {
      setDiscordCacheCleared(true);
      vizality.native.app.clearCache();
      setTimeout(() => {
        setDiscordCacheCleared(false);
      }, 2500);
    } catch (err) {
      builtin.error(err);
    }
  };

  /**
   * Clears Vizality's cache.
   * @returns {void}
   */
  const clearVizalityCache = () => {
    try {
      setVizalityCacheCleared(true);
      removeDirRecursive(Directories.CACHE)
        .then(() => {
          setTimeout(() => {
            setVizalityCacheCleared(false);
          }, 2500);
        });
    } catch (err) {
      builtin.error(err);
    }
  };

  /**
   *
   * @returns {void}
   */
  const handleDebugInfoCopy = () => {
    const plugins = vizality.manager.plugins.getEnabledKeys();
    const extract = document.querySelector('.vz-updater-debug-info > code')
      .innerText.replace(/([A-Z/ ]+) (?=\s(?!C:\\).*?:)/g, '\n[$1]').replace(/(.*?):\s(.*.+)/g, '$1="$2"').replace(/[ -](\w*(?=.*=))/g, '$1');

    setCopyText(Messages.COPIED);
    clipboard.writeText(
      `\`\`\`ini
      # Debugging Information | Result created: ${moment().calendar()}
      ${extract.substring(0, extract.indexOf('\nPlugins', extract.indexOf('\nPlugins') + 1))}
      Plugins="${plugins.join(', ')}"
      \`\`\``.replace(/ {6}|n\/a/g, '').replace(/(?![0-9]{1,3}) \/ (?=[0-9]{1,3})/g, '/')
    );
    setTimeout(() => setCopyText(Messages.COPY), 2500);
  };

  /**
   *
   * @note Intentionally left english-only.
   * @returns {void}
   */
  const renderDebugInfo = () => {
    const { getRegisteredExperiments, getExperimentOverrides } = getModule('initialize', 'getExperimentOverrides');
    const superProperties = getModule('getSuperPropertiesBase64').getSuperProperties();
    const plugins = vizality.manager.plugins.getEnabledKeys();

    const experimentOverrides = Object.keys(getExperimentOverrides()).length;
    const availableExperiments = Object.keys(getRegisteredExperiments()).length;

    const discordPath = process.resourcesPath.slice(0, -10);
    const maskPath = (path) => {
      path = path.replace(/(?:\/home\/|C:\\Users\\|\/Users\/)([ \w.-]+).*/i, (path, username) => {
        const usernameIndex = path.indexOf(username);
        return [ path.slice(0, usernameIndex), username.charAt(0) + username.slice(1).replace(/[a-zA-Z]/g, '*'),
          path.slice(usernameIndex + username.length) ].join('');
      });

      return path;
    };

    const cachedFiles = (existsSync(Directories.CACHE) && readdirSync(Directories.CACHE)
      .map(d => readdirSync(`${Directories.CACHE}/${d}`))
      .flat().length) || 'n/a';

    const createPathReveal = (title, path) =>
      <div className='full-column'>
        {title}:&#10;<a
          onMouseEnter={() => setPathsRevealed(true)}
          onMouseLeave={() => setPathsRevealed(false)}
          onClick={() => window.DiscordNative.fileManager.showItemInFolder(path)}
        >{pathsRevealed ? path : maskPath(path)}</a>
      </div>;

    return (
      <FormNotice
        type={FormNotice.Types.PRIMARY}
        body={<div className={ joinClassNames('vz-updater-debug-info', { copied: copyText === Messages.COPIED })}>
          <code>
            <b>System / Discord</b>
            <div className='row'>
              <div className='column'>Locale:&#10;{chosenLocale}</div>
              <div className='column'>OS:&#10;{(window.platform.os).toString()}</div>
              <div className='column'>Architecture:&#10;{superProperties.os_arch}</div>
              {process.platform === 'linux' && (
                <div className='column'>Distro:&#10;{superProperties.distro || 'n/a'}</div>
              )}
              <div className='column'>Release Channel:&#10;{superProperties.release_channel}</div>
              <div className='column'>App Version:&#10;{superProperties.client_version}</div>
              <div className='column'>Build Number:&#10;{superProperties.client_build_number}</div>
              <div className='column'>Build ID:&#10;{window.GLOBAL_ENV.SENTRY_TAGS.buildId}</div>
              <div className='column'>Experiments:&#10;{experimentOverrides} / {availableExperiments}</div>
            </div>

            <b>Process Versions</b>
            <div className='row'>
              <div className='column'>React:&#10;{React.version}</div>
              {[ 'electron', 'chrome', 'node' ].map(proc =>
                <div className='column'>{proc.charAt(0).toUpperCase() + proc.slice(1)}:&#10;{process.versions[proc]}</div>
              )}
            </div>

            <b>Vizality</b>
            <div className='row'>
              <div className='column'>Commands:&#10;{vizality.api.commands.getAllCommands().length}</div>
              <div className='column'>Settings:&#10;{Object.keys(vizality.api.settings?.store?.getAllSettings()).length}</div>
              <div className='column'>Plugins:&#10;{vizality.manager.plugins.getEnabledKeys().length} / {vizality.manager.plugins.count}
              </div>
              <div className='column'>Themes:&#10;{vizality.manager.themes.getEnabledKeys().length} / {vizality.manager.themes.count}
              </div>
              <div className='column'>Cached Files:&#10;{cachedFiles}</div>
              <div className='column'>APIs:&#10;{vizality.manager.apis._apis.length}</div>
            </div>

            <b>Git</b>
            <div className='row'>
              <div className='column'>Upstream:&#10;{vizality.git.upstream.replace(Repositories.VIZALITY, 'Official')}</div>
              <div className='column'>Revision:&#10;
                <a
                  href={`https://github.com/${vizality.git.upstream}/commit/${vizality.git.revision}`}
                  target='_blank'
                >
                  [{vizality.git.revision.substring(0, 7)}]
                </a>
              </div>
              <div className='column'>Branch:&#10;{vizality.git.branch}</div>
              <div className='column'>{`Latest:\n${!vizality.manager.builtins.get('updater').settings.get('updates', []).find(update => update.updateId === 'vizality')}`}</div>
            </div>

            <b>Listings</b>
            <div className='row'>
              {createPathReveal('Vizality Path', vizality.dir)}
              {createPathReveal('Discord Path', discordPath)}
              <div className='full-column'>Experiments:&#10;{experimentOverrides ? Object.keys(getExperimentOverrides()).join(', ') : 'n/a'}</div>
              <div className='full-column'>
              Plugins:&#10;
                {(plugins.length > 6 ? `${(pluginsRevealed ? plugins : plugins.slice(0, 6)).join(', ')}` : plugins.join(', ')) || 'n/a'}&nbsp;
                {plugins.length > 6 &&
                <Clickable tag='a' onClick={() => {
                  try {
                    setPluginsRevealed(!pluginsRevealed);
                  } catch (err) {
                    builtin.error(err);
                  }
                }}>
                  {pluginsRevealed ? 'Show less' : 'Show more'}
                </Clickable>}
              </div>
            </div>
          </code>
          <Button
            size={Button.Sizes.SMALL}
            color={copyText === Messages.COPIED ? Button.Colors.GREEN : Button.Colors.BRAND}
            onClick={() => {
              try {
                handleDebugInfoCopy();
              } catch (err) {
                builtin.error(err);
              }
            }}
          >
            {copyText}
          </Button>
        </div>}
      />
    );
  };

  const items = [
    {
      search: [
        Messages.VIZALITY_SETTINGS_TRANSPARENT_WINDOW,
        Messages.VIZALITY_SETTINGS_TRANSPARENT_WINDOW_DESC,
        'pizza'
      ],
      render: query =>
        <SwitchItem
          description={Messages.VIZALITY_SETTINGS_TRANSPARENT_WINDOW_DESC}
          value={transparentWindow}
          onChange={() => {
            try {
              setTransparentWindow(!transparentWindow);
            } catch (err) {
              builtin.error(err);
            }
          }}
          info={Messages.VIZALITY_SETTINGS_TRANSPARENT_WINDOW_INFO.format()}
          requiresRestart
        >
          {Messages.VIZALITY_SETTINGS_TRANSPARENT_WINDOW}
        </SwitchItem>
    },
    {
      search: [
        Messages.VIZALITY_SETTINGS_CACHE_VIZALITY,
        Messages.VIZALITY_SETTINGS_CACHE_VIZALITY_DESC,
        'cake'
      ],
      render: query =>
        <ButtonItem
          note={Messages.VIZALITY_SETTINGS_CACHE_VIZALITY_DESC}
          button={isVizalityCacheCleared ? Messages.VIZALITY_SETTINGS_CACHE_CLEARED : Messages.VIZALITY_SETTINGS_CACHE_VIZALITY}
          success={isVizalityCacheCleared}
          onClick={() => {
            try {
              clearVizalityCache();
            } catch (err) {
              builtin.error(err);
            }
          }}
        >
          {Messages.VIZALITY_SETTINGS_CACHE_VIZALITY}
        </ButtonItem>
    },
    {
      search: [
        Messages.VIZALITY_SETTINGS_CACHE_DISCORD,
        Messages.VIZALITY_SETTINGS_CACHE_DISCORD_DESC,
        'pie'
      ],
      render: query =>
        <ButtonItem
          note={Messages.VIZALITY_SETTINGS_CACHE_DISCORD_DESC}
          button={isDiscordCacheCleared ? Messages.VIZALITY_SETTINGS_CACHE_CLEARED : Messages.VIZALITY_SETTINGS_CACHE_DISCORD}
          success={isDiscordCacheCleared}
          onClick={() => {
            try {
              clearDiscordCache();
            } catch (err) {
              builtin.error(err);
            }
          }}
        >
          {Messages.VIZALITY_SETTINGS_CACHE_DISCORD}
        </ButtonItem>
    },
    {
      search: [
        Messages.VIZALITY_UPDATES_OPTS_DEBUG,
        Messages.VIZALITY_UPDATES_OPTS_DEBUG_DESC,
        'pie'
      ],
      render: query =>
        <Category
          icon='bug'
          title={Messages.VIZALITY_UPDATES_OPTS_DEBUG}
          description={Messages.VIZALITY_UPDATES_OPTS_DEBUG_DESC}
        >
          {renderDebugInfo()}
        </Category>
    }
  ];

  const [ query, setQuery, filteredResults ] = useFilter({
    keys: [ 'search' ],
    data: items
  });

  useEffect(() => {
    setQuery(search);
  }, [ search ]);

  return filteredResults.map(result => result.render(query));
});
