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

import { zodResolver } from '@hookform/resolvers/zod'
import { AlertCircleIcon } from 'lucide-react'
import { useEffect } from 'react'
import { useForm } from 'react-hook-form'
import { PatternFormat } from 'react-number-format'
import { Link, useFetcher, useOutletContext } from 'react-router'
import { toast } from 'sonner'

import {
  Alert,
  AlertDescription,
  AlertTitle
} from '@repo/ui/components/ui/alert'
import { Button } from '@repo/ui/components/ui/button'
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle
} from '@repo/ui/components/ui/card'
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage
} from '@repo/ui/components/ui/form'
import { Input } from '@repo/ui/components/ui/input'
import { Spinner } from '@repo/ui/components/ui/spinner'
import { type User } from '@repo/ui/routes/users/data'
import { HttpMethod, request as req } from '@repo/util/request'

import { FieldSet } from '@repo/ui/components/ui/field'
import { formSchema, type Schema } from '../_.$orgid.users.add/data'

export async function action({ params, request, context }: Route.ActionArgs) {
  const body = await request.json()
  const r = await req({
    url: `/users/${params.id}`,
    method: HttpMethod.PATCH,
    headers: new Headers({ 'Content-Type': 'application/json' }),
    body: JSON.stringify(body),
    request,
    context
  })

  if (r.ok) {
    return { ok: true }
  }

  return { ok: false, error: await r.json() }
}

export default function Route({}: Route.ComponentProps) {
  const { user } = useOutletContext() as { user: User }
  const fetcher = useFetcher()
  const form = useForm({
    defaultValues: { ...user, given_email: false },
    resolver: zodResolver(formSchema)
  })
  const { handleSubmit, control, formState, setError } = form

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

  useEffect(() => {
    if (fetcher.data?.ok) {
      toast.success('O colaborador(a) foi atualizado(a).')
      return
    }

    switch (fetcher.data?.error?.type) {
      case 'RateLimitExceededError':
        toast.error('Limite diário de atualizações atingido.')
        return
      case 'CPFConflictError':
        setError('cpf', { message: 'CPF já está em uso' })
        return
    }
  }, [fetcher.data, setError])

  return (
    <Form {...form}>
      <form onSubmit={handleSubmit(onSubmit)}>
        <fieldset disabled={!!user?.rate_limit_exceeded} className="space-y-4">
          {user?.rate_limit_exceeded && (
            <Alert variant="destructive">
              <AlertCircleIcon />
              <AlertTitle>Limite diário de atualizações atingido.</AlertTitle>
              <AlertDescription>
                Tente novamente a partir de{' '}
                {getDaysRemaining(user.rate_limit_exceeded.ttl)}
              </AlertDescription>
            </Alert>
          )}

          <Card>
            <CardHeader>
              <CardTitle className="text-2xl">Editar colaborador</CardTitle>
              <CardDescription>
                Configurar as informações gerais para este colaborador.
              </CardDescription>
            </CardHeader>

            <CardContent>
              <FieldSet>
                <FormField
                  control={control}
                  name="name"
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>Nome</FormLabel>
                      <FormControl>
                        <Input {...field} />
                      </FormControl>
                      <FormMessage />
                    </FormItem>
                  )}
                />

                <FormField
                  control={control}
                  name="email"
                  disabled={true}
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>Email</FormLabel>
                      <FormControl>
                        <Input {...field} />
                      </FormControl>
                      <FormLabel className="text-sm font-normal text-muted-foreground">
                        <span>
                          Para gerenciar os emails ou trocar o email principal,
                          use as{' '}
                          <Link
                            to="emails"
                            className="text-blue-400 underline hover:no-underline"
                          >
                            configurações de emails
                          </Link>
                        </span>
                      </FormLabel>
                      <FormMessage />
                    </FormItem>
                  )}
                />

                <FormField
                  control={control}
                  name="cpf"
                  render={({ field: { onChange, ref, ...props } }) => (
                    <FormItem>
                      <FormLabel>CPF</FormLabel>
                      <FormControl>
                        <PatternFormat
                          format="###.###.###-##"
                          mask="_"
                          placeholder="___.___.___-__"
                          customInput={Input}
                          getInputRef={ref}
                          onValueChange={({ value }) => {
                            onChange(value)
                          }}
                          {...props}
                        />
                      </FormControl>
                      <FormMessage />
                    </FormItem>
                  )}
                />

                <div className="flex justify-end">
                  <Button
                    type="submit"
                    className="cursor-pointer"
                    disabled={formState.isSubmitting}
                  >
                    {formState.isSubmitting && <Spinner />}
                    Editar
                  </Button>
                </div>
              </FieldSet>
            </CardContent>
          </Card>
        </fieldset>
      </form>
    </Form>
  )
}

function getDaysRemaining(ttl: number) {
  const date = new Date(ttl * 1000)

  const day = date.toLocaleDateString('pt-BR', {
    day: '2-digit',
    month: '2-digit'
  })

  const time = date.toLocaleTimeString('pt-BR', {
    hour: '2-digit',
    minute: '2-digit'
  })

  return `${day} às ${time}`
}
