import { useRequest, useToggle } from 'ahooks'
import { PatternFormat } from 'react-number-format'
import { ExternalLinkIcon, PencilIcon, SearchIcon } from 'lucide-react'
import { Controller, useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import valid from 'card-validator'

import { Currency } from '@repo/ui/components/currency'
import { Button } from '@repo/ui/components/ui/button'
import { Separator } from '@repo/ui/components/ui/separator'
import { Spinner } from '@repo/ui/components/ui/spinner'
import {
  Table,
  TableBody,
  TableCell,
  TableFooter,
  TableHead,
  TableHeader,
  TableRow
} from '@repo/ui/components/ui/table'
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemTitle
} from '@repo/ui/components/ui/item'
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger
} from '@repo/ui/components/ui/dialog'

import { useWizard } from '@/components/wizard'
import { type WizardState } from './route'
import { applyDiscount } from './discount'
import { paymentMethods } from '@repo/ui/routes/orders/data'
import {
  Field,
  FieldDescription,
  FieldError,
  FieldGroup,
  FieldLabel,
  FieldSet
} from '@repo/ui/components/ui/field'
import { Input } from '@repo/ui/components/ui/input'
import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupInput
} from '@repo/ui/components/ui/input-group'

type ReviewProps = {
  state: WizardState
  onSubmit: (value: WizardState) => void | Promise<void>
}

export function Review({ state, onSubmit }: ReviewProps) {
  const wizard = useWizard()
  const [loading, { set }] = useToggle()
  const { coupon, items } = state || { items: [], coupon: {} }
  const subtotal =
    items?.reduce(
      (acc, { course, quantity }) =>
        acc +
        (course?.unit_price || 0) *
          (Number.isFinite(quantity) && quantity > 0 ? quantity : 1),
      0
    ) || 0
  const discount = coupon
    ? applyDiscount(subtotal, coupon.amount, coupon.type) * -1
    : 0
  const total = subtotal > 0 ? subtotal + discount : 0

  return (
    <>
      <Address total={total} {...state} />

      <form
        onSubmit={async (e) => {
          e.preventDefault()
          set(true)
          await onSubmit(state)
        }}
        className="space-y-4"
      >
        <Table className="pointer-events-none">
          <TableHeader>
            <TableRow>
              <TableHead>Curso</TableHead>
              <TableHead>Quantidade</TableHead>
              <TableHead>Valor unit.</TableHead>
              <TableHead>Total</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {items?.map(({ course, quantity }, index) => {
              return (
                <TableRow key={index}>
                  <TableCell>{course.name}</TableCell>
                  <TableCell>{quantity}</TableCell>
                  <TableCell>
                    <Currency>{course.unit_price}</Currency>
                  </TableCell>
                  <TableCell>
                    <Currency>{course.unit_price * quantity}</Currency>
                  </TableCell>
                </TableRow>
              )
            })}
          </TableBody>
          <TableFooter>
            <TableRow>
              <TableCell className="text-right" colSpan={3}>
                Subtotal
              </TableCell>
              <TableCell>
                <Currency>{subtotal}</Currency>
              </TableCell>
            </TableRow>
            <TableRow>
              <TableCell className="text-right" colSpan={3}>
                Descontos
              </TableCell>
              <TableCell>
                <Currency>{discount}</Currency>
              </TableCell>
            </TableRow>
            <TableRow>
              <TableCell className="text-right" colSpan={3}>
                Total
              </TableCell>
              <TableCell>
                <Currency>{total}</Currency>
              </TableCell>
            </TableRow>
          </TableFooter>
        </Table>

        <Separator />

        <div className="flex justify-between gap-4 *:cursor-pointer">
          <Button
            type="button"
            variant="link"
            className="text-black dark:text-white"
            onClick={() => wizard('payment')}
            tabIndex={-1}
          >
            Voltar
          </Button>

          <Button type="submit" disabled={loading}>
            {loading && <Spinner />}
            Pagar <Currency>{total}</Currency>
          </Button>
        </div>
      </form>
    </>
  )
}

