import { useEffect, useMemo, useState, useCallback } from 'react'
import { Copy } from 'lucide-react'
import type { ColumnDef } from '@tanstack/react-table'
import { toast } from 'sonner'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { DataTable } from '@/components/ui/data-table'
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from '@/components/ui/tooltip'
import type { AuditEventDto, AuditEventsFilter } from '@/api/audit'
import { useAuditEvents } from '@/features/admin/audit/useAuditEvents'
import {
  AuditFilters,
  EMPTY_FILTERS,
  toApiFilter,
  type AuditFiltersValue,
} from './AuditFilters'
import { formatInstant } from '@/lib/dateFormat'

/** Copia texto al clipboard con fallback + toast. */
async function copyToClipboard(text: string, label: string): Promise<void> {
  try {
    if (
      typeof navigator !== 'undefined' &&
      navigator.clipboard &&
      typeof navigator.clipboard.writeText === 'function'
    ) {
      await navigator.clipboard.writeText(text)
    } else {
      // Fallback jsdom / navegadores viejos
      const ta = document.createElement('textarea')
      ta.value = text
      ta.setAttribute('readonly', '')
      ta.style.position = 'absolute'
      ta.style.left = '-9999px'
      document.body.appendChild(ta)
      ta.select()
      document.execCommand('copy')
      document.body.removeChild(ta)
    }
    toast.success(`${label} copiado al portapapeles`)
  } catch {
    toast.error(`No se pudo copiar ${label.toLowerCase()}`)
  }
}

