import { Link } from '@inertiajs/react'
import {
  ArrowRightIcon,
  DatabaseIcon,
  EyeIcon,
  InfoIcon,
  MousePointerClickIcon,
  SplitIcon,
  TrendingUpIcon,
} from 'lucide-react'

import { EmptyState } from '@/components/EmptyState'
import { IndicatorCard } from '@/components/IndicatorCard'
import { Section } from '@/components/Section'
import { SectionCard } from '@/components/SectionCard'
import { Button } from '@/components/ui/button'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { AppLayout } from '@/layouts/AppLayout'
import { formatNumber } from '@/lib/format'
import { locale, t } from '@/lib/i18n'
import { route } from '@/lib/routes'
import { ModuleStatusBadge } from '@/pages/Seo/status'
import { TopKeywords } from '@/pages/Seo/TopKeywords'
import { keywordsHref } from '@/pages/Seo/vocabulary'
import type {
  HomeMetrics,
  Overview,
  SiteProps,
  TopKeywords as TopKeywordsData,
} from '@/pages/Seo/types'

interface Props {
  domain: SiteProps | null
  overview: Overview | null
  metrics: HomeMetrics | null
  /** El gráfico y su tabla. `null` mientras no haya historia que dibujar. */
  top_keywords: TopKeywordsData | null
  window_days?: number
  min_impressions?: number
}

/**
 * El inicio de la herramienta, en dos grupos con nombre.
 *
 * Los grupos separan **por la pregunta que contestan** y no por parecido visual,
 * igual que el tablero de la otra herramienta: una fila de cuatro tarjetas
 * iguales no dice en qué se diferencian, y el ojo termina leyendo cuatro veces
 * lo mismo para descubrirlo.
 *
 * - **Cómo viene** — lo que trajo el período. Es la cifra de cabecera.
 * - **Qué revisar** — los tres indicadores accionables, cada uno con su lista.
 *
 * **No lleva medidor de cuota.** Un medidor necesita un denominador contra el
 * cual llenarse, y el de Search Analytics son treinta millones de llamadas
 * diarias por proyecto contra las pocas que hace este módulo: marcaría cero para
 * siempre, ocuparía el lugar de algo que sí informa y entrenaría a no mirar ese
 * rincón. La cuota aparece cuando molesta, como estado.
 */
