'use client'

/**
 * Alerts Page - 告警管理
 * =======================
 * 顯示活躍 Incidents 告警列表，按嚴重度排序
 * 資料來源: GET /api/v1/incidents
 *
 * @created 2026-04-01 ogt
 */

import { AppLayout } from '@/components/layout'
import { useEffect, useMemo, useState } from 'react'
import { useSearchParams } from 'next/navigation'
import { useTranslations } from 'next-intl'
import { useIncidents } from '@/hooks/useIncidents'
import { useIncidentStatusChains } from '@/hooks/useIncidentStatusChains'
import { IncidentCard } from '@/components/incident'
import {
  AwoooPStatusChainPanel,
  type AwoooPStatusChain,
} from '@/components/awooop/status-chain'
import { IwoooSReadOnlyBridge } from '@/components/security/iwooos-read-only-bridge'
import { cn } from '@/lib/utils'
import { API_V1_URL } from '@/lib/config'
import type { IncidentResponse } from '@/lib/api-client'
import { Link } from '@/i18n/routing'
import {
  Activity,
  Bell,
  BellOff,
  RefreshCw,
  AlertTriangle,
  AlertCircle,
  Info,
  ChevronLeft,
  ChevronRight,
  GitBranch,
  Link2,
  ListChecks,
  MessageSquareText,
  Monitor,
  Repeat2,
  SearchCheck,
  ShieldCheck,
} from 'lucide-react'

// =============================================================================
// Severity helpers
// =============================================================================

const SEVERITY_ORDER: Record<string, number> = { P0: 0, P1: 1, P2: 2, P3: 3 }
const ALERTS_PAGE_SIZE = 50
const SOURCE_COVERAGE_LIMIT = 100
const SOURCE_FRESHNESS_STALE_HOURS = 24

const SEVERITY_STYLE: Record<string, { bg: string; text: string }> = {
  P0: { bg: 'bg-status-critical/10', text: 'text-status-critical' },
  P1: { bg: 'bg-status-warning/10',  text: 'text-status-warning' },
  P2: { bg: 'bg-claw-blue/10',       text: 'text-claw-blue' },
  P3: { bg: 'bg-nothing-gray-100',   text: 'text-nothing-gray-600' },
}

function SeverityBadge({ severity, label }: { severity: string; label: string }) {
  const style = SEVERITY_STYLE[severity] ?? SEVERITY_STYLE['P3']
  return (
    <span className={cn(
      'inline-flex items-center gap-1 px-2 py-0.5 rounded font-body text-[11px] font-bold uppercase',
      style.bg, style.text
    )}>
      {severity === 'P0' && <AlertTriangle className="w-3 h-3" />}
      {severity === 'P1' && <AlertCircle className="w-3 h-3" />}
      {(severity === 'P2' || severity === 'P3') && <Info className="w-3 h-3" />}
      {label} · {severity}
    </span>
  )
}

// =============================================================================
// Stat pill
// =============================================================================

function StatPill({ label, value, highlight }: { label: string; value: number; highlight?: boolean }) {
  return (
    <div className={cn(
      'flex flex-col items-center px-5 py-3 rounded-lg border',
      highlight && value > 0
        ? 'bg-status-critical/5 border-status-critical/20'
        : 'bg-white border-nothing-gray-200'
    )}>
      <span className={cn(
        'text-2xl font-bold font-body tabular-nums',
        highlight && value > 0 ? 'text-status-critical' : 'text-nothing-black'
      )}>
        {value}
      </span>
      <span className="text-[11px] font-body text-nothing-gray-500 uppercase tracking-wider mt-0.5">
        {label}
      </span>
    </div>
  )
}

interface SourceCoverageSummary {
  source_count: number
  with_source_refs_total: number
  missing_source_refs_total: number
  sentry_ref_total: number
  signoz_ref_total: number
  alert_ref_total: number
  latest_received_at?: string | null
}

interface SourceCoverageProvider {
  provider: string
  total: number
  missing_source_refs_total: number
  sentry_ref_total: number
  signoz_ref_total: number
  alert_ref_total: number
  latest_received_at?: string | null
}

interface SourceCoverageResponse {
  summary: SourceCoverageSummary
  providers: SourceCoverageProvider[]
}

function percentLabel(value: number, total: number) {
  if (total <= 0) return '--'
  return `${Math.round((value / total) * 100)}%`
}

function parseApiTimestamp(value?: string | null) {
  if (!value) return null
  const normalized = /(?:z|[+-]\d{2}:?\d{2})$/i.test(value) ? value : `${value}Z`
  const date = new Date(normalized)
  return Number.isNaN(date.getTime()) ? null : date
}

function formatTimestamp(value: string | null | undefined, locale: string, emptyLabel: string) {
  const date = parseApiTimestamp(value)
  if (!date) return emptyLabel
  return new Intl.DateTimeFormat(locale, {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  }).format(date)
}

function freshnessAgeHours(value?: string | null) {
  const date = parseApiTimestamp(value)
  if (!date) return null
  return Math.max(0, (Date.now() - date.getTime()) / 3_600_000)
}

