import type { Route } from './+types/password'

import { useToggle } from 'ahooks'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { toast } from 'sonner'
import { useFetcher } from 'react-router'
import { useEffect } from 'react'

import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage
} from '@repo/ui/components/ui/form'
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle
} from '@repo/ui/components/ui/card'
import { Input } from '@repo/ui/components/ui/input'
import { Button } from '@repo/ui/components/ui/button'
import { Spinner } from '@repo/ui/components/ui/spinner'
import { Checkbox } from '@repo/ui/components/ui/checkbox'
import { Label } from '@repo/ui/components/ui/label'
import { request as req, HttpMethod } from '@repo/util/request'
import { userContext } from '@repo/auth/context'
import type { User } from '@repo/auth/auth'

const formSchema = z
  .object({
    new_password: z.string().min(6, 'Deve ter no mínimo 6 caracteres'),
    confirm_password: z.string().min(6, 'Deve ter no mínimo 6 caracteres')
  })
  .refine((data) => data.new_password === data.confirm_password, {
    message: 'As senhas não coincidem',
    path: ['confirm_password']
  })

type Schema = z.infer<typeof formSchema>

export async function action({ request, context }: Route.ActionArgs) {
  const user = context.get(userContext) as User
  const body = await request.json()
  const r = await req({
    url: `users/${user.sub}/password`,
    headers: new Headers({ 'Content-Type': 'application/json' }),
    method: HttpMethod.POST,
    body: JSON.stringify(body),
    request,
    context
  })

  if (!r.ok) {
    const error = await r.json().catch(() => ({}))
    return { ok: false, error }
  }

  return { ok: true }
}

export default function Route({}: Route.ComponentProps) {
  const [show, { toggle }] = useToggle()
  const inputType = show ? 'text' : 'password'
  const fetcher = useFetcher()
  const form = useForm({
    resolver: zodResolver(formSchema)
  })
  const { control, formState, handleSubmit, reset } = form

  const onSubmit = async ({ new_password }: Schema) => {
    await fetcher.submit(JSON.stringify({ new_password }), {
      method: 'post',
      encType: 'application/json'
    })
  }

  useEffect(() => {
    if (fetcher.data?.ok) {
      toast.success('A senha foi alterada')
      return reset()
    }

    switch (fetcher.data?.error?.type) {
      case 'UserConflictError':
        toast.error('O colaborador já foi vinculado anteriormente')
    }
  }, [fetcher.data, reset])

  return (
    <Form {...form}>
      <form onSubmit={handleSubmit(onSubmit)} className="space-y-2.5">
        <Card>
          <CardHeader>
            <CardTitle className="text-lg">Alterar senha</CardTitle>
            <CardDescription>
              Sua senha deve ter no mínimo 6 caracteres. Recomendamos que inclua
              uma combinação de números, letras e caracteres especiais (ex.:
              !$@%).
            </CardDescription>
          </CardHeader>

          <CardContent className="space-y-2.5">
            <FormField
              control={control}
              name="new_password"
              defaultValue=""
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Nova senha</FormLabel>
                  <FormControl>
                    <Input type={inputType} autoComplete="false" {...field} />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />

            <FormField
              control={control}
              name="confirm_password"
              defaultValue=""
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Confirmar nova senha</FormLabel>
                  <FormControl>
                    <Input type={inputType} autoComplete="false" {...field} />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />

            <div className="flex items-center gap-3">
              <Checkbox id="showPassword" onClick={toggle} tabIndex={-1} />
              <Label htmlFor="showPassword" className="cursor-pointer">
                Mostrar senha
              </Label>
            </div>
          </CardContent>
        </Card>

        <div className="flex justify-end">
          <Button
            type="submit"
            className="relative overflow-hidden cursor-pointer"
          >
            {formState.isSubmitting && (
              <div className="absolute inset-0 bg-lime-500 flex items-center justify-center">
                <Spinner />
              </div>
            )}
            Alterar senha
          </Button>
        </div>
      </form>
    </Form>
  )
}
