import { typeboxResolver } from '@hookform/resolvers/typebox';
import { Static, Type } from '@sinclair/typebox';
import { useMutation } from '@tanstack/react-query';
import { t } from 'i18next';
import { useState } from 'react';
import { SubmitHandler, useForm } from 'react-hook-form';
import { Link, Navigate } from 'react-router-dom';

import { Button } from '@/components/ui/button';
import { Form, FormField, FormItem, FormMessage } from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { flagsHooks } from '@/hooks/flags-hooks';
import { HttpError, api } from '@/lib/api';
import { authenticationApi } from '@/lib/authentication-api';
import { authenticationSession } from '@/lib/authentication-session';
import { useRedirectAfterLogin } from '@/lib/navigation-utils';
import { formatUtils } from '@/lib/utils';
import { OtpType } from '@activepieces/ee-shared';
import {
  ApEdition,
  ApFlagId,
  AuthenticationResponse,
  ErrorCode,
  isNil,
  SignInRequest,
} from '@activepieces/shared';

import { CheckEmailNote } from './check-email-note';

const SignInSchema = Type.Object({
  email: Type.String({
    pattern: formatUtils.emailRegex.source,
    errorMessage: t('Email is invalid'),
  }),
  password: Type.String({
    minLength: 1,
    errorMessage: t('Password is required'),
  }),
});

type SignInSchema = Static<typeof SignInSchema>;

const SignInForm: React.FC = () => {
  const [showCheckYourEmailNote, setShowCheckYourEmailNote] = useState(false);
  const form = useForm<SignInSchema>({
    resolver: typeboxResolver(SignInSchema),
    defaultValues: {
      email: '',
      password: '',
    },
    mode: 'onChange',
  });

  const { data: edition } = flagsHooks.useFlag(ApFlagId.EDITION);

  const { data: userCreated } = flagsHooks.useFlag(ApFlagId.USER_CREATED);
  const redirectAfterLogin = useRedirectAfterLogin();

  const { mutate, isPending } = useMutation<
    AuthenticationResponse,
    HttpError,
    SignInRequest
  >({
    mutationFn: authenticationApi.signIn,
    onSuccess: (data) => {
      authenticationSession.saveResponse(data, false);
      redirectAfterLogin();
    },
    onError: (error) => {
      if (api.isError(error)) {
        const errorCode: ErrorCode | undefined = (
          error.response?.data as { code: ErrorCode }
        )?.code;
        if (isNil(errorCode)) {
          form.setError('root.serverError', {
            message: t('Something went wrong, please try again later'),
          });
          return;
        }
        switch (errorCode) {
          case ErrorCode.INVALID_CREDENTIALS: {
            form.setError('root.serverError', {
              message: t('Invalid email or password'),
            });
            break;
          }
          case ErrorCode.USER_IS_INACTIVE: {
            form.setError('root.serverError', {
              message: t('User has been deactivated'),
            });
            break;
          }
          case ErrorCode.EMAIL_IS_NOT_VERIFIED: {
            setShowCheckYourEmailNote(true);
            break;
          }
          case ErrorCode.DOMAIN_NOT_ALLOWED: {
            form.setError('root.serverError', {
              message: t(`Email domain is disallowed`),
            });
            break;
          }
          case ErrorCode.EMAIL_AUTH_DISABLED: {
            form.setError('root.serverError', {
              message: t(`Email authentication has been disabled`),
            });
            break;
          }
          default: {
            form.setError('root.serverError', {
              message: t('Something went wrong, please try again later'),
            });
          }
        }
      }
    },
  });

  const onSubmit: SubmitHandler<SignInRequest> = (data) => {
    form.setError('root.serverError', {
      message: undefined,
    });
    mutate(data);
  };

  if (!userCreated) {
    return <Navigate to="/sign-up" />;
  }

  return (
    <>
      <Form {...form}>
        <form className="grid space-y-4">
          <FormField
            control={form.control}
            name="email"
            render={({ field }) => (
              <FormItem className="grid space-y-2">
                <Label htmlFor="email">{t('Email')}</Label>
                <Input
                  {...field}
                  required
                  id="email"
                  type="text"
                  placeholder={'email@example.com'}
                  className="rounded-sm"
                  tabIndex={1}
                  onChange={(e) => {
                    field.onChange(e);
                    setShowCheckYourEmailNote(false);
                  }}
                />
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="password"
            render={({ field }) => (
              <FormItem className="grid space-y-2">
                <div className="flex items-center justify-between">
                  <Label htmlFor="password">{t('Password')}</Label>
                  {edition !== ApEdition.COMMUNITY && (
                    <Link
                      to="/forget-password"
                      className="text-muted-foreground text-sm hover:text-primary transition-all duration-200"
                    >
                      {t('Forgot your password?')}
                    </Link>
                  )}
                </div>
                <Input
                  {...field}
                  required
                  id="password"
                  type="password"
                  placeholder={'********'}
                  className="rounded-sm"
                  tabIndex={2}
                />
                <FormMessage />
              </FormItem>
            )}
          />
          {form?.formState?.errors?.root?.serverError && (
            <FormMessage>
              {form.formState.errors.root.serverError.message}
            </FormMessage>
          )}
          <Button
            loading={isPending}
            onClick={(e) => form.handleSubmit(onSubmit)(e)}
            tabIndex={3}
          >
            {t('Sign in')}
          </Button>
        </form>
      </Form>

      {showCheckYourEmailNote && (
        <div className="mt-4">
          <CheckEmailNote
            email={form.getValues().email}
            type={OtpType.EMAIL_VERIFICATION}
          />
        </div>
      )}
    </>
  );
};

SignInForm.displayName = 'SignIn';

export { SignInForm };