export default function SeoIndex({
  domain,
  overview,
  metrics,
  top_keywords,
  window_days = 28,
  min_impressions = 10,
}: Props) {
  if (domain === null || overview === null) {
    return (
      <AppLayout title={t('seo.title')} description={t('seo.description')}>
        <EmptyState
          icon={DatabaseIcon}
          title={t('seo.noSite.title')}
          description={t('seo.noSite.description')}
        />
      </AppLayout>
    )
  }

  if (metrics === null) {
    return (
      <AppLayout title={t('seo.title')} description={t('seo.description')}>
        <SectionCard
          title={{ text: t('seo.overview.title') }}
          actions={<ModuleStatusBadge status={overview.status} code={overview.error_code} />}
        >
          <EmptyState
            icon={DatabaseIcon}
            title={t('seo.empty.title')}
            description={t('seo.empty.description')}
            className="border-0"
            action={
              <Button asChild>
                <Link href={route('seo.connection')}>
                  {t('seo.empty.action')}
                  <ArrowRightIcon aria-hidden />
                </Link>
              </Button>
            }
          />
        </SectionCard>
      </AppLayout>
    )
  }

  const current = metrics.performance?.current ?? null
  const previous = metrics.performance?.previous ?? null
  const period = metrics.performance
    ? ([metrics.performance.current_start, metrics.performance.current_end] as const)
    : null
  const previousPeriod = metrics.performance
    ? ([metrics.performance.previous_start, metrics.performance.previous_end] as const)
    : null

  // Sin insignia de estado en el encabezado. «Listo» al lado del título no dice
  // nada que la pantalla no esté diciendo ya —si hay cifras, el módulo
  // funciona— y ocupa el lugar donde se buscan las acciones. El tablero de la
  // otra herramienta tampoco la lleva. El estado vive en la conexión, que es
  // adonde se va a mirar cuando algo falle.
  return (
    <AppLayout title={t('seo.title')} description={t('seo.description')}>
      <Section title={{ text: t('seo.home.group.performance') }}>
        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
          <IndicatorCard
            title={t('seo.home.impressions')}
            icon={EyeIcon}
            value={current ? formatNumber(current.impressions) : '—'}
            description={
              previous
                ? t('seo.home.against', { previous: formatNumber(previous.impressions) })
                : t('seo.home.noPrevious')
            }
            /*
              La única que compara, y por eso la única que declara los dos
              tramos. «Contra 84 el período anterior» sin decir de cuándo a
              cuándo no se puede juzgar: no se sabe si son siete días o noventa.
            */
            footer={
              <RangeFooter
                days={window_days}
                range={period}
                against={previous ? previousPeriod : undefined}
              />
            }
          />
          <IndicatorCard
            title={t('seo.home.clicksLabel')}
            icon={MousePointerClickIcon}
            value={current ? formatNumber(current.clicks) : '—'}
            description={
              previous
                ? t('seo.home.against', { previous: formatNumber(previous.clicks) })
                : t('seo.home.noPrevious')
            }
            footer={
              <RangeFooter
                days={window_days}
                range={period}
                against={previous ? previousPeriod : undefined}
              />
            }
          />
          <IndicatorCard
            title={t('seo.home.averagePosition')}
            icon={TrendingUpIcon}
            value={current ? current.position.toFixed(1) : '—'}
            /*
              Sin marca de dirección: en Google un número más bajo es mejor, así
              que pintar de verde una baja exigiría explicar la inversión en cada
              tarjeta. Los dos números al lado se comparan solos, y donde la
              dirección sí importa —la tabla de keywords— ya está resuelta con
              signo y color en la celda de variación.
            */
            description={
              previous
                ? t('seo.home.against', { previous: previous.position.toFixed(1) })
                : t('seo.home.noPrevious')
            }
            footer={
              <RangeFooter
                days={window_days}
                range={period}
                against={previous ? previousPeriod : undefined}
              />
            }
          />
        </div>
      </Section>

      <Section title={{ text: t('seo.home.group.review') }}>
        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
          <IndicatorCard
            title={t('seo.home.cannibalization')}
            icon={SplitIcon}
            value={formatNumber(metrics.cannibalization.total)}
            description={t('seo.home.cannibalizationNote', {
              threshold: metrics.cannibalization.threshold,
            })}
            /*
              Va a la pantalla de canibalización y no a la tabla de consultas:
              lo que hay que mirar acá es **qué URLs se pisan**, y eso es una
              lista adentro de cada fila. La tabla de consultas no la tiene.
            */
            actions={
              metrics.cannibalization.total > 0 ? (
                <DetailsButton href={route('seo.cannibalization')} />
              ) : undefined
            }
          />

          <IndicatorCard
            title={t('seo.home.nearFirstPage')}
            icon={TrendingUpIcon}
            value={formatNumber(metrics.near_first_page.total)}
            description={t('seo.home.nearFirstPageNote')}
            actions={
              metrics.near_first_page.total > 0 ? (
                <DetailsButton href={keywordsHref({ band: 'NEAR_FIRST_PAGE' })} />
              ) : undefined
            }
          />

          <IndicatorCard
            title={t('seo.home.reachWithoutClicks')}
            icon={MousePointerClickIcon}
            value={formatNumber(metrics.reach_without_clicks.total)}
            description={t('seo.home.reachWithoutClicksNote')}
            actions={
              metrics.reach_without_clicks.total > 0 ? (
                <DetailsButton href={keywordsHref({ engagement: 'NO_CLICKS' })} />
              ) : undefined
            }
          />
        </div>
      </Section>

      {/*
        Al final de la pantalla. Los dos grupos de arriba son cifras —lo que hay
        que mirar primero y lo que hay que revisar—, y esto es el detalle de
        dónde salieron: veintiocho días de recorrido y las diez filas que los
        producen. El detalle antes del titular obliga a leer el recorrido para
        recién después enterarse de en qué terminó.
      */}
      {top_keywords ? (
        <TopKeywords
          data={top_keywords}
          window_days={window_days}
          min_impressions={min_impressions}
        />
      ) : null}
    </AppLayout>
  )
}

