import { SwitchItem, TextInput, Category, FormTitle } from '@vizality/components/settings';
import { Confirm, Button, FormNotice } from '@vizality/components';
import { openModal, closeModal } from '@vizality/modal';
import { Repositories } from '@vizality/constants';
import React, { useEffect, memo } from 'react';
import { Messages } from '@vizality/i18n';
import { joinClassNames } from '@vizality/util/dom';
import { getModule } from '@vizality/webpack';
import moment from 'moment';

import Update from './Update';
import Icons from './Icons';

export default memo(({ getSetting, toggleSetting, updateSetting }) => {
  useEffect(() => {
    const updateToasts = [
      'vizality-updater-update-complete',
      'vizality-updater-update-available'
    ];
    updateToasts.forEach(t => vizality.api.notifications.closeToast(t));
  });

  // eslint-disable-next-line consistent-this
  const _this = vizality.manager.builtins.get('updater');
  // @todo: Make this be in its own store
  const awaitingReload = getSetting('awaitingReload', false);
  const updating = getSetting('updating', false);
  const checking = getSetting('checking', false);
  const disabled = getSetting('disabled', false);
  const paused = getSetting('paused', false);
  const failed = getSetting('failed', false);

  const updates = getSetting('updates', []);
  const disabledAddons = getSetting('addonsDisabled', []);
  const checkingProgress = getSetting('checkingProgress', [ 0, 0 ]);
  const last = moment(getSetting('lastCheck', false)).calendar();

  let icon, title;
  if (disabled) {
    icon = <Icons.Update color='#f04747'/>;
    title = Messages.VIZALITY_UPDATES_DISABLED;
  } else if (paused) {
    icon = <Icons.Paused/>;
    title = Messages.VIZALITY_UPDATES_PAUSED;
  } else if (checking) {
    icon = <Icons.Update color='#7289da' animated/>;
    title = Messages.VIZALITY_UPDATES_CHECKING;
  } else if (updating) {
    icon = <Icons.Update color='#7289da' animated/>;
    title = Messages.VIZALITY_UPDATES_UPDATING;
  } else if (failed) {
    icon = <Icons.Error/>;
    title = Messages.VIZALITY_UPDATES_FAILED;
  } else if (updates.length > 0) {
    icon = <Icons.Update/>;
    title = Messages.VIZALITY_UPDATES_AVAILABLE;
  } else {
    icon = <Icons.UpToDate/>;
    title = Messages.VIZALITY_UPDATES_UP_TO_DATE;
  }

  /**
   * Gets a valid interval value in minutes based on user's input.
   * @param {number} minutes Interval value
   * @returns {void}
   */
  const _getValidInterval = minutes => {
    if (Number(minutes)) {
      if (Number(minutes) >= 10) {
      /**
       * This is to make sure the user doesn't input a value that goes over setInterval's
       * max of 2,147,483,647, because if this happens, it will trigger the updates immediately
       * and infinitely, using max computer resources and freezing the app.
       */
        if (Number(minutes) >= 34000) {
          return 34000;
        }
        return Math.ceil(Number(minutes));
      }
      /**
       * If it's set to less than 10, set it to 10.
       */
      return 10;
    }
    /**
     * If all else fails, set it to the default 15 minutes.
     */
    return 15;
  };

  /**
   * Gets a valid concurrency limit based on user's input.
   * @param {number} limit Concurrency limit
   * @returns {void}
   */
  const _getValidConcurrency = limit => {
    if (Number(limit)) {
      if (Number(limit) >= 1) {
        return Math.ceil(Number(limit));
      }
      /**
       * If it's set to less than 1, set it to 1.
       */
      return 1;
    }
    /**
     * If all else fails, set it to the default 2 concurrency limit.
     */
    return 2;
  };

  const _renderFormNotice = (title, body) => {
    const { marginBottom20 } = getModule('marginBottom20');
    return <FormNotice
      className={joinClassNames('vz-updater-form-notice', marginBottom20)}
      imageData={{
        width: 60,
        height: 60,
        src: '/assets/0694f38cb0b10cc3b5b89366a0893768.svg'
      }}
      type={FormNotice.Types.WARNING}
      title={title}
      body={body}
    />;
  };

  // --- PARTS
  const renderReload = () => {
    const body = <>
      <p>{Messages.VIZALITY_UPDATES_AWAITING_RELOAD_DESC}</p>
      <Button
        size={Button.Sizes.SMALL}
        color={Button.Colors.YELLOW}
        look={Button.Looks.INVERTED}
        onClick={() => location.reload()}
      >
        {Messages.ERRORS_RELOAD}
      </Button>
    </>;
    return _renderFormNotice(Messages.VIZALITY_UPDATES_AWAITING_RELOAD_TITLE, body);
  };

  // @todo Add to modals AI
  const _confirm = (title, content, confirm, callback) => {
    const { colorStandard } = getModule('colorStandard');
    const { spacing } = getModule('spacing', 'message');
    const { size16 } = getModule('size16');
    openModal(() => props => (
      <Confirm
        {...props}
        header={title}
        confirmText={confirm}
        cancelText={Messages.CANCEL}
        onConfirm={callback}
        onCancel={closeModal}
      >
        <div className={joinClassNames(colorStandard, spacing, size16)}>
          {content}
        </div>
      </Confirm>
    ));
  };

  // --- PROMPTS
  const confirmSkipUpdate = callback => {
    _confirm(
      Messages.VIZALITY_UPDATES_SKIP_MODAL_TITLE,
      Messages.VIZALITY_UPDATES_SKIP_MODAL,
      Messages.VIZALITY_UPDATES_SKIP,
      callback
    );
  };

  const confirmPauseUpdates = () => {
    _confirm(
      Messages.VIZALITY_UPDATES_PAUSE,
      Messages.VIZALITY_UPDATES_PAUSE_MODAL,
      Messages.VIZALITY_UPDATES_PAUSE,
      () => updateSetting('paused', true)
    );
  };

  const confirmDisableUpdates = (all, callback) => {
    _confirm(
      Messages.VIZALITY_UPDATES_DISABLE,
      all ? Messages.VIZALITY_UPDATES_DISABLE_MODAL_ALL : Messages.VIZALITY_UPDATES_DISABLE_MODAL,
      Messages.VIZALITY_UPDATES_DISABLE,
      callback
    );
  };

  return (
    <>
      {awaitingReload && renderReload()}
      <div className='vz-updater-top-section'>
        <div className='vz-updater-top-section-header'>
          <div className='vz-updater-top-section-icon'>
            {icon}
          </div>
          <div className='vz-updater-top-section-status'>
            <h3 className='vz-updater-top-section-title'>
              {title}
            </h3>
            {!disabled && !updating && (!checking || checkingProgress[1] > 0) && <div className='vz-updater-top-section-subtitle'>
              {paused
                ? Messages.VIZALITY_UPDATES_PAUSED_RESUME
                : checking
                  ? Messages.VIZALITY_UPDATES_CHECKING_STATUS.format({
                    checked: checkingProgress[0],
                    total: checkingProgress[1]
                  })
                  : Messages.VIZALITY_UPDATES_LAST_CHECKED.format({ date: last })}
            </div>}
          </div>
          <div className='vz-updater-top-section-about'>
            <div className='vz-updater-top-section-about-column'>
              <span className='vz-updater-top-section-about-title'>
                {Messages.VIZALITY_UPDATES_UPSTREAM}
              </span>
              <span className='vz-updater-top-section-about-title'>
                {Messages.VIZALITY_UPDATES_REVISION}
              </span>
              <span className='vz-updater-top-section-about-title'>
                {Messages.VIZALITY_UPDATES_BRANCH}
              </span>
            </div>
            <div className='vz-updater-top-section-about-column'>
              <span className='vz-updater-top-section-about-value'>
                {vizality.git.upstream.replace(Repositories.VIZALITY, Messages.VIZALITY_UPDATES_UPSTREAM_OFFICIAL)}
              </span>
              <span className='vz-updater-top-section-about-value'>
                {vizality.git.revision.substring(0, 7)}
              </span>
              <span className='vz-updater-top-section-about-value'>
                {vizality.git.branch}
              </span>
            </div>
          </div>
        </div>
        <div className='vz-updater-top-section-footer'>
          {disabled || paused
            ? <Button
              size={Button.Sizes.SMALL}
              color={Button.Colors.GREEN}
              onClick={() => {
                updateSetting('paused', false);
                updateSetting('disabled', false);
              }}
            >
              {disabled ? Messages.VIZALITY_UPDATES_ENABLE : Messages.VIZALITY_UPDATES_RESUME}
            </Button>
            : (!checking && !updating && <>
              {updates.length > 0 && <Button
                size={Button.Sizes.SMALL}
                color={failed ? Button.Colors.RED : Button.Colors.GREEN}
                onClick={() => failed ? _this.confirmForce() : _this.updateAll()}
              >
                {failed ? Messages.VIZALITY_UPDATES_FORCE : Messages.VIZALITY_UPDATES_UPDATE}
              </Button>}
              <Button
                size={Button.Sizes.SMALL}
                onClick={() => _this.checkForUpdates(true)}
              >
                {Messages.VIZALITY_UPDATES_CHECK}
              </Button>
              <Button
                size={Button.Sizes.SMALL}
                color={Button.Colors.YELLOW}
                onClick={() => confirmPauseUpdates()}
              >
                {Messages.VIZALITY_UPDATES_PAUSE}
              </Button>
              <Button
                size={Button.Sizes.SMALL}
                color={Button.Colors.RED}
                onClick={() => confirmDisableUpdates(true, () => updateSetting('disabled', true))}
              >
                {Messages.VIZALITY_UPDATES_DISABLE}
              </Button>
            </>)}
        </div>
      </div>
      {!disabled && !paused && !checking && updates.length > 0 && <div className='vz-updater-updates'>
        <FormTitle className='vz-updater-updates-title'>
          Pending Updates
        </FormTitle>
        {updates.map(update => {
          return (
            <Update
              {...update}
              key={update.updateId}
              updating={updating}
              onUpdate={() => _this.update(update)}
              onSkip={() => confirmSkipUpdate(() => _this.skipUpdate(update, update.commits[0].id))}
              onDisable={() => confirmDisableUpdates(false, () => _this.disableUpdates(update))}
            />
          );
        })}
      </div>}
      {disabledAddons.length > 0 && (
        <Category title={Messages.VIZALITY_UPDATES_DISABLED_SECTION} description={Messages.VIZALITY_UPDATES_DISABLED_SECTION_DESC}>
          {disabledAddons.map(update => {
            return (
              <Update
                {...update}
                disabled={true}
                key={update.updateId}
                updating={updating}
                onEnableUpdates={() => _this.enableUpdates(update)}
              />
            );
          })}
        </Category>
      )}
      <div className='vz-updater-options'>
        <FormTitle className='vz-updater-options-title'>
          {Messages.OPTIONS}
        </FormTitle>
        <SwitchItem
          value={getSetting('automatic', false)}
          disabled={disabled}
          onChange={() => toggleSetting('automatic')}
          note={Messages.VIZALITY_UPDATES_OPTS_AUTO_DESC}
        >
          {Messages.VIZALITY_UPDATES_OPTS_AUTO}
        </SwitchItem>
        <SwitchItem
          value={getSetting('checkForUpdatesOnStartup', false)}
          disabled={disabled}
          onChange={() => toggleSetting('checkForUpdatesOnStartup')}
          note={Messages.VIZALITY_UPDATES_OPTS_STARTUP_CHECK_DESC}
        >
          {Messages.VIZALITY_UPDATES_OPTS_STARTUP_CHECK}
        </SwitchItem>
        <TextInput
          note={Messages.VIZALITY_UPDATES_OPTS_INTERVAL_DESC.format()}
          disabled={disabled}
          onChange={val => updateSetting('interval', _getValidInterval(val))}
          defaultValue={getSetting('interval', 15)}
          required={true}
        >
          {Messages.VIZALITY_UPDATES_OPTS_INTERVAL}
        </TextInput>
        <TextInput
          note={Messages.VIZALITY_UPDATES_OPTS_CONCURRENCY_DESC.format()}
          disabled={disabled}
          onChange={val => updateSetting('concurrency', _getValidConcurrency(val))}
          defaultValue={getSetting('concurrency', 2)}
          required={true}
        >
          {Messages.VIZALITY_UPDATES_OPTS_CONCURRENCY}
        </TextInput>
      </div>
    </>
  );
});
