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

import { formatCEP } from '@brazilian-utils/brazilian-utils'
import { zodResolver } from '@hookform/resolvers/zod'
import { useRequest, useToggle } from 'ahooks'
import {
  AlertCircleIcon,
  ArrowLeftRightIcon,
  CircleCheckIcon,
  CircleXIcon,
  EllipsisIcon,
  ExternalLinkIcon,
  HelpCircleIcon
} from 'lucide-react'
import { useEffect } from 'react'
import { useForm } from 'react-hook-form'
import { Link, useRevalidator } from 'react-router'
import { z } from 'zod'

import { Abbr } from '@repo/ui/components/abbr'
import { Currency } from '@repo/ui/components/currency'
import { DateTime } from '@repo/ui/components/datetime'
import { Badge } from '@repo/ui/components/ui/badge'
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator
} from '@repo/ui/components/ui/breadcrumb'
import { Button } from '@repo/ui/components/ui/button'
import {
  Card,
  CardContent,
  CardHeader,
  CardTitle
} from '@repo/ui/components/ui/card'
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger
} from '@repo/ui/components/ui/dialog'
import {
  Item,
  ItemActions,
  ItemContent,
  ItemGroup,
  ItemTitle
} from '@repo/ui/components/ui/item'
import { Kbd } from '@repo/ui/components/ui/kbd'
import {
  Popover,
  PopoverContent,
  PopoverTrigger
} from '@repo/ui/components/ui/popover'
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 { cn } from '@repo/ui/lib/utils'
import {
  labels,
  statuses,
  type Order as Order_
} from '@repo/ui/routes/orders/data'
import { request as req } from '@repo/util/request'
import {
  CreditCard,
  creditCardSchema,
  type CreditCard as CreditCardProps
} from '../_.$orgid.enrollments.buy/payment'
import type { Address } from '../_.$orgid.enrollments.buy/review'
import { useWizardStore } from '../_.$orgid.enrollments.buy/store'
import { Enrollments } from './enrollments'

export function meta() {
  return [
    {
      title: 'Detalhes do pagamento'
    }
  ]
}

const PaymentMethodComponent = {
  PIX: PixPaymentMethod,
  BANK_SLIP: BankSlipPaymentMethod,
  CREDIT_CARD: CreditCardPaymentMethod
}

type Item = {
  id: string
  name: string
  unit_price: number
  quantity: number
}

type User = {
  id: string
  name: string
}

type Invoice = {
  invoice_id: string
  secure_url: string
  bank_slip?: {
    bank_slip_pdf_url: string
  }
  pix?: {
    qrcode: string
    qrcode_text: string
  }
}

type Attempts = {
  sk: string
  status: string
  brand: string
  last4: string
}

type Course = {
  id: string
  name: string
}

export type Enrollment = {
  status: 'PENDING' | 'EXECUTED' | 'ROLLBACK'
  user: { id: string; name: string; email: string }
  course: Course
  executed_at?: string
  rollback_at?: string
  scheduled_at?: string
}

export type Seat = {
  course: Course
}

type Order = Order_ & {
  items: Item[]
  interest_amount: number
  due_date: string
  created_at: string
  subtotal: number
  discount: number
  address: Address
  payment_attempts: Attempts[]
  credit_card?: CreditCardProps
  coupon?: string
  enrollments?: Enrollment[]
  seats?: Seat[]
  installments?: number
  created_by?: User
  invoice: Invoice
}

export async function loader({ context, request, params }: Route.LoaderArgs) {
  const r = await req({
    url: `/orders/${params.id}`,
    context,
    request
  })

  if (!r.ok) {
    throw new Response(null, { status: r.status })
  }

  const order = (await r.json()) as Order
  return { order }
}