/**
 * El tramo que la cifra resume, al pie y en chico.
 *
 * Dice **cuántos días** y no las fechas: «Jul 28 – Aug 24» obliga a contar para
 * saber si son veintiocho o treinta, que es justamente lo que hay que saber para
 * juzgar la comparación. Las fechas exactas viven en la ayuda, junto con el
 * motivo de que la ventana sea ésa.
 *
 * Las fechas se escriben sin trasladarlas de zona: Google fecha en horario del
 * Pacífico y estos días son los suyos, así que correrlos a la zona de la cuenta
 * haría que el rango no coincida con el que muestra Search Console —que es
 * exactamente contra lo que se lo quiere contrastar—.
 */
function RangeFooter({
  days,
  range,
  against,
}: {
  days: number
  range: readonly [string, string] | null
  against?: readonly [string, string] | null
}) {
  if (range === null) return null

  return (
    <Tooltip>
      <TooltipTrigger asChild>
        {/*
          El disparador es la frase entera y no una marca al final: lo que hay
          que explicar es el rango, así que el área de ayuda es el rango. Un
          punto de doce píxeles al final obliga a apuntar para leer lo que la
          frase de al lado ya está pidiendo que se explique.
        */}
        <span
          tabIndex={0}
          className="text-muted-foreground inline-flex items-center gap-1.5 text-xs"
        >
          <InfoIcon aria-hidden className="size-3.5 shrink-0" />
          {against ? t('seo.home.rangeCompared', { days }) : t('seo.home.range', { days })}
        </span>
      </TooltipTrigger>
      <TooltipContent className="max-w-xs">
        {t('seo.home.rangeWhy', { days })} {t('seo.home.rangeCurrent', { range: span(range) })}
        {against ? ` ${t('seo.home.rangePrevious', { range: span(against) })}` : null}
      </TooltipContent>
    </Tooltip>
  )
}

/** «28 jul – 24 ago». Sin año: los dos extremos caen siempre en el mismo tramo corto. */
function span([start, end]: readonly [string, string]): string {
  const format = new Intl.DateTimeFormat(locale(), {
    month: 'short',
    day: 'numeric',
    timeZone: 'UTC',
  })
  return `${format.format(new Date(start))} – ${format.format(new Date(end))}`
}

/**
 * El control de la esquina de una tarjeta: adónde se va a ver el detalle.
 *
 * Sólo el icono, con el rótulo en el tooltip y como nombre accesible: en una
 * grilla de tarjetas, tres botones con texto compiten con las cifras, que son lo
 * que hay que leer primero.
 *
 * **Es un enlace de verdad y no un disparador de modal**, y eso es un cambio de
 * criterio con motivo. La regla del producto dice que una cifra se abre donde se
 * la lee, y reserva el enlace para cuando el destino contesta *la misma pregunta
 * con el mismo conjunto*. Antes ningún destino lo hacía —la tabla mostraba las
 * cuatrocientas setenta consultas del sitio— y por eso las tres tarjetas abrían
 * un modal con diez filas de muestra. Ahora el destino llega recortado por el
 * mismo corte que produjo la cifra, así que contesta exactamente lo mismo, y con
 * la lista entera en vez de con diez.
 */
function DetailsButton({ href }: { href: string }) {
  return (
    <Tooltip>
      <TooltipTrigger asChild>
        <Button asChild variant="ghost" size="icon">
          <Link href={href} aria-label={t('seo.home.details')}>
            <ArrowRightIcon aria-hidden />
          </Link>
        </Button>
      </TooltipTrigger>
      <TooltipContent>{t('seo.home.details')}</TooltipContent>
    </Tooltip>
  )
}