export function Address({
  total,
  payment_method,
  credit_card
}: WizardState & { total: number }) {
  const numberValidation = valid.number(credit_card?.number)

  return (
    <ItemGroup className="grid lg:grid-cols-2 gap-4">
      <Item variant="outline" className="items-start">
        <ItemContent>
          <ItemTitle>Endereço de cobrança</ItemTitle>
          <ul className="text-muted-foreground text-sm leading-normal font-normal text-balance">
            Rua Monsenhor Ivo Zanlorenzi, nº 5190, ap 1802
            <br />
            Cidade Industrial
            <br />
            Curitiba, Paraná
            <br />
            81280-350
          </ul>
        </ItemContent>
        <ItemActions>
          <AddressDialog />
        </ItemActions>
      </Item>

      <Item variant="outline" className="items-start">
        <ItemContent>
          <ItemTitle>Forma de pagamento</ItemTitle>
          <ItemDescription>
            {credit_card ? (
              <>
                {numberValidation.card?.niceType} (Crédito) ****{' '}
                {credit_card.number.slice(-4)}
                <br />
                1x <Currency>{total}</Currency>
              </>
            ) : (
              <>
                {payment_method
                  ? paymentMethods[payment_method]
                  : payment_method}
              </>
            )}
          </ItemDescription>
        </ItemContent>
      </Item>
    </ItemGroup>
  )
}

const formSchema = z.object({
  postcode: z.string().min(1, 'Digite um CEP'),
  address1: z.string().min(1, 'Digite um endereço'),
  address2: z.string().optional(),
  neighborhood: z.string().min(1, 'Digite o bairro'),
  city: z.string().min(1, 'Digite a cidade'),
  state: z.string().min(1, 'Digite o estado')
})

type Address = z.infer<typeof formSchema>

export function AddressDialog() {
  const [open, { toggle, set }] = useToggle()
  const { handleSubmit, control, reset } = useForm({
    resolver: zodResolver(formSchema)
  })

  const onSubmit = async (data: Address) => {
    set(false)
    console.log(data)
  }

  return (
    <Dialog open={open} onOpenChange={toggle}>
      <DialogTrigger asChild>
        <Button
          variant="ghost"
          type="button"
          className="text-muted-foreground cursor-pointer"
          size="icon-sm"
        >
          <PencilIcon />
          <span className="sr-only">Editar endereço</span>
        </Button>
      </DialogTrigger>
      <DialogContent className="sm:max-w-[425px]">
        <DialogHeader>
          <DialogTitle>Editar endereço</DialogTitle>
          <DialogDescription>
            Este endereço será utilizado para a emissão da NFS-e.
          </DialogDescription>
        </DialogHeader>

        <PostcodeForm onChange={reset} />

        <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
          <FieldGroup>
            <FieldSet>
              <Controller
                control={control}
                name="address1"
                defaultValue=""
                render={({ field, fieldState }) => (
                  <Field data-invalid={fieldState.invalid}>
                    <FieldLabel htmlFor={field.name}>Endereço</FieldLabel>
                    <Input
                      id={field.name}
                      aria-invalid={fieldState.invalid}
                      {...field}
                    />

                    {fieldState.invalid && (
                      <FieldError errors={[fieldState.error]} />
                    )}
                  </Field>
                )}
              />

              <Controller
                control={control}
                name="address2"
                defaultValue=""
                render={({ field, fieldState }) => (
                  <Field data-invalid={fieldState.invalid}>
                    <FieldLabel htmlFor={field.name}>
                      Complemento{' '}
                      <span className="text-muted-foreground">(opcional)</span>
                    </FieldLabel>
                    <Input
                      id={field.name}
                      aria-invalid={fieldState.invalid}
                      {...field}
                    />

                    {fieldState.invalid && (
                      <FieldError errors={[fieldState.error]} />
                    )}
                  </Field>
                )}
              />
            </FieldSet>

            <FieldSet className="grid grid-cols-3">
              {/* Neighborhood */}
              <Controller
                control={control}
                name="neighborhood"
                defaultValue=""
                render={({ field, fieldState }) => (
                  <Field data-invalid={fieldState.invalid}>
                    <FieldLabel htmlFor={field.name}>Bairro</FieldLabel>
                    <Input
                      id={field.name}
                      aria-invalid={fieldState.invalid}
                      {...field}
                    />

                    {fieldState.invalid && (
                      <FieldError errors={[fieldState.error]} />
                    )}
                  </Field>
                )}
              />
              {/* City */}
              <Controller
                control={control}
                name="city"
                defaultValue=""
                render={({ field, fieldState }) => (
                  <Field data-invalid={fieldState.invalid}>
                    <FieldLabel htmlFor={field.name}>Cidade</FieldLabel>
                    <Input
                      id={field.name}
                      aria-invalid={fieldState.invalid}
                      {...field}
                    />

                    {fieldState.invalid && (
                      <FieldError errors={[fieldState.error]} />
                    )}
                  </Field>
                )}
              />
              {/* State */}
              <Controller
                control={control}
                name="state"
                defaultValue=""
                render={({ field, fieldState }) => (
                  <Field data-invalid={fieldState.invalid}>
                    <FieldLabel htmlFor={field.name}>Estado</FieldLabel>
                    <Input
                      id={field.name}
                      aria-invalid={fieldState.invalid}
                      {...field}
                    />

                    {fieldState.invalid && (
                      <FieldError errors={[fieldState.error]} />
                    )}
                  </Field>
                )}
              />
            </FieldSet>
          </FieldGroup>

          <DialogFooter className="*:cursor-pointer">
            <DialogClose asChild>
              <Button
                variant="link"
                type="button"
                tabIndex={-1}
                className="text-black dark:text-white"
              >
                Cancel
              </Button>
            </DialogClose>

            <Button type="submit">Atualizar endereço</Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  )
}