export default function Route({ loaderData: { order } }: Route.ComponentProps) {
  const { reset } = useWizardStore()
  const {
    coupon,
    address,
    total,
    payment_method,
    interest_amount,
    discount,
    invoice,
    payment_attempts = [],
    enrollments = [],
    seats = [],
    items = [],
    subtotal
  } = order

  const Component =
    (PaymentMethodComponent as Record<string, React.ComponentType<any>>)[
      payment_method
    ] ?? UnknownPaymentMethod

  useEffect(() => {
    reset()
  }, [])
  console.log(seats)
  return (
    <div className="space-y-2.5">
      <Breadcrumb>
        <BreadcrumbList>
          <BreadcrumbItem>
            <BreadcrumbLink asChild>
              <Link to="../payments">Pagamentos</Link>
            </BreadcrumbLink>
          </BreadcrumbItem>
          <BreadcrumbSeparator />
          <BreadcrumbItem>
            <BreadcrumbPage>Detalhes do pagamento</BreadcrumbPage>
          </BreadcrumbItem>
        </BreadcrumbList>
      </Breadcrumb>

      <Card className="lg:max-w-4xl mx-auto">
        <CardHeader className="gap-0">
          <CardTitle className="text-2xl">Detalhes do pagamento</CardTitle>
        </CardHeader>

        <CardContent className="space-y-4">
          <ItemGroup className="grid lg:grid-cols-2 gap-4">
            <Item variant="outline" className="items-start">
              {/* Billing address */}
              <ItemContent>
                <ItemTitle>Endereço de cobrança</ItemTitle>
                <ul className="text-muted-foreground text-sm leading-normal font-normal text-balance">
                  {address?.address1}
                  {address?.address2 ? <>, {address?.address2}</> : null}
                  <br />
                  {address?.neighborhood}
                  <br />
                  {address?.city}, {address?.state}
                  <br />
                  {formatCEP(address?.postcode)}
                </ul>
              </ItemContent>
            </Item>
            {/* Payment method */}
            <Item variant="outline" className="items-start">
              <ItemContent>
                <ItemTitle>Forma de pagamento</ItemTitle>
                <div className="text-muted-foreground text-sm leading-normal font-normal text-balance">
                  {Component && <Component {...order} invoice={invoice} />}
                </div>
              </ItemContent>

              {payment_attempts.length > 0 ? (
                <ItemActions>
                  <PaymentAttemptsMenu payment_attempts={payment_attempts} />
                </ItemActions>
              ) : null}
            </Item>
          </ItemGroup>

          <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(({ name, unit_price, quantity }, index) => {
                return (
                  <TableRow key={index}>
                    <TableCell>{name}</TableCell>
                    <TableCell>{quantity}</TableCell>
                    <TableCell>
                      <Currency>{unit_price}</Currency>
                    </TableCell>
                    <TableCell>
                      <Currency>{unit_price * quantity}</Currency>
                    </TableCell>
                  </TableRow>
                )
              })}
            </TableBody>

            {/* Summary */}
            <TableFooter>
              <TableRow>
                <TableCell className="text-right" colSpan={3}>
                  Subtotal
                </TableCell>
                <TableCell>
                  <Currency>{subtotal}</Currency>
                </TableCell>
              </TableRow>
              {/* Discount */}
              <TableRow>
                <TableCell colSpan={3}>
                  <span className="flex gap-1 justify-end">
                    Descontos
                    {coupon && (
                      <Kbd>
                        <Abbr maxLen={8}>{coupon}</Abbr>
                      </Kbd>
                    )}
                  </span>
                </TableCell>
                <TableCell>
                  <Currency>{discount}</Currency>
                </TableCell>
              </TableRow>
              {/* Interest */}
              {interest_amount ? (
                <TableRow>
                  <TableCell className="text-right" colSpan={3}>
                    Juros
                  </TableCell>
                  <TableCell>
                    <Currency>{interest_amount}</Currency>
                  </TableCell>
                </TableRow>
              ) : (
                <></>
              )}
              {/* Total */}
              <TableRow>
                <TableCell className="text-right" colSpan={3}>
                  Total
                </TableCell>
                <TableCell>
                  <Currency>{total}</Currency>
                </TableCell>
              </TableRow>
            </TableFooter>
          </Table>
        </CardContent>
      </Card>

      {enrollments.length > 0 ? (
        <Enrollments enrollments={enrollments} seats={seats} />
      ) : null}
    </div>
  )
}

function Status({ status: s }: { status: string }) {
  const status = labels[s] ?? s
  const { icon: Icon, color } = statuses?.[s] ?? { icon: HelpCircleIcon }

  return (
    <Badge variant="outline" className={cn(color, 'px-1.5')}>
      <Icon className={cn('stroke-2', color)} />
      {status}
    </Badge>
  )
}

type PaymentMethodProps = {
  id: string
  status: string
  total: number
  invoice: Invoice
  installments: number
}

type BankSlipPaymentMethodProps = PaymentMethodProps & {}

function BankSlipPaymentMethod({
  status,
  invoice
}: BankSlipPaymentMethodProps) {
  return (
    <div className="space-y-2">
      <ul className="flex gap-x-1.5">
        <li>Boleto bancário</li>
        <li>
          <Status status={status} />
        </li>
      </ul>

      {invoice?.bank_slip ? (
        <>
          <Button
            size="sm"
            variant="secondary"
            className="cursor-pointer"
            asChild
          >
            <a href={invoice.bank_slip.bank_slip_pdf_url} target="_blank">
              <ExternalLinkIcon /> Abrir o boleto bancário
            </a>
          </Button>
        </>
      ) : null}
    </div>
  )
}

type PixPaymentMethodrops = PaymentMethodProps & {}

