'use client';

import { useState } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { GibsAuthSignInButton } from '@/components/layout/auth/buttons';
import { useAuthActions } from '@convex-dev/auth/react';
import { zodResolver } from '@hookform/resolvers/zod';
import { ConvexError } from 'convex/values';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
import { z } from 'zod';

import { PASSWORD_MAX, PASSWORD_MIN, PASSWORD_REGEX } from '@gib/backend/types';
import {
  Card,
  CardContent,
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
  Input,
  InputOTP,
  InputOTPGroup,
  InputOTPSeparator,
  InputOTPSlot,
  Separator,
  SubmitButton,
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
} from '@gib/ui';

const signInFormSchema = z.object({
  email: z.email({
    message: 'Please enter a valid email address.',
  }),
  password: z.string().regex(PASSWORD_REGEX, {
    message: 'Incorrect password. Does not meet requirements.',
  }),
});

const signUpFormSchema = z
  .object({
    name: z.string().min(2, {
      message: 'Name must be at least 2 characters.',
    }),
    email: z.email({
      message: 'Please enter a valid email address.',
    }),
    password: z
      .string()
      .min(PASSWORD_MIN, {
        message: `Password must be at least ${PASSWORD_MIN} characters.`,
      })
      .max(PASSWORD_MAX, {
        message: `Password must be no more than ${PASSWORD_MAX} characters.`,
      })
      .regex(/^\S+$/, {
        message: 'Password must not contain whitespace.',
      })
      .regex(/[0-9]/, {
        message: 'Password must contain at least one digit.',
      })
      .regex(/[a-z]/, {
        message: 'Password must contain at least one lowercase letter.',
      })
      .regex(/[A-Z]/, {
        message: 'Password must contain at least one uppercase letter.',
      })
      .regex(/[\p{P}\p{S}]/u, {
        message: 'Password must contain at least one symbol.',
      }),
    confirmPassword: z.string().min(PASSWORD_MIN, {
      message: `Password must be at least ${PASSWORD_MIN} characters.`,
    }),
  })
  .refine((data) => data.password === data.confirmPassword, {
    message: 'Passwords do not match!',
    path: ['confirmPassword'],
  });

const verifyEmailFormSchema = z.object({
  code: z.string({ message: 'Invalid code.' }),
});

