import { ChevronRight, Info, TriangleAlert, Zap } from 'lucide-react'

import { Button } from '@/components/ui/button'
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from '@/components/ui/collapsible'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '@/components/ui/dialog'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { formatNumber } from '@/lib/format'
import { locale, t } from '@/lib/i18n'
import { cn } from '@/lib/utils'

export interface DailyQuota {
  date: string
  limit_total: number
  manual_reserve: number
  used_automatic: number
  used_manual: number
}

/**
 * El cupo del día detrás de un botón, y no ocupando media pantalla.
 *
 * Estaba como tarjeta al pie de la ficha del lote, con los dos bolsillos
 * desplegados y setenta y ocho palabras de explicación. El reparto del cupo
 * entre trabajo automático y manual **no le interesa a nadie hasta que es un
 * problema**, y mientras tanto compite por la atención con las cifras que sí se
 * abrieron a mirar.
 *
 * Por eso se pliega. Y por eso el botón lleva un punto cuando el cupo se agotó:
 * esconder algo sólo es correcto si lo que hay adentro sabe pedir que lo miren.
 *
 * **No usa `QuotaMeter`.** Ése lo dibujan otras tres pantallas donde el cupo es
 * el tema —el tablero, la ficha del dominio— y ahí desplegado está bien. Acá el
 * tema es el lote, y el cupo es contexto: la pieza es otra porque la pregunta es
 * otra.
 */
export function QuotaDialog({ quota, batchUsed }: { quota: DailyQuota | null; batchUsed: number }) {
  // Sin fila del día no hay nada que mostrar, y no se inventa una con los
  // límites de hoy: un lote de hace un mes quedaría explicado con un cupo que
  // ese día no existió.
  if (quota === null) {
    return (
      <Tooltip>
        <TooltipTrigger asChild>
          <Button variant="outline" size="sm" disabled className="gap-1.5">
            <Zap aria-hidden />
            {t('quota.short')}
          </Button>
        </TooltipTrigger>
        <TooltipContent className="max-w-64">{t('batchShow.quota.missing')}</TooltipContent>
      </Tooltip>
    )
  }

  const figures = read(quota)

  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="outline" size="sm" className="gap-1.5">
          <Zap aria-hidden />
          {t('quota.short')}
          {/* El punto es la única razón por la que esconder esto es honesto: sin
              él, un cupo agotado quedaría a un clic de distancia que nadie tiene
              motivo para dar. Marca el agotamiento real —no queda nada en
              ninguno de los dos bolsillos—, no el de la reserva, que mientras
              sobre cupo automático no frena nada. */}
          {figures.allExhausted ? (
            <>
              <span className="bg-destructive size-1.5 rounded-full" aria-hidden />
              <span className="sr-only">{t('quota.exhausted.short')}</span>
            </>
          ) : null}
        </Button>
      </DialogTrigger>

      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2">
            <Zap className="size-4" aria-hidden />
            {t('quota.short')}
            {/* La nota de que el cupo es de Google y no un recurso nuestro. Es
                una aclaración que se lee una vez, así que no ocupa un renglón. */}
            <Tooltip>
              <TooltipTrigger asChild>
                <button type="button" className="text-muted-foreground">
                  <Info className="size-3.5" aria-hidden />
                  <span className="sr-only">{t('quota.footnote')}</span>
                </button>
              </TooltipTrigger>
              <TooltipContent className="max-w-64">{t('quota.footnote')}</TooltipContent>
            </Tooltip>
            <span className="text-muted-foreground ml-auto text-sm font-normal">
              <time dateTime={quota.date}>{dayLabel(quota.date)}</time>
            </span>
          </DialogTitle>
          {/* Obligatoria para el lector de pantalla. Es además lo único que
              nombra al lote: todo lo demás de acá adentro es del día. */}
          <DialogDescription className="sr-only">
            {t('batchShow.quota.description')}
          </DialogDescription>
        </DialogHeader>

        {/* El titular: lo que gastó este lote. Era la cifra que la tarjeta
            prometía situar y no mostraba. */}
        <div>
          <p className="text-2xl font-semibold tabular-nums">{formatNumber(batchUsed)}</p>
          <p className="text-muted-foreground text-sm tabular-nums">
            {t('quota.batchShare', {
              spent: formatNumber(figures.spent),
              limit: formatNumber(figures.limit),
            })}
          </p>
        </div>

        {figures.notice ? (
          <p className="text-destructive flex items-center gap-1.5 text-sm">
            <TriangleAlert className="size-4 shrink-0" aria-hidden />
            {figures.notice}
          </p>
        ) : null}

        {/* El reparto entre los dos bolsillos es una pregunta de segundo orden:
            lo que casi siempre importa es la cifra de arriba. Va plegado incluso
            acá adentro, donde el aviso de agotamiento ya subió al titular y por
            lo tanto nada urgente queda escondido. */}
        <Collapsible>
          <CollapsibleTrigger className="focus-visible:ring-ring group flex items-center gap-1.5 rounded text-sm focus-visible:ring-2 focus-visible:outline-none">
            <ChevronRight
              className="size-4 transition-transform group-data-[state=open]:rotate-90 motion-reduce:transition-none"
              aria-hidden
            />
            {t('quota.pockets')}
          </CollapsibleTrigger>

          <CollapsibleContent className="space-y-1.5 pt-2">
            <Pocket
              title={t('quota.automatic.title')}
              used={figures.usedAutomatic}
              quota={figures.automaticQuota}
              exhausted={figures.automaticRemaining === 0}
              note={t('quota.automatic.note')}
            />
            <Pocket
              title={t('quota.manual.title')}
              used={figures.usedManual}
              quota={figures.reserve}
              exhausted={figures.reserveRemaining === 0}
              note={
                figures.reserve === 0
                  ? t('quota.manual.noReserve')
                  : figures.manualRemaining > figures.reserveRemaining
                    ? t('quota.manual.plusUnused', {
                        count: figures.manualRemaining - figures.reserveRemaining,
                        total: formatNumber(figures.manualRemaining - figures.reserveRemaining),
                      })
                    : t('quota.manual.untouched')
              }
            />
          </CollapsibleContent>
        </Collapsible>
      </DialogContent>
    </Dialog>
  )
}