function PixPaymentMethod({ invoice, status }: PixPaymentMethodrops) {
  return (
    <div className="space-y-2">
      <ul className="flex gap-x-1.5">
        <li>Pix</li>
        <li>
          <Status status={status} />
        </li>
      </ul>

      {invoice?.pix ? (
        <div
          className="font-mono text-xs break-all p-2.5 border
                     rounded-md text-red-900 dark:text-yellow-600
                     bg-gray-50 dark:bg-muted/50 select-all"
        >
          {invoice.pix.qrcode_text}
        </div>
      ) : null}
    </div>
  )
}

function UnknownPaymentMethod() {
  return <>Deposito bancário</>
}

type CreditCardPaymentMethodProps = PaymentMethodProps & {
  stats?: { last_attempt_succeeded: boolean }
  credit_card: { last4: string; brand: string }
}

function CreditCardPaymentMethod({
  id,
  status,
  total,
  credit_card,
  installments,
  invoice,
  stats
}: CreditCardPaymentMethodProps) {
  return (
    <>
      <ul className="lg:flex gap-x-1">
        <li>
          <Abbr maxLen={6}>{credit_card.brand}</Abbr>
        </li>
        <li>(Crédito) **** {credit_card.last4}</li>
        <li>
          {stats?.last_attempt_succeeded === false ? (
            <Badge variant="outline" className="text-red-400 px-1.5">
              <AlertCircleIcon /> Negado
            </Badge>
          ) : (
            <Status status={status} />
          )}
        </li>
      </ul>

      <p>
        {installments}x <Currency>{total / Number(installments)}</Currency>
      </p>

      {stats?.last_attempt_succeeded === false && invoice?.invoice_id ? (
        <div className="lg:flex justify-center mt-2">
          <CreditCardPaymentDialog
            id={id}
            total={total}
            installments={installments}
            invoice_id={invoice.invoice_id}
          >
            <Button size="sm" variant="secondary" className="cursor-pointer">
              <ArrowLeftRightIcon /> Pagar com outro cartão
            </Button>
          </CreditCardPaymentDialog>
        </div>
      ) : null}
    </>
  )
}

const formSchema = z.object({
  credit_card: creditCardSchema
})

type Schema = z.input<typeof formSchema>

function CreditCardPaymentDialog({
  children,
  id,
  installments,
  invoice_id,
  total
}) {
  const revalidator = useRevalidator()
  const [open, { set: setOpen, toggle }] = useToggle()
  const { runAsync } = useRequest(
    async ({ credit_card }) => {
      return await fetch(`/~/api/orders/${id}/payment-retries`, {
        method: 'POST',
        headers: new Headers({ 'Content-Type': 'application/json' }),
        body: JSON.stringify({ credit_card, installments, invoice_id })
      })
    },
    { manual: true }
  )
  const { control, handleSubmit, formState } = useForm<Schema>({
    resolver: zodResolver(formSchema)
  })

  const onSubmit = async ({ credit_card }: Schema) => {
    await runAsync({ credit_card })
    revalidator.revalidate()
    setOpen(false)
  }

  return (
    <Dialog open={open} onOpenChange={toggle}>
      <DialogTrigger asChild>{children}</DialogTrigger>

      <DialogContent className="sm:max-w-[425px]">
        <DialogHeader>
          <DialogTitle>Novo cartão de crédito</DialogTitle>
          <DialogDescription>
            Use um novo cartão para concluir o pagamento. Nenhuma cobrança foi
            realizada no cartão anterior.
          </DialogDescription>
        </DialogHeader>

        <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
          <CreditCard control={control} />

          <Separator />

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

            <Button type="submit" disabled={formState.isSubmitting}>
              {formState.isSubmitting && <Spinner />}
              Pagar <Currency>{total}</Currency>
            </Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  )
}

function PaymentAttemptsMenu({
  payment_attempts
}: {
  payment_attempts: Attempts[]
}) {
  return (
    <Popover>
      <PopoverTrigger asChild>
        <Button variant="ghost" className="cursor-pointer" size="icon-sm">
          <EllipsisIcon />
        </Button>
      </PopoverTrigger>
      <PopoverContent align="end" className="w-82">
        <div className="p-2 space-y-1.5">
          {payment_attempts.map(({ sk, brand, last4, status }, index) => {
            const [, , created_at] = sk.split('#')

            return (
              <ul key={index} className="text-sm flex gap-1.5">
                <li>
                  <Kbd>
                    <DateTime
                      options={{
                        year: '2-digit',
                        hour: '2-digit',
                        minute: '2-digit'
                      }}
                    >
                      {created_at}
                    </DateTime>
                  </Kbd>
                </li>
                <li>
                  <Abbr maxLen={6}>{brand}</Abbr>
                </li>
                <li className="ml-auto">**** {last4}</li>
                <li className="flex items-center">
                  {status === 'FAILED' ? (
                    <CircleXIcon className="size-4 text-red-400" />
                  ) : (
                    <CircleCheckIcon className="size-4 text-green-400" />
                  )}
                </li>
              </ul>
            )
          })}
        </div>
      </PopoverContent>
    </Popover>
  )
}
