import React, { useCallback, useEffect, useState } from "react";
import { Link, Navigate } from "react-router-dom";
import Joi from "joi";
import authentication from "../services/authenticationService";
import { InputType } from "../../../components/common/Input";
import { ButtonType } from "../../../components/common/Button";
import { useForm } from "../../../components/common/useForm";
import {
  renderButton,
  renderError,
  renderInput,
} from "../../../components/common/formHelpers";

const LoginForm: React.FC = () => {
  const [isInNextStage, setIsInNextStage] = useState(false);
  const [emailSent, setEmailSent] = useState(false);
  const passwordMaxLength = 255;

  const form = useForm({
    loaded: true,
    data: {
      username: "",
      password: "",
      tfaNeeded: false,
      requestTfaRemoval: false,
      securityCode: "",
    },
    errors: {},
    redirect: "",
  });

  const schema = {
    username: Joi.string()
      .required()
      .email({ tlds: { allow: false } })
      .label("Email"),
    password: Joi.string().required().label("Password"),
    tfaNeeded: Joi.boolean().required(),
    requestTfaRemoval: Joi.boolean().required(),
    securityCode: Joi.string().allow("").label("Authenticate"),
  };

  form.schema = schema;

  useEffect(() => {
    window.location.replace("/login");
  }, []);

  const performLogin = useCallback(
    async (data: any) => {
      try {
        const result = await authentication.login(
          data.username,
          data.password,
          data.securityCode,
          data.requestTfaRemoval,
        );

        switch (result) {
          case 1: {
            const nextData = { ...form.state.data };

            if (!nextData.tfaNeeded) {
              nextData.tfaNeeded = true;
              form.setState({ data: nextData });
            }
            break;
          }
          case 2:
            window.location.href = "/";
            break;
          default:
            break;
        }
      } catch (ex: any) {
        form.handleGeneralError(ex);
      }
    },
    [form],
  );

  const doSubmit = async () => {
    const { data } = form.state;
    await performLogin(data);
  };

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    form.handleSubmit(e, async () => doSubmit());
  };

  const handleNextClick = async () => {
    const data = { ...form.state.data };
    const validationResult = schema.username.validate(data.username);
    if (validationResult.error === undefined) {
      setIsInNextStage(true);
    }
  };

  const handleForgetPassword = async () => {
    try {
      await authentication.forgotPassword(form.state.data.username as string);
      setEmailSent(true);
      const nextData = { ...form.state.data, username: "", password: "" };
      form.setState({ data: nextData });
    } catch (ex: any) {
      form.handleGeneralError(ex);
    }
  };

  const authenticationWorkAround = async () => {
    const data = { ...form.state.data, requestTfaRemoval: true };
    await performLogin(data);
    form.setState({ data });
  };

  const { tfaNeeded, requestTfaRemoval } = form.state.data as any;
  const result = schema.username.validate(form.state.data.username);
  const validEmail = result.error === undefined;

  if (authentication.getCurrentUser()) return <Navigate to="/" />;

  const requestTfaRemovalPanel = (
    <div>
      An email has been sent to you so that you can regain control of your
      account.
    </div>
  );

  const loginPanel = (
    <>
      <form onSubmit={handleSubmit}>
        {renderInput(
          "username",
          "",
          form.state.data,
          form.state.errors,
          InputType.text,
          isInNextStage,
          "",
          "Email",
          0,
          true,
          "username",
          form.handleChange,
        )}
        {renderInput(
          "password",
          "",
          form.state.data,
          form.state.errors,
          InputType.password,
          emailSent,
          "",
          "Password",
          passwordMaxLength,
          isInNextStage,
          "current-password",
          form.handleChange,
        )}
        {!isInNextStage &&
          renderButton(
            "Next",
            form.state.errors,
            "next",
            handleNextClick,
            "login",
            validEmail,
            ButtonType.primary,
            true,
          )}
        {isInNextStage && (
          <div className="clickables">
            {renderButton(
              "Login",
              form.state.errors,
              "login",
              undefined,
              "login",
              !emailSent,
            )}
          </div>
        )}
      </form>
      {isInNextStage && (
        <div className="forgottenLink">
          {renderButton(
            "Forgotten Password",
            form.state.errors,
            "forgot-password",
            handleForgetPassword,
            "forgot-password",
            validEmail,
            ButtonType.secondary,
            true,
          )}
        </div>
      )}
      {emailSent && (
        <div className="alert alert-info emailSent">
          If you have a registered account, you will receive an email.
        </div>
      )}
      {renderError("_general", form.state.errors)}
    </>
  );

  const tfaPanel = (
    <form onSubmit={handleSubmit}>
      {renderError("_general", form.state.errors)}
      {renderInput(
        "securityCode",
        "Authenticate",
        form.state.data,
        form.state.errors,
        InputType.text,
        false,
        "",
        "",
        0,
        true,
        undefined,
        form.handleChange,
      )}
      {renderButton("Authenticate", form.state.errors, "authenticate")}
      <Link to="#" onClick={authenticationWorkAround}>
        My Authenticator is not working
      </Link>
    </form>
  );

  return (
    <div>
      {requestTfaRemoval
        ? requestTfaRemovalPanel
        : tfaNeeded
          ? tfaPanel
          : loginPanel}
    </div>
  );
};

export default LoginForm;
