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

import { DateTime } from 'luxon'
import { Suspense } from 'react'
import { BanIcon } from 'lucide-react'

import { request as req } from '@repo/util/request'
import { Skeleton } from '@repo/ui/components/skeleton'
import { Await } from 'react-router'
import { Card, CardContent } from '@repo/ui/components/ui/card'
import {
  Table,
  TableBody,
  TableCell,
  TableFooter,
  TableHead,
  TableHeader,
  TableRow
} from '@repo/ui/components/ui/table'
import { Abbr } from '@repo/ui/components/abbr'
import { Button } from '@repo/ui/components/ui/button'
import { cn } from '@repo/ui/lib/utils'
import {
  Empty,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle
} from '@repo/ui/components/ui/empty'

import { billingPeriod, formatDate } from './util'
import { RangePeriod } from './range-period'
import { statuses } from './data'

export function meta({}) {
  return [{ title: 'Resumo de cobranças' }]
}

export async function loader({ context, request, params }: Route.LoaderArgs) {
  const { searchParams } = new URL(request.url)
  const subscription = await req({
    url: `/orgs/${params.orgid}/subscription`,
    context,
    request
  }).then((r) => r.json())

  const [startDate, endDate] = billingPeriod(
    subscription?.billing_day || 1,
    new Date()
  )
  const start = searchParams.get('start') || formatDate(startDate)
  const end = searchParams.get('end') || formatDate(endDate)

  const billing = req({
    url: `/orgs/${params.orgid}/billing?start_date=${start}&end_date=${end}`,
    context,
    request
  }).then((r) => r.json())

  return {
    subscription,
    billing,
    startDate: DateTime.fromISO(start).toJSDate(),
    endDate: DateTime.fromISO(end).toJSDate()
  }
}

export default function Route({
  loaderData: { subscription, billing, startDate, endDate }
}: Route.ComponentProps) {
  return (
    <>
      <Suspense fallback={<Skeleton />}>
        <div className="space-y-0.5 mb-8">
          <h1 className="text-2xl font-bold tracking-tight">
            Resumo de cobranças
          </h1>
          <p className="text-muted-foreground">
            Acompanhe as cobranças em tempo real e garanta mais eficiência no
            controle financeiro.
          </p>
        </div>

        <Await resolve={billing}>
          {({ items = [], ...billing }) => {
            const {
              icon: Icon,
              label: status,
              color
            } = statuses?.[billing?.status || 'CLOSED']
            const charges = items
              ?.filter((item) => 'course' in item && item?.unit_price > 0)
              ?.sort(sortBy('enrolled_at'))
            const credits = items
              ?.filter((item) => 'course' in item && item?.unit_price < 0)
              ?.sort(sortBy('created_at'))

            return (
              <Card>
                <CardContent className="space-y-4">
                  <div className="flex max-lg:flex-col gap-2.5">
                    <Button
                      className={cn('pointer-events-none', color)}
                      variant="outline"
                      asChild
                    >
                      <span>
                        <Icon className="size-3.5" /> {status}
                      </span>
                    </Button>

                    <RangePeriod
                      startDate={startDate}
                      endDate={endDate}
                      billingDay={subscription?.billing_day || 1}
                    />
                  </div>

                  {items.length ? (
                    <div className="border rounded-lg overflow-hidden">
                      <Table className="table-auto w-full">
                        {charges.length ? (
                          <>
                            <TableHeader>
                              <TableRow className="bg-muted-foreground/10 pointer-events-none">
                                <TableHead>Colaborador</TableHead>
                                <TableHead>Curso</TableHead>
                                <TableHead>Matriculado por</TableHead>
                                <TableHead>Matriculado em</TableHead>
                                <TableHead>Valor unit.</TableHead>
                              </TableRow>
                            </TableHeader>
                            <TableBody>
                              {charges?.map(
                                (
                                  {
                                    user,
                                    course,
                                    author: created_by,
                                    unit_price,
                                    enrolled_at
                                  },
                                  index
                                ) => (
                                  <TableRow key={index}>
                                    <TableCell>
                                      <Abbr>{user.name}</Abbr>
                                    </TableCell>
                                    <TableCell>
                                      <Abbr>{course.name}</Abbr>
                                    </TableCell>
                                    <TableCell>
                                      <Abbr>
                                        {created_by ? created_by.name : 'N/A'}
                                      </Abbr>
                                    </TableCell>
                                    <TableCell>
                                      {datetime.format(new Date(enrolled_at))}
                                    </TableCell>
                                    <TableCell>
                                      {currency.format(unit_price)}
                                    </TableCell>
                                  </TableRow>
                                )
                              )}
                            </TableBody>
                          </>
                        ) : null}

                        {credits.length ? (
                          <>
                            <TableHeader>
                              <TableRow className="bg-muted-foreground/10 pointer-events-none border-t">
                                <TableHead colSpan={2}></TableHead>
                                <TableHead>Cancelado por</TableHead>
                                <TableHead colSpan={2}>Cancelado em</TableHead>
                              </TableRow>
                            </TableHeader>
                            <TableBody>
                              {credits?.map(
                                (
                                  {
                                    user,
                                    course,
                                    author: canceled_by,
                                    unit_price,
                                    created_at
                                  },
                                  index
                                ) => (
                                  <TableRow key={index}>
                                    <TableCell>
                                      <Abbr>{user.name}</Abbr>
                                    </TableCell>
                                    <TableCell>
                                      <Abbr>{course.name}</Abbr>
                                    </TableCell>
                                    <TableCell>
                                      <Abbr>
                                        {canceled_by ? canceled_by.name : 'N/A'}
                                      </Abbr>
                                    </TableCell>
                                    <TableCell>
                                      {datetime.format(new Date(created_at))}
                                    </TableCell>
                                    <TableCell>
                                      {currency.format(unit_price)}
                                    </TableCell>
                                  </TableRow>
                                )
                              )}
                            </TableBody>
                          </>
                        ) : null}

                        <TableFooter>
                          <TableRow>
                            <TableCell
                              colSpan={4}
                              className="text-right pointer-events-none"
                            >
                              Total
                            </TableCell>
                            <TableCell>
                              {currency.format(
                                items
                                  ?.filter((x) => 'course' in x)
                                  .reduce(
                                    (acc, { unit_price }) => acc + unit_price,
                                    0
                                  )
                              )}
                            </TableCell>
                          </TableRow>
                        </TableFooter>
                      </Table>
                    </div>
                  ) : (
                    <Empty className="border border-dashed">
                      <EmptyHeader>
                        <EmptyMedia variant="icon">
                          <BanIcon />
                        </EmptyMedia>
                        <EmptyTitle>Nenhuma cobrança encontrada</EmptyTitle>
                        <EmptyDescription>
                          Não há nenhuma cobrança para este período.
                        </EmptyDescription>
                      </EmptyHeader>
                    </Empty>
                  )}
                </CardContent>
              </Card>
            )
          }}
        </Await>
      </Suspense>
    </>
  )
}
const currency = new Intl.NumberFormat('pt-BR', {
  style: 'currency',
  currency: 'BRL'
})

const datetime = new Intl.DateTimeFormat('pt-BR', {
  day: '2-digit',
  month: '2-digit',
  year: 'numeric',
  hour: '2-digit',
  minute: '2-digit'
})

const sortBy = (field: 'enrolled_at' | 'created_at') => (a: any, b: any) =>
  new Date(a[field]).getTime() - new Date(b[field]).getTime()