const SignIn = () => {
  const { signIn } = useAuthActions();
  const [flow, setFlow] = useState<'signIn' | 'signUp' | 'email-verification'>(
    'signIn',
  );
  const [email, setEmail] = useState<string>('');
  const [code, setCode] = useState<string>('');
  const [loading, setLoading] = useState(false);
  const router = useRouter();

  const signInForm = useForm<z.infer<typeof signInFormSchema>>({
    resolver: zodResolver(signInFormSchema),
    defaultValues: { email: '', password: '' },
  });

  const signUpForm = useForm<z.infer<typeof signUpFormSchema>>({
    resolver: zodResolver(signUpFormSchema),
    defaultValues: {
      name: '',
      email,
      password: '',
      confirmPassword: '',
    },
  });

  const verifyEmailForm = useForm<z.infer<typeof verifyEmailFormSchema>>({
    resolver: zodResolver(verifyEmailFormSchema),
    defaultValues: { code },
  });

  const handleSignIn = async (values: z.infer<typeof signInFormSchema>) => {
    const formData = new FormData();
    formData.append('email', values.email);
    formData.append('password', values.password);
    formData.append('flow', flow);
    setLoading(true);
    try {
      await signIn('password', formData).then(() => router.push('/'));
    } catch (error) {
      console.error('Error signing in:', error);
      toast.error('Error signing in.');
    } finally {
      signInForm.reset();
      setLoading(false);
    }
  };

  const handleSignUp = async (values: z.infer<typeof signUpFormSchema>) => {
    const formData = new FormData();
    formData.append('email', values.email);
    formData.append('password', values.password);
    formData.append('flow', flow);
    formData.append('name', values.name);
    setLoading(true);
    try {
      if (values.confirmPassword !== values.password)
        throw new ConvexError('Passwords do not match.');
      await signIn('password', formData).then(() => {
        setEmail(values.email);
        setFlow('email-verification');
      });
    } catch (error) {
      console.error('Error signing up:', error);
      toast.error('Error signing up.');
    } finally {
      signUpForm.reset();
      setLoading(false);
    }
  };

  const handleVerifyEmail = async (
    values: z.infer<typeof verifyEmailFormSchema>,
  ) => {
    const formData = new FormData();
    formData.append('code', code);
    formData.append('flow', flow);
    formData.append('email', email);
    setLoading(true);
    try {
      await signIn('password', formData).then(() => router.push('/'));
    } catch (error) {
      console.error('Error verifying email:', error);
      toast.error('Error verifying email.');
    } finally {
      verifyEmailForm.reset();
      setLoading(false);
    }
  };

  if (flow === 'email-verification') {
    return (
      <div className='flex flex-col items-center'>
        <Card className='bg-card/25 min-h-[720px] w-md p-4'>
          <CardContent>
            <div className='mb-6 text-center'>
              <h2 className='text-2xl font-bold'>Verify Your Email</h2>
              <p className='text-muted-foreground'>We sent a code to {email}</p>
            </div>
            <Form {...verifyEmailForm}>
              <form
                onSubmit={verifyEmailForm.handleSubmit(handleVerifyEmail)}
                className='flex flex-col space-y-8'
              >
                <FormField
                  control={verifyEmailForm.control}
                  name='code'
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel className='text-xl'>Code</FormLabel>
                      <FormControl>
                        <InputOTP
                          maxLength={6}
                          value={code}
                          onChange={(value) => setCode(value)}
                        >
                          <InputOTPGroup>
                            <InputOTPSlot index={0} />
                            <InputOTPSlot index={1} />
                            <InputOTPSlot index={2} />
                            <InputOTPSeparator />
                            <InputOTPSlot index={3} />
                            <InputOTPSlot index={4} />
                            <InputOTPSlot index={5} />
                          </InputOTPGroup>
                        </InputOTP>
                      </FormControl>
                      <FormDescription>
                        Please enter the one-time password sent to your email.
                      </FormDescription>
                      <div className='flex w-full flex-col items-center'>
                        <FormMessage className='w-5/6 text-center' />
                      </div>
                    </FormItem>
                  )}
                />
                <SubmitButton
                  disabled={loading}
                  pendingText='Signing Up...'
                  className='mx-auto w-2/3 text-xl font-semibold'
                >
                  Verify Email
                </SubmitButton>
              </form>
            </Form>
            <div className='mt-4 text-center'>
              <button
                onClick={() => setFlow('signUp')}
                className='text-muted-foreground text-sm hover:underline'
              >
                Back to Sign Up
              </button>
            </div>
          </CardContent>
        </Card>
      </div>
    );
  }

  return (
    <div className='flex flex-col items-center'>
      <Card className='bg-card/25 min-h-[720px] w-md p-4'>
        <Tabs
          defaultValue={flow}
          onValueChange={(value) => setFlow(value as 'signIn' | 'signUp')}
          className='items-center'
        >
          <TabsList className='py-6'>
            <TabsTrigger
              value='signIn'
              className='cursor-pointer p-6 text-2xl font-bold'
            >
              Sign In
            </TabsTrigger>
            <TabsTrigger
              value='signUp'
              className='cursor-pointer p-6 text-2xl font-bold'
            >
              Sign Up
            </TabsTrigger>
          </TabsList>
          <TabsContent value='signIn'>
            <Card className='bg-card/50 min-w-xs sm:min-w-sm'>
              <CardContent>
                <Form {...signInForm}>
                  <form
                    onSubmit={signInForm.handleSubmit(handleSignIn)}
                    className='flex flex-col space-y-8'
                  >
                    <FormField
                      control={signInForm.control}
                      name='email'
                      render={({ field }) => (
                        <FormItem>
                          <FormLabel className='text-xl'>Email</FormLabel>
                          <FormControl>
                            <Input
                              type='email'
                              placeholder='you@example.com'
                              {...field}
                            />
                          </FormControl>
                          <div className='flex w-full flex-col items-center'>
                            <FormMessage className='w-5/6 text-center' />
                          </div>
                        </FormItem>
                      )}
                    />
                    <FormField
                      control={signInForm.control}
                      name='password'
                      render={({ field }) => (
                        <FormItem>
                          <div className='flex justify-between'>
                            <FormLabel className='text-xl'>Password</FormLabel>
                            <Link href='/forgot-password'>
                              Forgot Password?
                            </Link>
                          </div>
                          <FormControl>
                            <Input
                              type='password'
                              placeholder='Your password'
                              {...field}
                            />
                          </FormControl>
                          <div className='flex w-full flex-col items-center'>
                            <FormMessage className='w-5/6 text-center' />
                          </div>
                        </FormItem>
                      )}
                    />
                    <SubmitButton
                      disabled={loading}
                      pendingText='Signing in...'
                      className='mx-auto w-2/3 text-xl font-semibold'
                    >
                      Sign In
                    </SubmitButton>
                  </form>
                </Form>
                <div className='flex justify-center'>
                  <div className='mx-auto my-2.5 flex w-1/4 flex-row items-center justify-center'>
                    <Separator className='mr-3 py-0.5' />
                    <span className='text-lg font-semibold'>or</span>
                    <Separator className='ml-3 py-0.5' />
                  </div>
                </div>
                <div className='mt-3 flex justify-center'>
                  <GibsAuthSignInButton />
                </div>
              </CardContent>
            </Card>
          </TabsContent>
          <TabsContent value='signUp'>
            <Card className='bg-card/50 min-w-xs sm:min-w-sm'>
              <CardContent>
                <Form {...signUpForm}>
                  <form
                    onSubmit={signUpForm.handleSubmit(handleSignUp)}
                    className='flex flex-col space-y-8'
                  >
                    <FormField
                      control={signUpForm.control}
                      name='name'
                      render={({ field }) => (
                        <FormItem>
                          <FormLabel className='text-xl'>Name</FormLabel>
                          <FormControl>
                            <Input
                              type='text'
                              placeholder='Full Name'
                              {...field}
                            />
                          </FormControl>
                          <div className='flex w-full flex-col items-center'>
                            <FormMessage className='w-5/6 text-center' />
                          </div>
                        </FormItem>
                      )}
                    />
                    <FormField
                      control={signUpForm.control}
                      name='email'
                      render={({ field }) => (
                        <FormItem>
                          <FormLabel className='text-xl'>Email</FormLabel>
                          <FormControl>
                            <Input
                              type='email'
                              placeholder='you@example.com'
                              {...field}
                            />
                          </FormControl>
                          <div className='flex w-full flex-col items-center'>
                            <FormMessage className='w-5/6 text-center' />
                          </div>
                        </FormItem>
                      )}
                    />
                    <FormField
                      control={signUpForm.control}
                      name='password'
                      render={({ field }) => (
                        <FormItem>
                          <FormLabel className='text-xl'>Password</FormLabel>
                          <FormControl>
                            <Input
                              type='password'
                              placeholder='Your password'
                              {...field}
                            />
                          </FormControl>
                          <div className='flex w-full flex-col items-center'>
                            <FormMessage className='w-5/6 text-center' />
                          </div>
                        </FormItem>
                      )}
                    />
                    <FormField
                      control={signUpForm.control}
                      name='confirmPassword'
                      render={({ field }) => (
                        <FormItem>
                          <FormLabel className='text-xl'>
                            Confirm Passsword
                          </FormLabel>
                          <FormControl>
                            <Input
                              type='password'
                              placeholder='Confirm your password'
                              {...field}
                            />
                          </FormControl>
                          <div className='flex w-full flex-col items-center'>
                            <FormMessage className='w-5/6 text-center' />
                          </div>
                        </FormItem>
                      )}
                    />
                    <SubmitButton
                      disabled={loading}
                      pendingText='Signing Up...'
                      className='mx-auto w-2/3 text-xl font-semibold'
                    >
                      Sign Up
                    </SubmitButton>
                  </form>
                </Form>
                <div className='my-auto flex w-2/3 justify-center'>
                  <div className='my-2.5 flex w-1/3 flex-row items-center'>
                    <Separator className='mr-3 py-0.5' />
                    <span className='text-lg font-semibold'>or</span>
                    <Separator className='ml-3 py-0.5' />
                  </div>
                </div>
                <div className='mt-3 flex justify-center'>
                  <GibsAuthSignInButton type='signUp' />
                </div>
              </CardContent>
            </Card>
          </TabsContent>
        </Tabs>
      </Card>
    </div>
  );
};
export default SignIn;