export function AuditPage() {
  // Filtros confirmados (los que se mandan a la API). Se actualizan al Aplicar.
  const [filters, setFilters] = useState<AuditFiltersValue>(EMPTY_FILTERS)
  // Cursor actual (undefined = primera página).
  const [cursor, setCursor] = useState<string | undefined>(undefined)
  // Acumulador de items entre páginas ("cargar más").
  const [accumulated, setAccumulated] = useState<AuditEventDto[]>([])

  const apiFilter = useMemo<AuditEventsFilter>(() => {
    const f = toApiFilter(filters)
    return cursor ? { ...f, cursor } : f
  }, [filters, cursor])

  const { data, isLoading, isFetching, isError } = useAuditEvents(apiFilter)

  // Acumular items cuando llegan. Si es la primera página (cursor=undefined)
  // reseteamos; si hay cursor, appendeamos.
  useEffect(() => {
    if (!data) return
    if (cursor === undefined) {
      // eslint-disable-next-line react-hooks/set-state-in-effect -- acumula datos paginados de una query externa; reset en primera página es intencional
      setAccumulated(data.items)
    } else {
      setAccumulated((prev) => {
        // Evitar dobles appends en StrictMode: si el último batch ya incluye
        // este primer id, asumimos que ya fue appendeado.
        const firstNew = data.items[0]
        if (
          firstNew &&
          prev.length > 0 &&
          prev[prev.length - 1]?.id === firstNew.id
        ) {
          return prev
        }
        return [...prev, ...data.items]
      })
    }
  }, [data, cursor])

  const handleApply = useCallback((value: AuditFiltersValue) => {
    setFilters(value)
    setCursor(undefined)
    setAccumulated([])
  }, [])

  const handleReset = useCallback(() => {
    setFilters(EMPTY_FILTERS)
    setCursor(undefined)
    setAccumulated([])
  }, [])

  const handleLoadMore = useCallback(() => {
    if (data?.nextCursor) {
      setCursor(data.nextCursor)
    }
  }, [data])

  const columns = useMemo<ColumnDef<AuditEventDto>[]>(
    () => [
      {
        accessorKey: 'occurredAt',
        header: 'Fecha',
        cell: ({ row }) => (
          <span className="font-mono text-xs text-foreground">
            {formatInstant(row.original.occurredAt)}
          </span>
        ),
        meta: { priority: 'high' },
      },
      {
        accessorKey: 'actorUsername',
        header: 'Usuario',
        cell: ({ row }) => {
          const u = row.original.actorUsername
          if (!u) {
            return (
              <span className="text-muted-foreground italic">
                sistema
              </span>
            )
          }
          return <span className="font-mono text-xs">{u}</span>
        },
        meta: { priority: 'high' },
      },
      {
        accessorKey: 'action',
        header: 'Acción',
        cell: ({ row }) => (
          <Badge variant="secondary" className="font-mono text-[11px]">
            {row.original.action}
          </Badge>
        ),
        meta: { priority: 'high' },
      },
      {
        id: 'target',
        header: 'Entidad',
        cell: ({ row }) => (
          <div className="flex flex-col gap-0.5">
            <span className="text-xs font-medium text-foreground">
              {row.original.targetType}
            </span>
            <span className="font-mono text-[11px] text-muted-foreground break-all">
              {row.original.targetId}
            </span>
          </div>
        ),
        meta: { priority: 'medium' },
      },
      {
        accessorKey: 'ipAddress',
        header: 'IP',
        cell: ({ row }) => (
          <span className="font-mono text-xs text-muted-foreground">
            {row.original.ipAddress ?? '—'}
          </span>
        ),
        meta: { priority: 'low' },
      },
      {
        accessorKey: 'correlationId',
        header: 'Correlation',
        cell: ({ row }) => {
          const cid = row.original.correlationId
          if (!cid) return <span className="text-muted-foreground">—</span>
          const short = cid.length > 10 ? `${cid.slice(0, 8)}…` : cid
          return (
            <div className="flex items-center gap-1">
              <span
                className="font-mono text-[11px] text-muted-foreground"
                title={cid}
              >
                {short}
              </span>
              <Tooltip>
                <TooltipTrigger asChild>
                  <button
                    type="button"
                    onClick={(e) => {
                      e.stopPropagation()
                      void copyToClipboard(cid, 'Correlation ID')
                    }}
                    aria-label="Copiar correlation ID"
                    className="inline-flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
                  >
                    <Copy className="h-3 w-3" />
                  </button>
                </TooltipTrigger>
                <TooltipContent>Copiar correlation ID</TooltipContent>
              </Tooltip>
            </div>
          )
        },
        meta: { priority: 'low' },
      },
    ],
    [],
  )

  const hasMore = Boolean(data?.nextCursor)

  return (
    <div className="space-y-6">
      <div className="flex items-center justify-between">
        <div className="space-y-1">
          <h1 className="text-xl font-semibold text-foreground">
            Auditoría
          </h1>
          <p className="text-sm text-muted-foreground">
            Historial de eventos del sistema. Resultados paginados por cursor.
          </p>
        </div>
      </div>

      <AuditFilters
        initialValue={filters}
        onApply={handleApply}
        onReset={handleReset}
      />

      {isError ? (
        <div
          role="alert"
          className="surface p-4 text-sm text-destructive"
        >
          No se pudieron cargar los eventos de auditoría. Intentá de nuevo.
        </div>
      ) : (
        <DataTable
          columns={columns}
          data={accumulated}
          getRowId={(row) => String(row.id)}
          isLoading={isLoading && accumulated.length === 0}
          emptyMessage="Sin resultados — no se encontraron eventos con los filtros seleccionados."
        />
      )}

      <div className="flex items-center justify-between pt-2">
        <span className="text-sm text-muted-foreground">
          {accumulated.length > 0
            ? `${accumulated.length} evento${accumulated.length !== 1 ? 's' : ''} cargado${accumulated.length !== 1 ? 's' : ''}`
            : ''}
        </span>
        <Button
          variant="outline"
          size="sm"
          disabled={!hasMore || isFetching}
          onClick={handleLoadMore}
          aria-label="Cargar más eventos"
        >
          {isFetching && cursor !== undefined ? 'Cargando…' : 'Cargar más'}
        </Button>
      </div>

      {/*
        TODOs para ADM-004:
        - Drill-down del evento (modal con metadata JSON formatted)
        - Export CSV de los resultados filtrados
        - Timeline visualization por entidad
      */}
    </div>
  )
}