function freshnessToneClass(ageHours: number | null) {
  if (ageHours === null || ageHours > SOURCE_FRESHNESS_STALE_HOURS) {
    return 'border-status-warning/30 bg-status-warning/5 text-status-warning'
  }
  return 'border-status-healthy/30 bg-status-healthy/5 text-status-healthy'
}

function valueOrEmpty(value: unknown, emptyLabel: string) {
  if (value === null || value === undefined || value === '') return emptyLabel
  return String(value)
}

function FocusIncidentEvidencePanel({
  incidentId,
  projectId,
  incident,
  chain,
  loading,
  locale,
}: {
  incidentId: string
  projectId: string
  incident?: IncidentResponse | null
  chain?: AwoooPStatusChain | null
  loading: boolean
  locale: string
}) {
  const t = useTranslations('alerts.focus')
  const emptyLabel = t('emptyValue')
  const encodedProjectId = encodeURIComponent(projectId)
  const encodedIncidentId = encodeURIComponent(incidentId)
  const sourceCorrelation = chain?.source_refs?.correlation
  const sourceStatus = String(sourceCorrelation?.status ?? 'missing')
  const statusLabels: Record<string, string> = {
    linked: t('sourceStatuses.linked'),
    candidate_found: t('sourceStatuses.candidateFound'),
    provider_fresh_no_match: t('sourceStatuses.providerFreshNoMatch'),
    missing: t('sourceStatuses.missing'),
    no_incident_context: t('sourceStatuses.noIncidentContext'),
    fetch_failed: t('sourceStatuses.fetchFailed'),
  }
  const sourceStatusLabel = statusLabels[sourceStatus] ?? valueOrEmpty(sourceStatus, emptyLabel)
  const mcpGateway = chain?.mcp?.gateway
  const ansible = chain?.execution?.ansible
  const outcomeState = String(chain?.operator_outcome?.state ?? '')
  const nextAction = String(chain?.operator_outcome?.next_action ?? chain?.next_step ?? '')
  const humanReason = String(chain?.operator_outcome?.human_action_reason ?? '')
  const sourceReasonCode = String(sourceCorrelation?.missing_reason ?? '')
  const outcomeStateLabels: Record<string, string> = {
    verification_degraded_manual_required: t('operatorFlow.stateLabels.verificationDegradedManualRequired'),
  }
  const nextActionLabels: Record<string, string> = {
    manual_verify_or_repair: t('operatorFlow.nextActionLabels.manualVerifyOrRepair'),
  }
  const humanReasonLabels: Record<string, string> = {
    incident_open_after_successful_execution: t('operatorFlow.reasonLabels.incidentOpenAfterSuccessfulExecution'),
  }
  const sourceReasonLabels: Record<string, string> = {
    provider_heartbeat_present_but_no_incident_match: t('operatorFlow.sourceReasonLabels.providerHeartbeatPresentButNoIncidentMatch'),
  }
  const outcomeStateLabel = outcomeStateLabels[outcomeState] ?? valueOrEmpty(outcomeState, emptyLabel)
  const nextActionLabel = nextActionLabels[nextAction] ?? valueOrEmpty(nextAction, emptyLabel)
  const humanReasonLabel = humanReasonLabels[humanReason] ?? valueOrEmpty(humanReason, emptyLabel)
  const sourceReasonLabel = sourceReasonLabels[sourceReasonCode] ?? valueOrEmpty(sourceReasonCode, emptyLabel)
  const relatedIncidentIds = chain?.source_refs?.refs?.incident_ids ?? []
  const fingerprint = chain?.source_refs?.refs?.fingerprints?.[0] ?? emptyLabel
  const latestInbound = chain?.source_refs?.latest_inbound
  const latestOutbound = chain?.source_refs?.latest_outbound
  const isDuplicateInbound = latestInbound?.is_duplicate === true
  const repeatStateKey = !chain
    ? 'unknown'
    : isDuplicateInbound
      ? 'duplicate'
      : relatedIncidentIds.length > 1
        ? 'related'
        : 'single'
  const repeatStateLabel = t(`operatorFlow.repeatStates.${repeatStateKey}`)
  const latestInboundLabel = latestInbound?.received_at
    ? formatTimestamp(latestInbound.received_at, locale, emptyLabel)
    : emptyLabel
  const latestOutboundLabel = latestOutbound?.sent_at
    ? formatTimestamp(latestOutbound.sent_at, locale, emptyLabel)
    : emptyLabel
  const needsHumanLabel = chain?.needs_human ? t('operatorFlow.needsHumanYes') : t('operatorFlow.needsHumanNo')
  const handoffTone = !chain ? 'gray' : chain.needs_human ? 'red' : 'green'
  const handoffTitle = chain?.needs_human
    ? t('operatorFlow.handoff.titleManual')
    : chain
      ? t('operatorFlow.handoff.titleAutomated')
      : t('operatorFlow.handoff.titleUnknown')
  const handoffAction = !chain
    ? t('operatorFlow.handoff.actionUnknown')
    : chain.needs_human
      ? t('operatorFlow.handoff.actionManualVerifyOrRepair')
      : t('operatorFlow.handoff.actionNoManual')
  const handoffOwner = chain?.needs_human
    ? t('operatorFlow.handoff.ownerSre')
    : chain
      ? t('operatorFlow.handoff.ownerAutomation')
      : emptyLabel
  const handoffEntry = chain?.needs_human
    ? t('operatorFlow.handoff.entryManual')
    : chain
      ? t('operatorFlow.handoff.entryReadOnly')
      : emptyLabel
  const handoffReason = chain?.needs_human ? humanReasonLabel : valueOrEmpty(chain?.verdict, emptyLabel)
  const handoffLinks = [
    {
      key: 'workItems',
      label: t('links.workItems'),
      href: `/awooop/work-items?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
      Icon: ListChecks,
    },
    {
      key: 'approvals',
      label: t('links.approvals'),
      href: `/awooop/approvals?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
      Icon: ShieldCheck,
    },
    {
      key: 'runs',
      label: t('links.runs'),
      href: `/awooop/runs?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
      Icon: Activity,
    },
  ]
  const operatorCards = [
    {
      key: 'repeat',
      Icon: Repeat2,
      title: t('operatorFlow.repeatTitle'),
      value: t('operatorFlow.repeatValue', {
        state: repeatStateLabel,
        count: relatedIncidentIds.length,
      }),
      detail: t('operatorFlow.repeatDetail', {
        fingerprint,
        latest: latestInboundLabel,
      }),
      tone: repeatStateKey === 'single' ? 'green' : repeatStateKey === 'unknown' ? 'gray' : 'amber',
      testId: 'alerts-repeat-state',
    },
    {
      key: 'telegram',
      Icon: MessageSquareText,
      title: t('operatorFlow.telegramTitle'),
      value: t('operatorFlow.telegramValue', {
        channel: valueOrEmpty(latestOutbound?.channel_type, emptyLabel),
        status: valueOrEmpty(latestOutbound?.send_status, emptyLabel),
      }),
      detail: t('operatorFlow.telegramDetail', {
        type: valueOrEmpty(latestOutbound?.message_type, emptyLabel),
        outbound: chain?.source_refs?.outbound_total ?? 0,
        latest: latestOutboundLabel,
      }),
      tone: latestOutbound?.send_status === 'sent' ? 'green' : latestOutbound ? 'amber' : 'gray',
      testId: 'alerts-telegram-state',
    },
    {
      key: 'ai',
      Icon: Activity,
      title: t('operatorFlow.aiTitle'),
      value: valueOrEmpty(chain?.operator_outcome?.summary_zh ?? chain?.verdict, emptyLabel),
      detail: t('operatorFlow.aiDetail', {
        state: outcomeStateLabel,
        nextStep: nextActionLabel,
        needsHuman: needsHumanLabel,
      }),
      tone: chain?.needs_human ? 'red' : chain ? 'green' : 'gray',
      testId: 'alerts-ai-state',
    },
    {
      key: 'source',
      Icon: Link2,
      title: t('operatorFlow.sourceTitle'),
      value: sourceStatusLabel,
      detail: t('operatorFlow.sourceDetail', {
        direct: sourceCorrelation?.direct_ref_total ?? 0,
        candidate: sourceCorrelation?.candidate_total ?? 0,
        applied: sourceCorrelation?.applied_link_total ?? 0,
        reason: sourceReasonLabel,
      }),
      tone: sourceStatus === 'linked' ? 'green' : sourceStatus === 'missing' ? 'red' : 'amber',
      testId: 'alerts-source-state',
    },
  ]
  const navItems = [
    {
      key: 'monitoring',
      label: t('links.monitoring'),
      href: `/monitoring?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
      Icon: Monitor,
    },
    {
      key: 'workItems',
      label: t('links.workItems'),
      href: `/awooop/work-items?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
      Icon: ListChecks,
    },
    {
      key: 'runs',
      label: t('links.runs'),
      href: `/awooop/runs?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
      Icon: Activity,
    },
    {
      key: 'approvals',
      label: t('links.approvals'),
      href: `/awooop/approvals?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
      Icon: ShieldCheck,
    },
    {
      key: 'tickets',
      label: t('links.tickets'),
      href: `/tickets?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
      Icon: GitBranch,
    },
  ]

  return (
    <section
      data-testid="alerts-incident-focus"
      className="mb-6 overflow-hidden rounded-lg border border-[#e0ddd4] bg-white"
    >
      <div className="flex flex-wrap items-start justify-between gap-3 border-b border-[#e0ddd4] bg-[#faf9f3] px-4 py-4">
        <div className="flex min-w-0 items-start gap-3">
          <span className="flex h-9 w-9 shrink-0 items-center justify-center border border-[#9bb6d9] bg-[#eef5ff] text-[#1f5b9b]">
            <SearchCheck className="h-4 w-4" aria-hidden="true" />
          </span>
          <div className="min-w-0">
            <h3 className="text-sm font-semibold text-[#141413]">{t('title')}</h3>
            <p className="mt-1 text-xs leading-5 text-[#77736a]">
              {t('subtitle', {
                incidentId,
                service: incident?.affected_services?.[0] ?? valueOrEmpty(chain?.source_id, emptyLabel),
              })}
              {loading ? ` · ${t('loading')}` : ''}
            </p>
          </div>
        </div>
        <div className="flex flex-wrap gap-2">
          {navItems.map(({ key, label, href, Icon }) => (
            <Link
              key={key}
              href={href}
              className="inline-flex items-center gap-1.5 border border-[#d8d3c7] bg-white px-2.5 py-1.5 text-xs font-semibold text-[#3f3a32] hover:bg-[#f5f1e8]"
            >
              <Icon className="h-3.5 w-3.5" aria-hidden="true" />
              {label}
              <Link2 className="h-3 w-3" aria-hidden="true" />
            </Link>
          ))}
        </div>
      </div>

      <div className="grid gap-px bg-[#e0ddd4] md:grid-cols-4">
        <div className="min-w-0 bg-white px-4 py-3">
          <p className="text-xs font-semibold text-[#77736a]">{t('metrics.sourceRefs')}</p>
          <p className="mt-2 font-mono text-sm font-semibold text-[#141413]">
            {t('metrics.sourceRefsValue', {
              inbound: chain?.source_refs?.inbound_total ?? 0,
              outbound: chain?.source_refs?.outbound_total ?? 0,
            })}
          </p>
        </div>
        <div className="min-w-0 bg-white px-4 py-3">
          <p className="text-xs font-semibold text-[#77736a]">{t('metrics.provider')}</p>
          <p className="mt-2 truncate font-mono text-sm font-semibold text-[#141413]" title={sourceStatusLabel}>
            {sourceStatusLabel}
          </p>
        </div>
        <div className="min-w-0 bg-white px-4 py-3">
          <p className="text-xs font-semibold text-[#77736a]">{t('metrics.mcp')}</p>
          <p className="mt-2 font-mono text-sm font-semibold text-[#141413]">
            {t('metrics.mcpValue', { success: mcpGateway?.success ?? 0, total: mcpGateway?.total ?? 0 })}
          </p>
        </div>
        <div className="min-w-0 bg-white px-4 py-3">
          <p className="text-xs font-semibold text-[#77736a]">{t('metrics.ansible')}</p>
          <p className="mt-2 truncate font-mono text-sm font-semibold text-[#141413]" title={valueOrEmpty(ansible?.latest_playbook_path, emptyLabel)}>
            {valueOrEmpty(ansible?.latest_status ?? chain?.execution?.latest_status, emptyLabel)}
          </p>
        </div>
      </div>

      {!incident && (
        <div className="border-t border-[#e0ddd4] bg-[#fff7e8] px-4 py-3 text-xs leading-5 text-[#8a5a08]">
          {t('notInActiveList')}
        </div>
      )}

      <div className="border-t border-[#e0ddd4] bg-[#faf9f3] px-4 py-3 text-xs leading-5 text-[#5f5b52]">
        {t('boundary')}
      </div>

      <div data-testid="alerts-operator-flow" className="border-t border-[#e0ddd4] bg-white px-4 py-4">
        <div className="mb-3">
          <p className="text-sm font-semibold text-[#141413]">{t('operatorFlow.title')}</p>
          <p className="mt-1 text-xs leading-5 text-[#77736a]">{t('operatorFlow.subtitle')}</p>
        </div>
        <div
          data-testid="alerts-operator-handoff"
          className={cn(
            'mb-3 border px-3 py-3',
            handoffTone === 'green' && 'border-[#9bc7a4] bg-[#f0faf2]',
            handoffTone === 'red' && 'border-[#e2a29b] bg-[#fff0ef]',
            handoffTone === 'gray' && 'border-[#d8d3c7] bg-[#faf9f3]',
          )}
        >
          <div className="flex flex-wrap items-start justify-between gap-3">
            <div className="min-w-0">
              <p className="text-xs font-semibold text-[#5f5b52]">{t('operatorFlow.handoff.eyebrow')}</p>
              <p className="mt-1 text-sm font-semibold text-[#141413]">{handoffTitle}</p>
              <p className="mt-1 text-xs leading-5 text-[#77736a]">{handoffAction}</p>
            </div>
            <div className="flex shrink-0 flex-wrap gap-2">
              {handoffLinks.map(({ key, label, href, Icon }) => (
                <Link
                  key={key}
                  href={href}
                  className="inline-flex items-center gap-1.5 border border-[#d8d3c7] bg-white/80 px-2.5 py-1.5 text-xs font-semibold text-[#3f3a32] hover:bg-white"
                >
                  <Icon className="h-3.5 w-3.5" aria-hidden="true" />
                  {label}
                </Link>
              ))}
            </div>
          </div>
          <div className="mt-3 grid gap-2 md:grid-cols-4">
            <div className="min-w-0 border border-current/10 bg-white/60 px-2.5 py-2">
              <p className="text-[11px] font-semibold uppercase text-[#77736a]">{t('operatorFlow.handoff.ownerLabel')}</p>
              <p className="mt-1 truncate text-xs font-semibold text-[#141413]" title={handoffOwner}>{handoffOwner}</p>
            </div>
            <div className="min-w-0 border border-current/10 bg-white/60 px-2.5 py-2">
              <p className="text-[11px] font-semibold uppercase text-[#77736a]">{t('operatorFlow.handoff.entryLabel')}</p>
              <p className="mt-1 truncate text-xs font-semibold text-[#141413]" title={handoffEntry}>{handoffEntry}</p>
            </div>
            <div className="min-w-0 border border-current/10 bg-white/60 px-2.5 py-2">
              <p className="text-[11px] font-semibold uppercase text-[#77736a]">{t('operatorFlow.handoff.reasonLabel')}</p>
              <p className="mt-1 truncate text-xs font-semibold text-[#141413]" title={handoffReason}>{handoffReason}</p>
            </div>
            <div className="min-w-0 border border-current/10 bg-white/60 px-2.5 py-2">
              <p className="text-[11px] font-semibold uppercase text-[#77736a]">{t('operatorFlow.handoff.boundaryLabel')}</p>
              <p className="mt-1 truncate text-xs font-semibold text-[#141413]" title={t('operatorFlow.handoff.boundary')}>{t('operatorFlow.handoff.boundary')}</p>
            </div>
          </div>
        </div>
        <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
          {operatorCards.map(({ key, Icon, title, value, detail, tone, testId }) => (
            <div
              key={key}
              data-testid={testId}
              className={cn(
                'min-w-0 border px-3 py-3',
                tone === 'green' && 'border-[#9bc7a4] bg-[#f0faf2]',
                tone === 'amber' && 'border-[#d9b36f] bg-[#fff7e8]',
                tone === 'red' && 'border-[#e2a29b] bg-[#fff0ef]',
                tone === 'gray' && 'border-[#d8d3c7] bg-[#faf9f3]',
              )}
            >
              <div className="flex min-w-0 items-start gap-2">
                <span className="mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center border border-current/20 bg-white/60">
                  <Icon className="h-3.5 w-3.5" aria-hidden="true" />
                </span>
                <div className="min-w-0">
                  <p className="text-xs font-semibold text-[#5f5b52]">{title}</p>
                  <p className="mt-1 truncate text-sm font-semibold text-[#141413]" title={value}>
                    {value}
                  </p>
                  <p className="mt-1 line-clamp-2 text-xs leading-5 text-[#77736a]" title={detail}>
                    {detail}
                  </p>
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>

      <AwoooPStatusChainPanel chain={chain ?? null} compact className="border-x-0 border-b-0" />
    </section>
  )
}

// =============================================================================
// Page
// =============================================================================

export default function AlertsPage({ params }: { params: { locale: string } }) {
  const t = useTranslations()
  const tAlerts = useTranslations('alerts')
  const searchParams = useSearchParams()
  const projectId = searchParams.get('project_id') ?? 'awoooi'
  const focusedIncidentId = searchParams.get('incident_id')?.trim() || null

  const { incidents, isLoading, error, refresh, lastUpdated } = useIncidents({
    pollInterval: 15000,
    enablePolling: true,
  })
  const [sourceCoverage, setSourceCoverage] = useState<SourceCoverageResponse | null>(null)
  const [providerCoverage, setProviderCoverage] = useState<Record<string, SourceCoverageResponse | null>>({
    sentry: null,
    signoz: null,
  })
  const [sourceCoverageError, setSourceCoverageError] = useState<string | null>(null)
  const [sourceCoverageLoading, setSourceCoverageLoading] = useState(false)

  const sorted = useMemo(() => {
    return [...(incidents ?? [])].sort(
      (a, b) => (SEVERITY_ORDER[a.severity] ?? 9) - (SEVERITY_ORDER[b.severity] ?? 9)
    )
  }, [incidents])
  const visibleSorted = useMemo(() => {
    if (!focusedIncidentId) return sorted
    return sorted.filter(incident => incident.incident_id === focusedIncidentId)
  }, [focusedIncidentId, sorted])
  const focusedIncident = focusedIncidentId
    ? sorted.find(incident => incident.incident_id === focusedIncidentId) ?? null
    : null
  const [currentPage, setCurrentPage] = useState(1)
  const totalPages = Math.max(1, Math.ceil(visibleSorted.length / ALERTS_PAGE_SIZE))
  const pageStart = (currentPage - 1) * ALERTS_PAGE_SIZE
  const pageIncidents = visibleSorted.slice(pageStart, pageStart + ALERTS_PAGE_SIZE)
  const pageFrom = visibleSorted.length === 0 ? 0 : pageStart + 1
  const pageTo = pageStart + pageIncidents.length

  useEffect(() => {
    setCurrentPage(page => Math.min(Math.max(page, 1), totalPages))
  }, [totalPages])

  useEffect(() => {
    setCurrentPage(1)
  }, [focusedIncidentId])

  const statusChainIncidentIds = useMemo(() => {
    return Array.from(new Set([
      ...pageIncidents.map(incident => incident.incident_id),
      ...(focusedIncidentId ? [focusedIncidentId] : []),
    ]))
  }, [focusedIncidentId, pageIncidents])
  const {
    statusChains,
    requestedIncidentIds,
    isLoading: isStatusChainLoading,
  } = useIncidentStatusChains({
    incidentIds: statusChainIncidentIds,
    limit: ALERTS_PAGE_SIZE + 1,
    projectId,
    refreshKey: lastUpdated?.toISOString() ?? null,
  })
  const truthChainLoaded = requestedIncidentIds.filter(incidentId => {
    const chain = statusChains[incidentId]
    return Boolean(chain?.source_id && !chain.fetch_error)
  }).length

  useEffect(() => {
    let active = true
    const controller = new AbortController()
    async function loadSourceCoverage() {
      setSourceCoverageLoading(true)
      setSourceCoverageError(null)
      try {
        const buildCoverageUrl = (provider?: string) => {
          const params = new URLSearchParams()
          params.set('project_id', 'awoooi')
          params.set('limit', String(SOURCE_COVERAGE_LIMIT))
          if (provider) params.set('provider', provider)
          return `${API_V1_URL}/platform/events/dossier/coverage?${params.toString()}`
        }
        const [overallResponse, sentryResponse, signozResponse] = await Promise.all([
          fetch(buildCoverageUrl(), { signal: controller.signal }),
          fetch(buildCoverageUrl('sentry'), { signal: controller.signal }),
          fetch(buildCoverageUrl('signoz'), { signal: controller.signal }),
        ])
        if (!overallResponse.ok) throw new Error(`overall HTTP ${overallResponse.status}`)
        if (!sentryResponse.ok) throw new Error(`sentry HTTP ${sentryResponse.status}`)
        if (!signozResponse.ok) throw new Error(`signoz HTTP ${signozResponse.status}`)
        const [overallData, sentryData, signozData] = await Promise.all([
          overallResponse.json() as Promise<SourceCoverageResponse>,
          sentryResponse.json() as Promise<SourceCoverageResponse>,
          signozResponse.json() as Promise<SourceCoverageResponse>,
        ])
        if (active) {
          setSourceCoverage(overallData)
          setProviderCoverage({ sentry: sentryData, signoz: signozData })
        }
      } catch (err) {
        if (controller.signal.aborted) return
        if (active) setSourceCoverageError(err instanceof Error ? err.message : String(err))
      } finally {
        if (active) setSourceCoverageLoading(false)
      }
    }
    loadSourceCoverage()
    return () => {
      active = false
      controller.abort()
    }
  }, [lastUpdated])

  const p0Count = sorted.filter(i => i.severity === 'P0').length
  const p1Count = sorted.filter(i => i.severity === 'P1').length
  const p2Count = sorted.filter(i => i.severity === 'P2').length
  const p3Count = sorted.filter(i => i.severity === 'P3').length
  const coverageSummary = sourceCoverage?.summary
  const topCoverageProviders = sourceCoverage?.providers?.slice(0, 3) ?? []
  const sentryCoverageSummary = providerCoverage.sentry?.summary
  const signozCoverageSummary = providerCoverage.signoz?.summary
  const emptyFreshnessLabel = tAlerts('sourceCoverageNoEvents')
  const formatFreshnessAge = (value?: string | null) => {
    const ageHours = freshnessAgeHours(value)
    if (ageHours === null) return emptyFreshnessLabel
    if (ageHours <= SOURCE_FRESHNESS_STALE_HOURS) return tAlerts('sourceCoverageFresh')
    if (ageHours < 48) return tAlerts('sourceCoverageStaleHours', { hours: Math.floor(ageHours) })
    return tAlerts('sourceCoverageStaleDays', { days: Math.floor(ageHours / 24) })
  }
  const coverageFreshnessAge = freshnessAgeHours(coverageSummary?.latest_received_at)
  const sentryFreshnessAge = freshnessAgeHours(sentryCoverageSummary?.latest_received_at)
  const signozFreshnessAge = freshnessAgeHours(signozCoverageSummary?.latest_received_at)

  return (
    <AppLayout locale={params.locale}>
      {/* Header */}
      <div className="flex items-center justify-between mb-6">
        <div>
          <h2 className="font-heading text-2xl font-bold text-nothing-black flex items-center gap-2">
            <Bell className="w-6 h-6" />
            {t('nav.alerts')}
          </h2>
          <p className="mt-1 text-sm text-nothing-gray-500 font-body">
            {t('incident.activeIncidents')} · {t('alerts.autoRefresh', { seconds: 15 })}
          </p>
        </div>
        <button
          onClick={refresh}
          disabled={isLoading}
          className={cn(
            'flex items-center gap-1.5 px-3 py-1.5 rounded-lg',
            'text-xs font-body bg-nothing-gray-100 text-nothing-gray-600',
            'hover:bg-nothing-gray-200 transition-colors',
            'disabled:opacity-50 disabled:cursor-not-allowed'
          )}
        >
          <RefreshCw className={cn('w-3.5 h-3.5', isLoading && 'animate-spin')} />
          {t('common.refresh')}
        </button>
      </div>

      <IwoooSReadOnlyBridge />

      {/* Severity Stats */}
      <div className="grid grid-cols-4 gap-3 mb-6">
        <StatPill label={t('incident.severity.P0')} value={p0Count} highlight />
        <StatPill label={t('incident.severity.P1')} value={p1Count} />
        <StatPill label={t('incident.severity.P2')} value={p2Count} />
        <StatPill label={t('incident.severity.P3')} value={p3Count} />
      </div>

      <div className="mb-6 rounded-lg border border-nothing-gray-200 bg-white px-4 py-3">
        <div className="flex flex-wrap items-start justify-between gap-3">
          <div>
            <p className="font-body text-sm font-semibold text-nothing-black">
              {tAlerts('sourceCoverageTitle')}
            </p>
            <p className="mt-1 font-body text-xs text-nothing-gray-500">
              {sourceCoverageError
                ? tAlerts('sourceCoverageError', { error: sourceCoverageError })
                : tAlerts('sourceCoverageSubtitle', { limit: SOURCE_COVERAGE_LIMIT })}
              {sourceCoverageLoading ? ` · ${t('common.loading')}` : ''}
            </p>
          </div>
          <div className="grid grid-cols-2 gap-2 md:grid-cols-5">
            <StatPill
              label={tAlerts('sourceCoverageWithRefs')}
              value={coverageSummary?.with_source_refs_total ?? 0}
            />
            <StatPill
              label={tAlerts('sourceCoverageMissing')}
              value={coverageSummary?.missing_source_refs_total ?? 0}
              highlight
            />
            <StatPill
              label={tAlerts('sourceCoverageAlert')}
              value={coverageSummary?.alert_ref_total ?? 0}
            />
            <StatPill
              label={tAlerts('sourceCoverageSentry')}
              value={coverageSummary?.sentry_ref_total ?? 0}
              highlight={(coverageSummary?.source_count ?? 0) > 0 && (coverageSummary?.sentry_ref_total ?? 0) === 0}
            />
            <StatPill
              label={tAlerts('sourceCoverageSigNoz')}
              value={coverageSummary?.signoz_ref_total ?? 0}
              highlight={(coverageSummary?.source_count ?? 0) > 0 && (coverageSummary?.signoz_ref_total ?? 0) === 0}
            />
          </div>
        </div>
        <div className="mt-3 flex flex-wrap gap-2 font-body text-xs text-nothing-gray-500">
          <span className="rounded border border-nothing-gray-200 bg-nothing-gray-50 px-2 py-1">
            {tAlerts('sourceCoverageRatio', {
              ratio: percentLabel(coverageSummary?.with_source_refs_total ?? 0, coverageSummary?.source_count ?? 0),
              total: coverageSummary?.source_count ?? 0,
            })}
          </span>
          <span className={cn(
            'rounded border px-2 py-1',
            freshnessToneClass(coverageFreshnessAge)
          )}>
            {tAlerts('sourceCoverageFreshness', {
              provider: 'overall',
              latest: formatTimestamp(coverageSummary?.latest_received_at, params.locale, emptyFreshnessLabel),
              age: formatFreshnessAge(coverageSummary?.latest_received_at),
            })}
          </span>
          {topCoverageProviders.map(provider => (
            <span
              key={provider.provider}
              className={cn(
                'rounded border px-2 py-1',
                freshnessToneClass(freshnessAgeHours(provider.latest_received_at))
              )}
            >
              {tAlerts('sourceCoverageProvider', {
                provider: provider.provider,
                total: provider.total,
                missing: provider.missing_source_refs_total,
                sentry: provider.sentry_ref_total,
                signoz: provider.signoz_ref_total,
                latest: formatTimestamp(provider.latest_received_at, params.locale, emptyFreshnessLabel),
                age: formatFreshnessAge(provider.latest_received_at),
              })}
            </span>
          ))}
          <span className={cn(
            'rounded border px-2 py-1',
            freshnessToneClass(sentryFreshnessAge)
          )}>
            {tAlerts('sourceCoverageProviderWindow', {
              provider: 'sentry',
              total: sentryCoverageSummary?.source_count ?? 0,
              withRefs: sentryCoverageSummary?.with_source_refs_total ?? 0,
              missing: sentryCoverageSummary?.missing_source_refs_total ?? 0,
              latest: formatTimestamp(sentryCoverageSummary?.latest_received_at, params.locale, emptyFreshnessLabel),
              age: formatFreshnessAge(sentryCoverageSummary?.latest_received_at),
            })}
          </span>
          <span className={cn(
            'rounded border px-2 py-1',
            freshnessToneClass(signozFreshnessAge)
          )}>
            {tAlerts('sourceCoverageProviderWindow', {
              provider: 'signoz',
              total: signozCoverageSummary?.source_count ?? 0,
              withRefs: signozCoverageSummary?.with_source_refs_total ?? 0,
              missing: signozCoverageSummary?.missing_source_refs_total ?? 0,
              latest: formatTimestamp(signozCoverageSummary?.latest_received_at, params.locale, emptyFreshnessLabel),
              age: formatFreshnessAge(signozCoverageSummary?.latest_received_at),
            })}
          </span>
        </div>
      </div>

      {focusedIncidentId && (
        <FocusIncidentEvidencePanel
          incidentId={focusedIncidentId}
          projectId={projectId}
          incident={focusedIncident}
          chain={statusChains[focusedIncidentId] ?? null}
          loading={isStatusChainLoading}
          locale={params.locale}
        />
      )}

      {visibleSorted.length > 0 && (
        <div className="mb-6 flex flex-wrap items-center justify-between gap-3 rounded-lg border border-nothing-gray-200 bg-white px-4 py-3">
          <div>
            <p className="font-body text-sm font-semibold text-nothing-black">
              {focusedIncidentId
                ? tAlerts('focusedPageSummary', { incidentId: focusedIncidentId, total: visibleSorted.length })
                : tAlerts('pageSummary', { from: pageFrom, to: pageTo, total: visibleSorted.length })}
            </p>
            <p className="mt-1 font-body text-xs text-nothing-gray-500">
              {tAlerts('statusChainWindow', {
                loaded: truthChainLoaded,
                shown: requestedIncidentIds.length,
              })}
              {isStatusChainLoading ? ` · ${t('common.loading')}` : ''}
            </p>
          </div>
          <div className="flex items-center gap-2">
            <button
              type="button"
              onClick={() => setCurrentPage(page => Math.max(1, page - 1))}
              disabled={currentPage <= 1}
              className="inline-flex items-center gap-1 rounded-lg border border-nothing-gray-200 bg-nothing-gray-50 px-3 py-1.5 font-body text-xs text-nothing-gray-700 transition-colors hover:bg-nothing-gray-100 disabled:cursor-not-allowed disabled:opacity-40"
            >
              <ChevronLeft className="h-3.5 w-3.5" />
              {tAlerts('previousPage')}
            </button>
            <span className="font-body text-xs text-nothing-gray-500">
              {tAlerts('pageIndicator', { page: currentPage, totalPages })}
            </span>
            <button
              type="button"
              onClick={() => setCurrentPage(page => Math.min(totalPages, page + 1))}
              disabled={currentPage >= totalPages}
              className="inline-flex items-center gap-1 rounded-lg border border-nothing-gray-200 bg-nothing-gray-50 px-3 py-1.5 font-body text-xs text-nothing-gray-700 transition-colors hover:bg-nothing-gray-100 disabled:cursor-not-allowed disabled:opacity-40"
            >
              {tAlerts('nextPage')}
              <ChevronRight className="h-3.5 w-3.5" />
            </button>
          </div>
        </div>
      )}

      {focusedIncidentId && visibleSorted.length === 0 && !isLoading && (
        <div className="mb-6 rounded-lg border border-status-warning/25 bg-status-warning/5 px-4 py-3">
          <p className="font-body text-sm font-semibold text-status-warning">
            {tAlerts('focusedNotActiveTitle', { incidentId: focusedIncidentId })}
          </p>
          <p className="mt-1 font-body text-xs leading-5 text-nothing-gray-600">
            {tAlerts('focusedNotActiveDescription')}
          </p>
        </div>
      )}

      {/* Error */}
      {error && (
        <div className="mb-4 p-4 rounded-lg bg-status-critical/10 border border-status-critical/20 flex items-center gap-2">
          <AlertCircle className="w-4 h-4 text-status-critical" />
          <span className="text-sm font-body text-status-critical">{error}</span>
        </div>
      )}

      {/* Loading skeleton */}
      {isLoading && sorted.length === 0 && (
        <div className="flex items-center justify-center py-16">
          <RefreshCw className="w-6 h-6 animate-spin text-nothing-gray-400" />
          <span className="ml-2 text-nothing-gray-400 font-body text-sm">{t('common.loading')}</span>
        </div>
      )}

      {/* Empty state */}
      {!isLoading && sorted.length === 0 && !error && (
        <div className="flex flex-col items-center justify-center py-20 text-center">
          <BellOff className="w-12 h-12 text-nothing-gray-300 mb-4" />
          <p className="font-body text-nothing-gray-500 text-sm">{t('incident.noActiveIncidents')}</p>
          <p className="font-body text-nothing-gray-400 text-xs mt-1">{t('incident.systemStable')}</p>
        </div>
      )}

      {/* Incidents grouped by severity */}
      {pageIncidents.length > 0 && (
        <div className="space-y-6">
          {(['P0', 'P1', 'P2', 'P3'] as const).map(sev => {
            const group = pageIncidents.filter(i => i.severity === sev)
            if (group.length === 0) return null
            return (
              <div key={sev}>
                {/* Section header */}
                <div className="flex items-center gap-3 mb-3">
                  <SeverityBadge severity={sev} label={t(`incident.severity.${sev}`)} />
                  <span className="text-[11px] font-body text-nothing-gray-400">
                    {tAlerts('incidentCount', { count: group.length })}
                  </span>
                  <div className="flex-1 h-px bg-nothing-gray-200" />
                </div>
                <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                  {group.map(incident => (
                    <IncidentCard
                      key={incident.incident_id}
                      incident={incident}
                      projectId={projectId}
                      statusChain={statusChains[incident.incident_id] ?? null}
                    />
                  ))}
                </div>
              </div>
            )
          })}
        </div>
      )}
    </AppLayout>
  )
}
