import { useMemo } from "react"
import { useRouter } from "next/router"
import Link from "next/link"
import useTranslation from "next-translate/useTranslation"
import { useTheme } from "next-themes"
import axios from "axios"
import { useForm } from "react-component-form"
import type { HandleUseFormCallback } from "react-component-form"

import { Main } from "../design/Main"
import { Input } from "../design/Input"
import { Button } from "../design/Button"
import { FormState } from "../design/FormState"
import { AuthenticationForm } from "."
import { userSchema } from "../../models/User"
import { api } from "../../tools/api"
import type { Tokens } from "../../tools/authentication"
import { Authentication as AuthenticationClass } from "../../tools/authentication"
import { AuthenticationSocialMedia } from "./AuthenticationSocialMedia"
import { useFormTranslation } from "../../hooks/useFormTranslation"

export interface AuthenticationProps {
  mode: "signup" | "signin"
}

export const Authentication: React.FC<AuthenticationProps> = (props) => {
  const { mode } = props

  const router = useRouter()
  const { lang, t } = useTranslation()
  const { theme } = useTheme()

  const schema = useMemo(() => {
    return {
      ...(mode === "signup" && { name: userSchema.name }),
      email: userSchema.email,
      password: userSchema.password,
    }
  }, [mode])

  const { handleUseForm, errors, fetchState, message } = useForm(schema)
  const { getFirstErrorTranslation } = useFormTranslation()

  const onSubmit: HandleUseFormCallback<typeof schema> = async (
    formData,
    formElement,
  ) => {
    if (mode === "signup") {
      try {
        await api.post(
          `/users/signup?redirectURI=${window.location.origin}/authentication/signin`,
          { ...formData, language: lang, theme },
        )
        formElement.reset()
        return {
          type: "success",
          message: "authentication:success-signup",
        }
      } catch (error) {
        if (axios.isAxiosError(error) && error.response?.status === 400) {
          const message = error.response.data.message as string
          if (message.endsWith("already taken.")) {
            return {
              type: "error",
              message: "authentication:already-used",
            }
          }
          return {
            type: "error",
            message: "errors:server-error",
          }
        }
        return {
          type: "error",
          message: "errors:server-error",
        }
      }
    } else {
      try {
        const { data } = await api.post<Tokens>("/users/signin", formData)
        const authentication = new AuthenticationClass(data, true)
        authentication.signin()
        await router.push("/application")
        return null
      } catch (error) {
        if (axios.isAxiosError(error) && error.response?.status === 400) {
          return {
            type: "error",
            message: "authentication:wrong-credentials",
          }
        }
        return {
          type: "error",
          message: "errors:server-error",
        }
      }
    }
  }

  return (
    <Main>
      <AuthenticationSocialMedia />
      <div className="pt-8 text-center font-paragraph text-lg">
        {t("authentication:or")}
      </div>
      <AuthenticationForm onSubmit={handleUseForm(onSubmit)}>
        {mode === "signup" && (
          <Input
            type="text"
            placeholder={t("common:name")}
            name="name"
            label={t("common:name")}
            error={getFirstErrorTranslation(errors.name)}
          />
        )}
        <Input
          type="email"
          placeholder="Email"
          name="email"
          label="Email"
          error={getFirstErrorTranslation(errors.email)}
        />
        <Input
          type="password"
          placeholder={t("authentication:password")}
          name="password"
          label={t("authentication:password")}
          showForgotPassword={mode === "signin"}
          error={getFirstErrorTranslation(errors.password)}
        />
        <Button data-cy="submit" className="mt-6 w-full" type="submit">
          {t("authentication:submit")}
        </Button>
        <p className="mt-3 font-headline text-sm text-green-800 hover:underline dark:text-green-400">
          <Link
            href={
              mode === "signup"
                ? "/authentication/signin"
                : "/authentication/signup"
            }
          >
            {mode === "signup"
              ? t("authentication:already-have-an-account")
              : t("authentication:dont-have-an-account")}
          </Link>
        </p>
      </AuthenticationForm>
      <FormState
        id="message"
        state={fetchState}
        message={message != null ? t(message) : undefined}
      />
    </Main>
  )
}
