import React, { Component } from 'react';
import { Container, Form, Input, Message } from 'semantic-ui-react';
import PropTypes from 'prop-types';
import { path, prop } from 'ramda';

import { withSite } from '../../addons/Site';
import PasswordStrength from '../PasswordStrength';
import { validateEmail } from '../../lib';

/* Interface */
const propTypes = {
  /** Link to privacy policy. */
  privacyPolicyLink: PropTypes.string,

  /** Event handler called when sign-up is successful. */
  onSignUp: PropTypes.func.isRequired,

  /**
   * StoryShare `Site`.
   * @private
   */
  site: PropTypes.object.isRequired,
};

/**
 * Signup form
 * It validates email and password
 * @returns {Object} component
 */
export class SignUpForm extends Component {
  state = {
    email: '',
    error: null,
    firstName: '',
    isLoading: false,
    lastName: '',
    password: '',
    passwordValid: null,
    privacyAgreement: false,
  };

  /**
   * Handle inputs change by updating value in local state
   * @param {SyntheticEvent} event - React's original SyntheticEvent.
   * @param {Object} data - All props and proposed value.
   * @returns {void}
   */
  handleChange = (event, { name, value }) => {
    this.setState({ [name]: value });
  };

  /**
   * Handle checkbox input change by updating value in local state
   * @param {SyntheticEvent} event - React's original SyntheticEvent.
   * @param {Object} data - All props and proposed value.
   * @returns {void}
   */
  handlePrivacy = (event, { checked }) =>
    this.setState({ privacyAgreement: checked });

  /**
   * Handles password validation
   * @param {boolean} valid - Updates state if password is valid.
   * @returns {void}
   */
  handlePasswordValidate = (valid) => this.setState({ passwordValid: valid });

  /**
   * Displays an error in the form
   * @param {string} error - Value of error to set state to.
   * @returns {void}
   */
  showError = (error = null) => {
    this.setState({
      error,
      isLoading: false,
    });
  };

  handleSubmit = async () => {
    if (!this.isComplete()) {
      return;
    }

    this.setState({ error: null, isLoading: true });

    const { email, password, firstName, lastName } = this.state;
    const { onSignUp, site } = this.props;

    if (!validateEmail(email.trim())) {
      this.showError('Supplied email address is not valid');
      return;
    }

    try {
      const result = await site.req('identityprovider/email/register')
        .setParams({
          email: email.trim(),
          first_name: firstName.trim(),
          last_name: lastName.trim(),
          password,
        })
        .promise()
        .create();

      const token = prop('token', result);
      if (!token) {
        // eslint-disable-next-line max-len
        this.showError('An error occurred during registration, please try again');
        return;
      }

      await site.login({ jwt: token });
      await site.req('users/me')
        .promise()
        .track('ME')
        .create();

      onSignUp();
    } catch (err) {
      if (path(['body', 'code'], err) === 'user_exists') {
        // eslint-disable-next-line max-len
        this.showError('You have already registered with this email address, please log in instead');
      } else {
        // eslint-disable-next-line max-len
        this.showError('An error occurred during registration, please try again');
      }
    }
  };

  privacyLabel = () => {
    const { privacyPolicyLink } = this.props;
    const policy = privacyPolicyLink ? (
      <a href={ privacyPolicyLink } target="_blank" rel="noopener noreferrer">
        privacy policy
      </a>
    ) : 'privacy policy';

    return <label>I agree to the { policy }</label>;
  };

  isComplete = () => {
    const {
      email,
      firstName,
      lastName,
      passwordValid,
      privacyAgreement,
    } = this.state;

    return true
      && email.trim()
      && firstName.trim()
      && lastName.trim()
      && passwordValid
      && privacyAgreement;
  };

  render() {
    const {
      email,
      password,
      firstName,
      lastName,
      privacyAgreement,
      isLoading,
      error,
    } = this.state;

    return (
      <Form
        onSubmit={ this.handleSubmit }
        loading={ isLoading }
        error={ !!error }
      >
        <p>Register here for a new account:</p>

        <Form.Field>
          <Input
            name="email"
            onChange={ this.handleChange }
            placeholder="Enter your email address"
            type="email"
            value={ email }
          />
        </Form.Field>

        <Form.Field>
          <Input
            name="password"
            onChange={ this.handleChange }
            placeholder="Enter a password"
            type="password"
            value={ password }
          />
        </Form.Field>
        <Form.Field>{ /* separate field for spacing */ }
          <Container fluid textAlign="left">{ /* forces left alignment */ }
            <PasswordStrength
              password={ password }
              onValidate={ this.handlePasswordValidate }
            />
          </Container>
        </Form.Field>

        <Form.Field>
          <Input
            name="firstName"
            onChange={ this.handleChange }
            placeholder="Enter your first name"
            type="text"
            value={ firstName }
          />
        </Form.Field>

        <Form.Field>
          <Input
            name="lastName"
            onChange={ this.handleChange }
            placeholder="Enter your last name"
            type="text"
            value={ lastName }
          />
        </Form.Field>

        <Message error content={ error } />

        <Form.Field>
          <Form.Checkbox
            label={ this.privacyLabel() }
            checked={ privacyAgreement }
            onChange={ this.handlePrivacy }
          />
        </Form.Field>

        <Form.Button
          circular
          disabled={ !this.isComplete() }
          primary
          size="large"
          type="submit"
        >
          Register
        </Form.Button>
      </Form>
    );
  }
}

SignUpForm.propTypes = propTypes;

export default withSite(SignUpForm);
