import autoBind from 'auto-bind';
import classNames from 'classnames';
import { isString } from 'lodash';
import { PureComponent, useEffect } from 'react';
import { toast } from 'react-toastify';
import styled from 'styled-components';

import { SessionButton, SessionButtonColor, SessionButtonType } from './basic/SessionButton';
// import { SessionSpinner } from './basic/SessionSpinner';
import { SessionTheme } from '../themes/SessionTheme';
import { switchPrimaryColorTo } from '../themes/switchPrimaryColor';
import { switchThemeTo } from '../themes/switchTheme';
import { SessionToastContainer } from './SessionToastContainer';
import { SessionWrapperModal } from './SessionWrapperModal';
import { SessionToast } from './basic/SessionToast';
import { SessionSpinner } from './loading';

interface State {
  errorCount: number;
  clearDataView: boolean;
  loading: boolean;
}

export const MAX_LOGIN_TRIES = 3;

const TextPleaseWait = (props: { isLoading: boolean }) => {
  if (!props.isLoading) {
    return null;
  }
  return <div>{window.i18n('waitOneMoment')}</div>;
};

const StyledContent = styled.div`
  background-color: var(--background-secondary-color);
  height: 100%;
  width: 100%;
`;

// We cannot import toastutils from the password window as it is pulling the whole sending
// pipeline(and causing crashes on Session instances with password)
function pushToastError(id: string, title: string, description?: string) {
  toast.error(<SessionToast title={title} description={description} />, {
    toastId: id,
    updateId: id,
  });
}

class SessionPasswordPromptInner extends PureComponent<unknown, State> {
  private inputRef?: any;

  constructor(props: any) {
    super(props);

    this.state = {
      errorCount: 0,
      clearDataView: false,
      loading: false,
    };

    autoBind(this);
  }

  public componentDidMount() {
    setTimeout(() => {
      this.inputRef?.focus();
    }, 100);
  }

  public render() {
    const isLoading = this.state.loading;
    const spinner = isLoading ? <SessionSpinner loading={true} /> : null;
    const featureElement = this.state.clearDataView ? (
      <p>{window.i18n('clearDeviceDescription')}</p>
    ) : (
      <div className="session-modal__input-group">
        <input
          type="password"
          id="password-prompt-input"
          defaultValue=""
          placeholder={window.i18n('passwordEnter')}
          onKeyUp={this.onKeyUp}
          ref={input => {
            this.inputRef = input;
          }}
        />
      </div>
    );

    return (
      <SessionWrapperModal
        title={this.state.clearDataView ? window.i18n('clearDevice') : window.i18n('passwordEnter')}
      >
        {spinner || featureElement}
        <TextPleaseWait isLoading={isLoading} />
        {this.state.clearDataView
          ? this.renderClearDataViewButtons()
          : this.renderPasswordViewButtons()}
      </SessionWrapperModal>
    );
  }

  public onKeyUp(event: any) {
    switch (event.key) {
      case 'Enter':
        this.initLogin();
        break;
      default:
    }
    event.preventDefault();
  }

  public async onLogin(passPhrase: string) {
    // Note: we don't trim the password anymore. If the user entered a space at the end, so be it.
    try {
      await window.onLogin(passPhrase);
    } catch (error) {
      // Increment the error counter and show the button if necessary
      this.setState({
        errorCount: this.state.errorCount + 1,
      });

      if (error && isString(error)) {
        pushToastError('onLogin', error);
      } else if (error?.message && isString(error.message)) {
        pushToastError('onLogin', error.message);
      }

      global.setTimeout(() => {
        document.getElementById('password-prompt-input')?.focus();
      }, 50);
    }
    this.setState({
      loading: false,
    });
  }

  private initLogin() {
    this.setState({
      loading: true,
    });
    const passPhrase = String((this.inputRef as HTMLInputElement).value);

    // this is to make sure a render has the time to happen before we lock the thread with all of the db work
    // this might be removed once we get the db operations to a worker thread
    global.setTimeout(() => {
      void this.onLogin(passPhrase);
    }, 100);
  }

  private initClearDataView() {
    this.setState({
      errorCount: 0,
      clearDataView: true,
    });
  }

  private renderPasswordViewButtons(): JSX.Element {
    const showResetElements = this.state.errorCount >= MAX_LOGIN_TRIES;

    return (
      <div className={classNames(showResetElements && 'session-modal__button-group')}>
        {showResetElements && (
          <>
            <SessionButton
              text={window.i18n('clearDevice')}
              buttonColor={SessionButtonColor.Danger}
              buttonType={SessionButtonType.Simple}
              onClick={this.initClearDataView}
            />
          </>
        )}
        {!this.state.loading && (
          <SessionButton
            text={showResetElements ? window.i18n('tryAgain') : window.i18n('done')}
            buttonType={SessionButtonType.Simple}
            onClick={this.initLogin}
            disabled={this.state.loading}
          />
        )}
      </div>
    );
  }

  private renderClearDataViewButtons(): JSX.Element {
    return (
      <div className="session-modal__button-group">
        <SessionButton
          text={window.i18n('clearDevice')}
          buttonColor={SessionButtonColor.Danger}
          buttonType={SessionButtonType.Simple}
          onClick={window.clearLocalData}
        />
        <SessionButton
          text={window.i18n('cancel')}
          buttonType={SessionButtonType.Simple}
          onClick={() => {
            this.setState({ clearDataView: false });
          }}
        />
      </div>
    );
  }
}

export const SessionPasswordPrompt = () => {
  useEffect(() => {
    if (window.theme) {
      void switchThemeTo({
        theme: window.theme,
      });
    }
    if (window.primaryColor) {
      void switchPrimaryColorTo(window.primaryColor);
    }
  }, []);

  return (
    <SessionTheme>
      <SessionToastContainer />
      <StyledContent>
        <SessionPasswordPromptInner />
      </StyledContent>
    </SessionTheme>
  );
};
