import app from '../../forum/app';
import FormModal, { IFormModalAttrs } from '../../common/components/FormModal';
import Button from '../../common/components/Button';
import LogInButtons from './LogInButtons';
import extractText from '../../common/utils/extractText';
import ItemList from '../../common/utils/ItemList';
import Stream from '../../common/utils/Stream';
import type Mithril from 'mithril';
import RequestError from '../../common/utils/RequestError';
import type { LoginParams } from '../../common/Session';
import ForgotPasswordModal from './ForgotPasswordModal';

export interface ILoginModalAttrs extends IFormModalAttrs {
  identification?: string;
  password?: string;
  remember?: boolean;
}

export default class LogInModal<CustomAttrs extends ILoginModalAttrs = ILoginModalAttrs> extends FormModal<CustomAttrs> {
  /**
   * The value of the identification input.
   */
  identification!: Stream<string>;
  /**
   * The value of the password input.
   */
  password!: Stream<string>;
  /**
   * The value of the remember me input.
   */
  remember!: Stream<boolean>;

  oninit(vnode: Mithril.Vnode<CustomAttrs, this>) {
    super.oninit(vnode);

    this.identification = Stream(this.attrs.identification || '');
    this.password = Stream(this.attrs.password || '');
    this.remember = Stream(!!this.attrs.remember);
  }

  className() {
    return 'LogInModal Modal--small';
  }

  title() {
    return app.translator.trans('core.forum.log_in.title');
  }

  content() {
    return [<div className="Modal-body">{this.body()}</div>, <div className="Modal-footer">{this.footer()}</div>];
  }

  body() {
    return [<LogInButtons />, <div className="Form Form--centered">{this.fields().toArray()}</div>];
  }

  fields() {
    const items = new ItemList();

    const identificationLabel = extractText(app.translator.trans('core.forum.log_in.username_or_email_placeholder'));
    const passwordLabel = extractText(app.translator.trans('core.forum.log_in.password_placeholder'));

    items.add(
      'identification',
      <div className="Form-group">
        <input
          className="FormControl"
          name="identification"
          type="text"
          placeholder={identificationLabel}
          aria-label={identificationLabel}
          bidi={this.identification}
          disabled={this.loading}
        />
      </div>,
      30
    );

    items.add(
      'password',
      <div className="Form-group">
        <input
          className="FormControl"
          name="password"
          type="password"
          autocomplete="current-password"
          placeholder={passwordLabel}
          aria-label={passwordLabel}
          bidi={this.password}
          disabled={this.loading}
        />
      </div>,
      20
    );

    items.add(
      'remember',
      <div className="Form-group">
        <div>
          <label className="checkbox">
            <input type="checkbox" bidi={this.remember} disabled={this.loading} />
            {app.translator.trans('core.forum.log_in.remember_me_label')}
          </label>
        </div>
      </div>,
      10
    );

    items.add(
      'submit',
      <div className="Form-group">
        <Button className="Button Button--primary Button--block" type="submit" loading={this.loading}>
          {app.translator.trans('core.forum.log_in.submit_button')}
        </Button>
      </div>,
      -10
    );

    return items;
  }

  footer() {
    return (
      <>
        <p className="LogInModal-forgotPassword">
          <Button className="Button Button--text Button--link" onclick={this.forgotPassword.bind(this)}>
            {app.translator.trans('core.forum.log_in.forgot_password_link')}
          </Button>
        </p>
        {app.forum.attribute<boolean>('allowSignUp') && (
          <p className="LogInModal-signUp">
            {app.translator.trans('core.forum.log_in.sign_up_text', {
              a: <Button className="Button Button--text Button--link" onclick={this.signUp.bind(this)} />,
            })}
          </p>
        )}
      </>
    );
  }

  /**
   * Open the forgot password modal, prefilling it with an email if the user has
   * entered one.
   */
  forgotPassword() {
    const email = this.identification();
    const attrs = email.includes('@') ? { email } : undefined;

    app.modal.show(ForgotPasswordModal, attrs);
  }

  /**
   * Open the sign up modal, prefilling it with an email/username/password if
   * the user has entered one.
   */
  signUp() {
    const identification = this.identification();

    const attrs = {
      [identification.includes('@') ? 'email' : 'username']: identification,
    };

    app.modal.show(() => import('./SignUpModal'), attrs);
  }

  onready() {
    this.$('[name=' + (this.identification() ? 'password' : 'identification') + ']').trigger('select');
  }

  onsubmit(e: SubmitEvent) {
    e.preventDefault();

    this.loading = true;

    app.session.login(this.loginParams(), { errorHandler: this.onerror.bind(this) }).then(() => window.location.reload(), this.loaded.bind(this));
  }

  loginParams(): LoginParams {
    const data = {
      identification: this.identification(),
      password: this.password(),
      remember: this.remember(),
    };

    return data;
  }

  onerror(error: RequestError) {
    if (error.status === 401 && error.alert) {
      error.alert.content = app.translator.trans('core.forum.log_in.invalid_login_message');
      this.password('');
    }

    super.onerror(error);
  }
}
