import { Fragment } from 'react'
import { MinusIcon, PlusIcon, Trash2Icon, XIcon } from 'lucide-react'
import {
  useForm,
  useFieldArray,
  Controller,
  useWatch,
  type UseFormSetValue
} from 'react-hook-form'
import { ErrorMessage } from '@hookform/error-message'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'

import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupInput
} from '@repo/ui/components/ui/input-group'
import { Form } from '@repo/ui/components/ui/form'
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 { Kbd } from '@repo/ui/components/ui/kbd'
import { Abbr } from '@repo/ui/components/abbr'

import { Cell } from '../_.$orgid.enrollments.add/route'
import { CoursePicker } from '../_.$orgid.enrollments.add/course-picker'
import { MAX_ITEMS, type Course } from '../_.$orgid.enrollments.add/data'
import { Discount, applyDiscount } from './discount'
import { currency } from './utils'

const emptyRow = {
  course: undefined
}

type BulkProps = {
  onSubmit: (value: any) => void | Promise<void>
  courses: Promise<{ hits: Course[] }>
}

const item = z.object({
  course: z
    .object(
      {
        id: z.string(),
        name: z.string(),
        access_period: z.number(),
        unit_price: z.number()
      },
      { error: 'Escolha um curso' }
    )
    .required(),
  quantity: z.number().min(1)
})

const formSchema = z.object({
  items: z.array(item).min(1).max(MAX_ITEMS),
  coupon: z
    .object({
      code: z.string(),
      type: z.enum(['FIXED', 'PERCENT']),
      amount: z.number().positive()
    })
    .optional()
})

type Schema = z.infer<typeof formSchema>