/**
 * Un bolsillo en una línea.
 *
 * La nota que explica la regla del reparto —que el automático no toca la
 * reserva, que el manual sí puede usar el sobrante— se consulta una vez y
 * después estorba, así que va al ícono. La barra dice «lleno» sin escribirlo, y
 * por eso tampoco hace falta el renglón de «quedan».
 */
function Pocket({
  title,
  used,
  quota,
  exhausted,
  note,
}: {
  title: string
  used: number
  quota: number
  exhausted: boolean
  note: string
}) {
  const ratio = quota > 0 ? Math.min(used / quota, 1) : 0

  return (
    <div className="flex items-center gap-3 text-sm">
      <span className="w-20 shrink-0">{title}</span>

      <span className="bg-muted relative h-1.5 min-w-0 flex-1 overflow-hidden rounded-full">
        <span
          className={cn(
            'absolute inset-0 origin-left transition-transform duration-200 ease-out motion-reduce:transition-none',
            exhausted ? 'bg-destructive' : 'bg-primary'
          )}
          style={{ transform: `scaleX(${ratio})` }}
          aria-hidden
        />
      </span>

      <span className={cn('shrink-0 tabular-nums', exhausted && 'text-destructive')}>
        {formatNumber(used)} / {formatNumber(quota)}
      </span>

      <Tooltip>
        <TooltipTrigger asChild>
          <button type="button" className="text-muted-foreground shrink-0">
            <Info className="size-3.5" aria-hidden />
            <span className="sr-only">{note}</span>
          </button>
        </TooltipTrigger>
        <TooltipContent className="max-w-64">{note}</TooltipContent>
      </Tooltip>
    </div>
  )
}

/**
 * Las cuentas del reparto, que replican las propiedades del presupuesto.
 *
 * La asimetría es intencional y viene del servidor: la reserva le garantiza un
 * piso al trabajo manual, no le pone un techo, así que lo que el ciclo
 * automático no gastó también queda a su alcance.
 */
function read(quota: DailyQuota) {
  const limit = Math.max(quota.limit_total, 0)
  const reserve = Math.min(Math.max(quota.manual_reserve, 0), limit)
  const usedAutomatic = Math.min(Math.max(quota.used_automatic, 0), limit)
  const usedManual = Math.min(Math.max(quota.used_manual, 0), limit)

  const automaticRemaining = Math.max(limit - reserve - usedAutomatic, 0)
  const reserveRemaining = Math.max(reserve - usedManual, 0)
  const manualRemaining = Math.max(limit - usedAutomatic - usedManual, 0)
  const allExhausted = manualRemaining === 0

  return {
    limit,
    reserve,
    usedAutomatic,
    usedManual,
    automaticQuota: Math.max(limit - reserve, 0),
    automaticRemaining,
    reserveRemaining,
    manualRemaining,
    spent: usedAutomatic + usedManual,
    allExhausted,
    // Un solo aviso, el más grave que aplique. Dos frases de alerta a la vez se
    // leen como ruido y ninguna se atiende.
    notice: allExhausted
      ? t('quota.exhausted.short')
      : reserveRemaining === 0
        ? t('quota.exhausted.manualReserve')
        : automaticRemaining === 0
          ? t('quota.exhausted.automatic')
          : null,
  }
}

/**
 * El día del presupuesto es una fecha de calendario, no un instante: se arma en
 * UTC para que no se corra un día hacia atrás al pasarlo por la zona local.
 */
function dayLabel(date: string): string {
  const [year, month, day] = date.split('-').map(Number)
  if (!year || !month || !day) return date

  return new Intl.DateTimeFormat(locale(), {
    day: 'numeric',
    month: 'short',
    timeZone: 'UTC',
  }).format(new Date(Date.UTC(year, month - 1, day)))
}

/**
 * Lo que este lote gastó, con el botón que lo sitúa en el día al lado.
 *
 * Van juntos porque son la misma pregunta: «242» sin nada contra qué compararlo
 * es un número suelto, y el día entero sin saber cuánto puso este lote tampoco
 * explica nada.
 */
export function QuotaFigure({
  used,
  quota,
  className,
}: {
  used: number
  quota: DailyQuota | null
  className?: string
}) {
  return (
    <div className={cn('flex flex-wrap items-center gap-x-3 gap-y-1', className)}>
      <span>{formatNumber(used)}</span>
      <QuotaDialog quota={quota} batchUsed={used} />
    </div>
  )
}