type PostcodeFormProps = {
  onChange: (value: Address) => void
}

function PostcodeForm({ onChange }: PostcodeFormProps) {
  const formSchema = z.object({
    postcode: z.string().min(1, 'Digite um CEP')
  })

  type Schema = z.infer<typeof formSchema>

  const { control, handleSubmit, setError } = useForm({
    resolver: zodResolver(formSchema)
  })

  const { runAsync, loading } = useRequest(
    async (cep: string) => {
      return await fetch(`/~/api/cep/${cep}.json`)
    },
    { manual: true }
  )

  const onSubmit = async ({ postcode }: Schema) => {
    const r = await runAsync(postcode)

    if (r.ok) {
      onChange?.((await r.json()) as Address)
      return
    }

    setError('postcode', { message: 'CEP não encontrado' })
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <FieldGroup>
        <Controller
          control={control}
          name="postcode"
          defaultValue=""
          render={({ field: { onChange, ref, ...field }, fieldState }) => (
            <Field data-invalid={fieldState.invalid}>
              {/* CEP */}
              <FieldLabel htmlFor={field.name}>CEP</FieldLabel>
              <InputGroup>
                <PatternFormat
                  id={field.name}
                  format="#####-###"
                  mask="_"
                  placeholder="_____-___"
                  customInput={InputGroupInput}
                  getInputRef={ref}
                  aria-invalid={fieldState.invalid}
                  onValueChange={({ value }) => {
                    onChange(value)
                  }}
                  {...field}
                />
                <InputGroupAddon align="inline-end">
                  <InputGroupButton
                    type="submit"
                    variant="secondary"
                    className="cursor-pointer"
                  >
                    {loading ? <Spinner /> : <SearchIcon />}
                  </InputGroupButton>
                </InputGroupAddon>
              </InputGroup>

              {fieldState.invalid && <FieldError errors={[fieldState.error]} />}

              <FieldDescription>
                <a
                  href="https://buscacepinter.correios.com.br/app/endereco/index.php"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="inline-flex gap-1 items-center "
                  tabIndex={-1}
                >
                  Não sei o CEP <ExternalLinkIcon className="size-4" />
                </a>
              </FieldDescription>
            </Field>
          )}
        />
      </FieldGroup>
    </form>
  )
}