export function Bulk({ courses, onSubmit }: BulkProps) {
  const form = useForm({
    resolver: zodResolver(formSchema),
    defaultValues: { items: [emptyRow] }
  })
  const {
    formState,
    control,
    handleSubmit,
    register,
    setValue,
    getValues,
    setFocus
  } = form
  const { fields, remove, append } = useFieldArray({
    control,
    name: 'items'
  })
  const items = useWatch({
    control,
    name: 'items'
  })
  const coupon = useWatch({ control, name: 'coupon' })
  const subtotal = items.reduce(
    (acc, { course, quantity }) =>
      acc +
      (course?.unit_price || 0) *
        (Number.isFinite(quantity) && quantity > 0 ? quantity : 1),
    0
  )
  const discount = coupon
    ? applyDiscount(subtotal, coupon.amount, coupon.type) * -1
    : 0
  const total = subtotal > 0 ? subtotal + discount : 0

  const onSubmit_ = async (data: Schema) => {
    await onSubmit(data)
  }

  return (
    <Form {...form}>
      <form onSubmit={handleSubmit(onSubmit_)} className="space-y-4">
        <div className="grid w-full gap-1.5 lg:grid-cols-[4fr_2fr_2fr_2fr_auto]">
          {/* Header */}
          <>
            <Cell>Curso</Cell>
            <Cell>Quantidade</Cell>
            <Cell>Valor unit.</Cell>
            <Cell>Total</Cell>
            <Cell>{/**/}</Cell>
          </>

          {/* Rows */}
          {fields.map((field, index) => {
            const item = items?.[index] || { course: {}, quantity: 1 }
            const { course, quantity } = item

            return (
              <Fragment key={field.id}>
                {/* Separator only for mobile */}
                {index >= 1 && <div className="h-2.5 lg:hidden"></div>}

                {/* Course */}
                <Controller
                  control={control}
                  name={`items.${index}.course`}
                  render={({
                    field: { name, value, onChange, ref },
                    fieldState
                  }) => (
                    <div className="grid gap-1">
                      <CoursePicker
                        ref={ref}
                        name={name}
                        autoFocus={index === 0}
                        value={value}
                        onChange={onChange}
                        options={courses}
                        error={fieldState.error}
                        readOnly
                      />

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

                {/* Quantity */}
                <InputGroup>
                  <InputGroupAddon className="border-r pr-2.5 w-1/3 lg:hidden justify-end">
                    Qtd.
                  </InputGroupAddon>

                  <InputGroupInput
                    type="number"
                    min={1}
                    defaultValue={1}
                    className="no-spinner"
                    {...register(`items.${index}.quantity`, {
                      valueAsNumber: true,
                      onBlur: (e) => {
                        const value = Number(e.target.value)

                        if (!value || value < 1) {
                          setValue(`items.${index}.quantity`, 1)
                        }
                      }
                    })}
                  />

                  <InputGroupAddon align="inline-end">
                    <InputGroupButton
                      type="button"
                      tabIndex={-1}
                      size="icon-xs"
                      className="border cursor-pointer"
                      onClick={() => {
                        const quantity =
                          getValues(`items.${index}.quantity`) || 1
                        setValue(
                          `items.${index}.quantity`,
                          Math.max(1, quantity - 1)
                        )
                      }}
                    >
                      <MinusIcon />
                    </InputGroupButton>
                  </InputGroupAddon>

                  <InputGroupAddon align="inline-end">
                    <InputGroupButton
                      type="button"
                      tabIndex={-1}
                      size="icon-xs"
                      className="border cursor-pointer"
                      onClick={() => {
                        const quantity =
                          getValues(`items.${index}.quantity`) || 1
                        setValue(`items.${index}.quantity`, quantity + 1)
                      }}
                    >
                      <PlusIcon />
                    </InputGroupButton>
                  </InputGroupAddon>
                </InputGroup>

                {/* Unit price */}
                <InputGroup>
                  <InputGroupAddon className="border-r pr-2.5 w-1/3 lg:hidden justify-end">
                    Valor unit.
                  </InputGroupAddon>
                  <InputGroupInput
                    tabIndex={-1}
                    className="pointer-events-none"
                    readOnly
                    value={currency(course?.unit_price || 0)}
                  />
                </InputGroup>

                {/* Total */}
                <InputGroup>
                  <InputGroupAddon className="border-r pr-2.5 w-1/3 lg:hidden justify-end">
                    Total
                  </InputGroupAddon>

                  <InputGroupInput
                    tabIndex={-1}
                    className="pointer-events-none"
                    readOnly
                    value={currency(
                      (course?.unit_price || 0) *
                        (Number.isFinite(quantity) && quantity > 0
                          ? quantity
                          : 1)
                    )}
                  />
                </InputGroup>

                {/* Action */}
                <Button
                  tabIndex={-1}
                  variant="destructive"
                  className="cursor-pointer"
                  disabled={fields.length == 1}
                  onClick={() => remove(index)}
                >
                  <Trash2Icon />
                </Button>
              </Fragment>
            )
          })}

          {/* Add button */}
          <div className="max-lg:mb-2.5">
            <Button
              type="button"
              onClick={() => {
                // @ts-ignore
                append(emptyRow, { shouldFocus: false })
                queueMicrotask(() => {
                  setFocus(`items.${fields.length}.course`)
                })
              }}
              className="cursor-pointer"
              variant="outline"
              size="sm"
            >
              <PlusIcon /> Adicionar
            </Button>
          </div>

          <Summary {...{ total, subtotal, discount, coupon, setValue }} />
        </div>

        <Separator />

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

type SummaryProps = {
  subtotal: number
  total: number
  discount: number
  coupon?: {
    code: string
    type: 'FIXED' | 'PERCENT'
    amount: number
  }
  setValue: UseFormSetValue<Schema>
}

export function Summary({
  subtotal,
  total,
  discount,
  coupon,
  setValue
}: SummaryProps) {
  return (
    <>
      {/* Subtotal */}
      <>
        <div className="col-start-3 flex items-center justify-end text-sm font-medium max-lg:hidden">
          Subtotal
        </div>

        <InputGroup>
          <InputGroupAddon className="border-r pr-2.5 w-1/3 lg:hidden justify-end">
            Subtotal
          </InputGroupAddon>
          <InputGroupInput
            tabIndex={-1}
            name="subtotal"
            value={currency(subtotal)}
            className="pointer-events-none text-muted-foreground"
            readOnly
          />
        </InputGroup>
      </>

      {/* Discount */}
      <>
        <div className="col-start-3 flex items-center justify-end text-sm font-medium max-lg:hidden">
          {coupon ? (
            <span className="flex gap-1">
              Descontos
              <Kbd>
                <Abbr maxLen={8}>{coupon.code}</Abbr>
              </Kbd>
            </span>
          ) : (
            <>Cupom</>
          )}
        </div>

        <InputGroup>
          <InputGroupAddon className="border-r pr-2.5 w-1/3 lg:hidden justify-end">
            {coupon ? <>Descontos</> : <>Cupom</>}
          </InputGroupAddon>

          <InputGroupInput
            name="discount"
            value={currency(discount)}
            tabIndex={-1}
            className="pointer-events-none text-muted-foreground"
            readOnly
          />

          <InputGroupAddon align="inline-end">
            {coupon ? (
              <InputGroupButton
                size="icon-xs"
                className="cursor-pointer"
                tabIndex={-1}
                variant="ghost"
                onClick={() => {
                  setValue('coupon', undefined)
                }}
              >
                <XIcon />
              </InputGroupButton>
            ) : (
              <Discount
                disabled={subtotal === 0}
                onChange={({ sk, discount_amount, discount_type }) => {
                  setValue('coupon', {
                    code: sk,
                    amount: discount_amount,
                    type: discount_type
                  })
                }}
              />
            )}
          </InputGroupAddon>
        </InputGroup>
      </>

      {/* Total */}
      <>
        <div className="col-start-3 flex items-center justify-end text-sm font-medium max-lg:hidden">
          Total
        </div>
        <InputGroup>
          <InputGroupAddon className="border-r pr-2.5 w-1/3 lg:hidden justify-end">
            Total
          </InputGroupAddon>
          <InputGroupInput
            name="total"
            tabIndex={-1}
            value={currency(total)}
            className="pointer-events-none text-muted-foreground"
            readOnly
          />
        </InputGroup>
      </>
    </>
  )
}
