import { useForm, Controller, useWatch, type Control } from 'react-hook-form'
import { PatternFormat } from 'react-number-format'
import { zodResolver } from '@hookform/resolvers/zod'
import { ErrorMessage } from '@hookform/error-message'
import { z } from 'zod'
import { ArrowRightIcon, CircleQuestionMarkIcon } from 'lucide-react'
import valid from 'card-validator'

import { Button } from '@repo/ui/components/ui/button'
import { Kbd } from '@repo/ui/components/ui/kbd'
import { Label } from '@repo/ui/components/ui/label'
import { RadioGroup, RadioGroupItem } from '@repo/ui/components/ui/radio-group'
import { Separator } from '@repo/ui/components/ui/separator'
import { Input } from '@repo/ui/components/ui/input'
import { Card, CardContent } from '@repo/ui/components/ui/card'
import {
  HoverCard,
  HoverCardContent,
  HoverCardTrigger
} from '@repo/ui/components/ui/hover-card'
import {
  Field,
  FieldError,
  FieldGroup,
  FieldLabel,
  FieldSet
} from '@repo/ui/components/ui/field'
import {
  NativeSelect,
  NativeSelectOption
} from '@repo/ui/components/ui/native-select'
import { Currency } from '@repo/ui/components/currency'

import { useWizard } from '@/components/wizard'
import { isName } from '../_.$orgid.users.add/data'
import { applyDiscount } from './discount'
import { useWizardStore } from './store'

const creditCard = z.object({
  holder_name: z
    .string()
    .trim()
    .nonempty('Digite um nome')
    .refine(isName, { message: 'Nome inválido' }),
  number: z.string().refine(
    (value) => {
      const numberValidation = valid.number(value)
      return numberValidation.isValid
    },
    { error: 'Número do cartão inválido' }
  ),
  exp_month: z.string().min(2),
  exp_year: z.string().min(4),
  cvv: z.string().min(3).max(4)
})

const formSchema = z.discriminatedUnion(
  'payment_method',
  [
    z.object({
      payment_method: z.literal('PIX')
    }),

    z.object({
      payment_method: z.literal('BANK_SLIP')
    }),

    z.object({
      payment_method: z.literal('MANUAL')
    }),

    z.object({
      payment_method: z.literal('CREDIT_CARD'),
      credit_card: creditCard,
      installments: z.coerce.number().int().min(1).max(12)
    })
  ],
  { error: 'Escolha uma forma de pagamento' }
)

type Schema = z.input<typeof formSchema>

export type CreditCard = z.infer<typeof creditCard>

export function Payment({}) {
  const wizard = useWizard()
  const { update, summary, ...state } = useWizardStore()
  const { subtotal, discount } = summary()
  const { control, handleSubmit } = useForm<Schema>({
    defaultValues: {
      payment_method: state.payment_method,
      installments: state.installments,
      credit_card: state.credit_card
    },
    resolver: zodResolver(formSchema)
  })
  const paymentMethod = useWatch({ control, name: 'payment_method' })

  const onSubmit = async ({ payment_method, ...data }: Schema) => {
    if (payment_method === 'CREDIT_CARD') {
      // @ts-ignore
      update({ payment_method, ...data })
    } else {
      update({
        payment_method,
        installments: undefined,
        credit_card: undefined
      })
    }

    wizard('review')
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
      <Controller
        name="payment_method"
        control={control}
        // @ts-ignore
        defaultValue=""
        render={({ field: { name, value, onChange }, formState }) => (
          <div className="space-y-1.5">
            <RadioGroup
              value={value}
              onValueChange={onChange}
              className="lg:flex gap-3
                         *:p-5 *:border *:rounded-xl *:flex-1
                         *:cursor-pointer *:bg-accent/25
                         *:has-[button[data-state=checked]]:bg-accent"
            >
              <Label>
                <RadioGroupItem value="PIX" />
                <span>Pix</span>
              </Label>

              <Label>
                <RadioGroupItem value="BANK_SLIP" />
                <span>Boleto bancário</span>
              </Label>

              <Label>
                <RadioGroupItem value="CREDIT_CARD" />
                <span>Cartão de crédito</span>
              </Label>
            </RadioGroup>

            <ErrorMessage
              errors={formState.errors}
              name={name}
              render={({ message }) => (
                <p className="text-destructive text-sm">{message}</p>
              )}
            />
          </div>
        )}
      />

      {paymentMethod === 'CREDIT_CARD' ? (
        <CreditCard control={control} total={subtotal + discount} />
      ) : null}

      <Separator />

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

        <Button type="submit" variant="secondary">
          Continuar <ArrowRightIcon />
        </Button>
      </div>
    </form>
  )
}

export function CreditCard({
  total,
  control
}: {
  total: number
  control: Control<Schema>
}) {
  const currentYear = new Date().getFullYear()
  const years = Array.from({ length: 10 }, (_, i) => currentYear + i)

  return (
    <Card className="lg:w-1/2">
      <CardContent>
        <FieldGroup>
          <FieldSet>
            {/* Credir card number */}
            <Controller
              control={control}
              defaultValue=""
              name="credit_card.number"
              render={({ field: { onChange, ref, ...field }, fieldState }) => (
                <Field data-invalid={fieldState.invalid}>
                  <FieldLabel htmlFor={field.name}>Número do cartão</FieldLabel>
                  <PatternFormat
                    id={field.name}
                    format="#### #### #### ####"
                    mask="_"
                    placeholder="•••• •••• •••• ••••"
                    customInput={Input}
                    getInputRef={ref}
                    aria-invalid={fieldState.invalid}
                    onValueChange={({ value }) => {
                      onChange(value)
                    }}
                    {...field}
                  />

                  {fieldState.invalid && (
                    <FieldError errors={[fieldState.error]} />
                  )}
                </Field>
              )}
            />
            {/* Holder name */}
            <Controller
              control={control}
              name="credit_card.holder_name"
              defaultValue=""
              render={({ field, fieldState }) => (
                <Field data-invalid={fieldState.invalid}>
                  <FieldLabel htmlFor={field.name}>Nome do titular</FieldLabel>
                  <Input
                    id={field.name}
                    aria-invalid={fieldState.invalid}
                    {...field}
                  />
                  {fieldState.invalid && (
                    <FieldError errors={[fieldState.error]} />
                  )}
                </Field>
              )}
            />

            <FieldSet className="grid grid-cols-3 gap-4">
              <Controller
                control={control}
                name="credit_card.exp_month"
                defaultValue=""
                render={({ field, fieldState }) => (
                  <Field data-invalid={fieldState.invalid}>
                    <FieldLabel htmlFor={field.name}>Mês</FieldLabel>
                    <NativeSelect
                      id={field.name}
                      value={field.value}
                      onChange={field.onChange}
                      aria-invalid={fieldState.invalid}
                    >
                      <NativeSelectOption value="" disabled>
                        Selecione
                      </NativeSelectOption>

                      {Array.from({ length: 12 }, (_, i) => {
                        const v = String(i + 1).padStart(2, '0')
                        return (
                          <NativeSelectOption key={v} value={v}>
                            {v}
                          </NativeSelectOption>
                        )
                      })}
                    </NativeSelect>
                  </Field>
                )}
              />

              <Controller
                control={control}
                name="credit_card.exp_year"
                defaultValue=""
                render={({ field, fieldState }) => (
                  <Field data-invalid={fieldState.invalid}>
                    <FieldLabel htmlFor={field.name}>Ano</FieldLabel>
                    <NativeSelect
                      id={field.name}
                      value={field.value}
                      onChange={field.onChange}
                      aria-invalid={fieldState.invalid}
                    >
                      <NativeSelectOption value="" disabled>
                        Selecione
                      </NativeSelectOption>

                      {years.map((year) => (
                        <NativeSelectOption key={year} value={String(year)}>
                          {year}
                        </NativeSelectOption>
                      ))}
                    </NativeSelect>
                  </Field>
                )}
              />

              <Controller
                control={control}
                name="credit_card.cvv"
                defaultValue=""
                render={({ field, fieldState }) => (
                  <Field data-invalid={fieldState.invalid}>
                    <FieldLabel htmlFor={field.name}>
                      CVC
                      <HoverCard openDelay={0}>
                        <HoverCardTrigger asChild>
                          <button type="button" tabIndex={-1}>
                            <CircleQuestionMarkIcon className="size-4 text-muted-foreground" />
                          </button>
                        </HoverCardTrigger>
                        <HoverCardContent
                          align="end"
                          className="text-sm space-y-1.5 lg:w-78"
                        >
                          <p>
                            O <Kbd>CVC</Kbd> é o código de segurança do cartão
                            de crédito.
                          </p>

                          <p>
                            Ele fica no verso do cartão e geralmente possui{' '}
                            <Kbd>3 dígitos</Kbd> (ou <Kbd>4 dígitos</Kbd> na
                            frente, no caso do American Express).
                          </p>
                        </HoverCardContent>
                      </HoverCard>
                    </FieldLabel>
                    <Input
                      id={field.name}
                      aria-invalid={fieldState.invalid}
                      {...field}
                    />
                  </Field>
                )}
              />
            </FieldSet>

            <Controller
              control={control}
              name="installments"
              defaultValue={1}
              render={({ field, fieldState }) => (
                <Field data-invalid={fieldState.invalid}>
                  <FieldLabel htmlFor={field.name}>Parcelas</FieldLabel>
                  <NativeSelect
                    id={field.name}
                    value={String(field.value)}
                    onChange={field.onChange}
                    aria-invalid={fieldState.invalid}
                  >
                    {Array.from({ length: 12 }, (_, index) => {
                      const installment = index + 1 // 1 -> 12

                      if (installment === 1) {
                        return (
                          <NativeSelectOption key={installment} value={1}>
                            <Currency>{total}</Currency> à vista
                          </NativeSelectOption>
                        )
                      }

                      const value =
                        installment > 1
                          ? calcInterest(total, installment) / installment
                          : total

                      return (
                        <NativeSelectOption
                          key={installment}
                          value={installment}
                        >
                          {installment}x <Currency>{value}</Currency> com juros
                        </NativeSelectOption>
                      )
                    })}
                  </NativeSelect>
                </Field>
              )}
            />
          </FieldSet>
        </FieldGroup>
      </CardContent>
    </Card>
  )
}

export const calcInterest = (total: number, installment: number) => {
  const rate2to6 = 0.055
  const rate7to12 = 0.0608
  const rate = installment >= 7 ? rate7to12 : rate2to6

  return total * ((1 - 0.0382) / (1 - rate))
}
