/* /status — System health dashboard.
 *
 * Pulls from:
 *   GET /api/dashboard/integration-health  (live API check + token expiry)
 *   GET /api/dashboard/overview            (syncHealth array)
 *
 * Surfaces what's wrong so the dashboard can stay focused on operational
 * KPIs.  Polls every 60 s while the page is visible. */

'use client';

import { useEffect, useState } from 'react';
import { PageHeader } from '@/components/navigation/page-header';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Button } from '@/components/ui/button';
import { Skeleton } from '@/components/ui/skeleton';
import { EmptyState } from '@/components/ui/empty-state';
import { StatusLight, type StatusLightState } from '@/components/ui/status-light';
import { StatusBadge } from '@/components/ui/status-badge';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table';
import { WorkerPulse } from '@/components/status/worker-pulse';
import {
  AlertTriangle,
  KeyRound,
  RefreshCw,
  ShieldCheck,
  Plug,
  Clock,
  Activity,
} from 'lucide-react';

// ── Types ────────────────────────────────────────────────────────────

type IntegrationCategory =
  | 'psa' | 'rmm' | 'docs' | 'security' | 'backup'
  | 'network' | 'identity' | 'mdm' | 'mail'
  | 'finance' | 'productivity' | 'llm';

interface IntegrationHealthItem {
  key: string;
  name: string;
  category: IntegrationCategory;
  status: 'ok' | 'auth_failed' | 'unreachable' | 'not_configured' | 'unknown' | 'disabled';
  configured: boolean;
  latencyMs?: number;
  error?: string | null;
  tokenExpiry?: {
    envVar: string;
    expiresAt: string;
    daysRemaining: number;
    subject?: string | null;
  } | null;
  checkedAt: string;
}

interface IntegrationHealthResponse {
  items: IntegrationHealthItem[];
  summary: {
    total: number;
    ok: number;
    failed: number;
    notConfigured: number;
    disabled: number;
    expiringWithin14Days: number;
    expired: number;
    hasIssues: boolean;
  };
}

interface SyncHealthItem {
  id: string;
  name: string;
  syncType: string;
  isEnabled: boolean;
  lastRun: string | null;
  lastStatus: string | null;
  lastError: string | null;
  nextRun: string | null;
}

interface OverviewResponse {
  syncHealth: SyncHealthItem[];
}

interface WorkerSnapshot {
  name: string;
  lastActivity: string | null;
  inFlight: number;
  oneHour: { success: number; failure: number };
}

interface WorkersResponse {
  workers: WorkerSnapshot[];
}

const WORKER_FRESHNESS: Record<string, number> = {
  Analyzer: 5,
  'RMM Overshell': 10,
  'Sync scheduler': 60,
};

// ── Helpers ──────────────────────────────────────────────────────────

const STALE_HOURS = 24;
const POLL_MS = 60_000;

const CATEGORY_LABELS: Record<IntegrationCategory, string> = {
  psa: 'PSA',
  rmm: 'RMM',
  docs: 'Documentation',
  security: 'Security',
  backup: 'Backup',
  network: 'Network',
  identity: 'Identity',
  mdm: 'MDM',
  mail: 'Mail',
  finance: 'Finance',
  productivity: 'Productivity',
  llm: 'LLM',
};

const CATEGORY_ORDER: IntegrationCategory[] = [
  'psa', 'rmm', 'docs', 'security', 'backup',
  'network', 'identity', 'mdm', 'mail',
  'finance', 'productivity', 'llm',
];

function relTime(iso: string | null): string {
  if (!iso) return 'never';
  const ms = Date.now() - new Date(iso).getTime();
  if (ms < 0) return 'in the future';
  const min = Math.floor(ms / 60000);
  if (min < 1) return 'just now';
  if (min < 60) return `${min} min ago`;
  const hr = Math.floor(min / 60);
  if (hr < 48) return `${hr} h ago`;
  const day = Math.floor(hr / 24);
  return `${day} d ago`;
}

function isStale(iso: string | null): boolean {
  if (!iso) return true;
  return Date.now() - new Date(iso).getTime() > STALE_HOURS * 3600_000;
}

function integrationLight(item: IntegrationHealthItem): StatusLightState {
  if (item.status === 'disabled') return 'idle';
  const tokenExpired = item.tokenExpiry && item.tokenExpiry.daysRemaining <= 0;
  const tokenExpiring =
    item.tokenExpiry &&
    item.tokenExpiry.daysRemaining > 0 &&
    item.tokenExpiry.daysRemaining <= 14;
  if (item.status === 'auth_failed' || item.status === 'unreachable' || tokenExpired) {
    return 'error';
  }
  if (tokenExpiring) return 'warn';
  if (item.status === 'ok') return 'ok';
  if (item.status === 'not_configured') return 'idle';
  return 'idle';
}

function syncLight(item: SyncHealthItem): StatusLightState {
  if (!item.isEnabled) return 'idle';
  if (item.lastStatus === 'failed') return 'error';
  if (isStale(item.lastRun)) return 'warn';
  if (item.lastStatus === 'success') return 'ok';
  return 'idle';
}

// ── Page ─────────────────────────────────────────────────────────────

export default function StatusPage() {
  const [health, setHealth] = useState<IntegrationHealthResponse | null>(null);
  const [overview, setOverview] = useState<OverviewResponse | null>(null);
  const [workers, setWorkers] = useState<WorkerSnapshot[] | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [refreshing, setRefreshing] = useState(false);

  async function load(force = false) {
    setRefreshing(true);
    try {
      const [hRes, oRes, wRes] = await Promise.all([
        fetch(`/api/dashboard/integration-health${force ? '?refresh=1' : ''}`, { cache: 'no-store' }),
        fetch('/api/dashboard/overview', { cache: 'no-store' }),
        fetch('/api/status/workers', { cache: 'no-store' }),
      ]);
      if (hRes.ok) setHealth((await hRes.json()) as IntegrationHealthResponse);
      if (oRes.ok) setOverview((await oRes.json()) as OverviewResponse);
      if (wRes.ok) {
        const j = (await wRes.json()) as WorkersResponse;
        setWorkers(j.workers);
      }
      setError(null);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to load');
    } finally {
      setRefreshing(false);
    }
  }

  useEffect(() => {
    void load();
    const id = setInterval(() => void load(), POLL_MS);
    return () => clearInterval(id);
  }, []);

  // Roll-up
  const overall: StatusLightState = !health
    ? 'idle'
    : health.summary.failed > 0 || health.summary.expired > 0
      ? 'error'
      : health.summary.expiringWithin14Days > 0 ||
        (overview?.syncHealth.some((s) => syncLight(s) === 'error') ?? false)
        ? 'warn'
        : 'ok';

  const overallTitle = !health
    ? 'Loading…'
    : overall === 'error'
      ? `${health.summary.failed} integration${health.summary.failed === 1 ? '' : 's'} failing`
      : overall === 'warn'
        ? health.summary.expiringWithin14Days > 0
          ? `${health.summary.expiringWithin14Days} token${health.summary.expiringWithin14Days === 1 ? '' : 's'} expiring soon`
          : 'Some sync tasks degraded'
        : 'All systems operational';

  // Group integrations
  const grouped = (() => {
    if (!health) return null;
    const map: Record<string, IntegrationHealthItem[]> = {};
    for (const item of health.items) {
      (map[item.category] ??= []).push(item);
    }
    return map;
  })();

  const expiring = health?.items
    .filter((i) => i.tokenExpiry && i.tokenExpiry.daysRemaining <= 30)
    .sort((a, b) => (a.tokenExpiry!.daysRemaining ?? 999) - (b.tokenExpiry!.daysRemaining ?? 999));

  const failingSyncs = overview?.syncHealth.filter((s) => syncLight(s) === 'error');
  const failingIntegrations = health?.items.filter(
    (i) => i.status === 'auth_failed' || i.status === 'unreachable',
  );

  return (
    <>
      <PageHeader
        title="System Status"
        description={overallTitle}
        breadcrumbs={[{ label: 'Status' }]}
        accent
        watermark
        actions={
          <>
            <StatusLight state={overall} size="lg" label={overallTitle} />
            <Button
              onClick={() => void load(true)}
              variant="outline"
              size="sm"
              disabled={refreshing}
            >
              <RefreshCw className={`h-4 w-4 mr-2 ${refreshing ? 'animate-spin' : ''}`} />
              Refresh
            </Button>
          </>
        }
      />

      <div className="container mx-auto px-6 py-6 space-y-6">
        {error && (
          <Alert variant="destructive">
            <AlertTitle>Failed to load status</AlertTitle>
            <AlertDescription>{error}</AlertDescription>
          </Alert>
        )}

        {/* CONDITIONAL BANNER -------------------------------------------- */}
        {(failingIntegrations?.length || failingSyncs?.length) ? (
          <Alert variant="destructive">
            <AlertTriangle className="h-4 w-4" />
            <AlertTitle>Action needed</AlertTitle>
            <AlertDescription>
              <ul className="list-disc pl-5 mt-1 space-y-0.5">
                {failingIntegrations?.map((i) => (
                  <li key={i.key}>
                    <span className="font-medium">{i.name}</span> —{' '}
                    {i.status === 'auth_failed' ? 'authentication failed' : 'unreachable'}
                    {i.error && <span className="text-muted-foreground"> · {i.error.slice(0, 120)}</span>}
                  </li>
                ))}
                {failingSyncs?.map((s) => (
                  <li key={s.id}>
                    <span className="font-medium">{s.name}</span> sync failed
                    {s.lastError && <span className="text-muted-foreground"> · {s.lastError.slice(0, 120)}</span>}
                  </li>
                ))}
              </ul>
            </AlertDescription>
          </Alert>
        ) : null}

        {/* INTEGRATION TILES --------------------------------------------- */}
        <section className="space-y-4">
          <div className="flex items-center gap-2">
            <Plug className="h-4 w-4 text-muted-foreground" />
            <h2 className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">
              Integrations
            </h2>
            {health && (
              <span className="text-xs text-muted-foreground">
                {health.summary.ok} of {health.summary.total - health.summary.notConfigured} healthy
              </span>
            )}
          </div>

          {!grouped ? (
            <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
              {[1, 2, 3, 4, 5, 6].map((i) => <Skeleton key={i} className="h-24" />)}
            </div>
          ) : (
            <div className="space-y-6">
              {CATEGORY_ORDER.filter((c) => grouped[c]?.length).map((category) => (
                <div key={category} className="space-y-2">
                  <h3 className="metric-label">{CATEGORY_LABELS[category]}</h3>
                  <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
                    {grouped[category]
                      .slice()
                      .sort((a, b) => a.name.localeCompare(b.name))
                      .map((item) => <IntegrationTile key={item.key} item={item} />)}
                  </div>
                </div>
              ))}
            </div>
          )}
        </section>

        {/* WORKERS ------------------------------------------------------- */}
        <section className="space-y-4">
          <div className="flex items-center gap-2">
            <Activity className="h-4 w-4 text-muted-foreground" />
            <h2 className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">
              Workers
            </h2>
          </div>
          {!workers ? (
            <div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
              {[1, 2, 3].map((i) => <Skeleton key={i} className="h-36" />)}
            </div>
          ) : (
            <div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
              {workers.map((w) => (
                <WorkerPulse
                  key={w.name}
                  worker={w}
                  freshnessMinutes={WORKER_FRESHNESS[w.name]}
                />
              ))}
            </div>
          )}
        </section>

        {/* TOKEN EXPIRY -------------------------------------------------- */}
        {expiring && expiring.length > 0 && (
          <Card>
            <CardHeader className="pb-3">
              <CardTitle className="text-base flex items-center gap-2">
                <KeyRound className="h-4 w-4" />
                Tokens expiring within 30 days
              </CardTitle>
            </CardHeader>
            <CardContent>
              <div className="divide-y divide-border">
                {expiring.map((item) => {
                  const days = item.tokenExpiry!.daysRemaining;
                  const tone = days <= 0 ? 'error' : days <= 14 ? 'warn' : 'pending';
                  return (
                    <div key={item.key} className="flex items-center justify-between py-2 text-sm">
                      <div className="min-w-0">
                        <span className="font-medium">{item.name}</span>
                        <span className="text-muted-foreground"> · {item.tokenExpiry!.envVar}</span>
                      </div>
                      <StatusBadge tone={tone}>
                        {days <= 0 ? `expired ${Math.abs(days)} d ago` : `${days} d`}
                      </StatusBadge>
                    </div>
                  );
                })}
              </div>
            </CardContent>
          </Card>
        )}

        {/* SYNC HEALTH --------------------------------------------------- */}
        <Card>
          <CardHeader className="pb-3">
            <CardTitle className="text-base flex items-center gap-2">
              <Clock className="h-4 w-4" />
              Scheduled syncs
            </CardTitle>
          </CardHeader>
          <CardContent className="p-0">
            {!overview ? (
              <div className="px-6 py-6">
                <Skeleton className="h-32" />
              </div>
            ) : overview.syncHealth.length === 0 ? (
              <div className="px-6 py-6">
                <EmptyState
                  icon={Clock}
                  title="No scheduled syncs"
                  description="Configure schedules in Admin to populate this list."
                  action={{ label: 'Open admin', href: '/admin' }}
                />
              </div>
            ) : (
              <Table>
                <TableHeader className="bg-muted/40">
                  <TableRow>
                    <TableHead>Schedule</TableHead>
                    <TableHead>Type</TableHead>
                    <TableHead>Last run</TableHead>
                    <TableHead>Next run</TableHead>
                    <TableHead className="text-right">Status</TableHead>
                    <TableHead className="w-10" aria-label="indicator" />
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {overview.syncHealth.map((s) => (
                    <TableRow key={s.id}>
                      <TableCell className="font-medium">{s.name}</TableCell>
                      <TableCell className="num text-muted-foreground">{s.syncType}</TableCell>
                      <TableCell className="num text-muted-foreground">{relTime(s.lastRun)}</TableCell>
                      <TableCell className="num text-muted-foreground">{relTime(s.nextRun)}</TableCell>
                      <TableCell className="text-right">
                        {s.isEnabled
                          ? s.lastStatus === 'failed'
                            ? <StatusBadge tone="error">failed</StatusBadge>
                            : isStale(s.lastRun)
                              ? <StatusBadge tone="warn">stale</StatusBadge>
                              : s.lastStatus === 'success'
                                ? <StatusBadge tone="ok">success</StatusBadge>
                                : <StatusBadge tone="neutral">idle</StatusBadge>
                          : <StatusBadge tone="inactive">off</StatusBadge>}
                      </TableCell>
                      <TableCell className="text-right">
                        <StatusLight state={syncLight(s)} size="sm" label={s.lastStatus ?? 'idle'} />
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            )}
          </CardContent>
        </Card>

        {/* COMPLIANCE FOOTER -------------------------------------------- */}
        {health && (
          <p className="flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground">
            <ShieldCheck className="h-3.5 w-3.5" />
            <span><span className="num">{health.summary.ok}</span> healthy</span>
            <span>·</span>
            <span><span className="num">{health.summary.failed}</span> failing</span>
            <span>·</span>
            <span><span className="num">{health.summary.notConfigured}</span> unconfigured</span>
            {health.summary.disabled > 0 && (
              <>
                <span>·</span>
                <span><span className="num">{health.summary.disabled}</span> disabled</span>
              </>
            )}
            <span>·</span>
            <span><span className="num">{health.summary.expiringWithin14Days}</span> expiring</span>
            <span>·</span>
            <span>last checked {relTime(health.items[0]?.checkedAt ?? null)}</span>
          </p>
        )}
      </div>
    </>
  );
}

// ── Integration tile ────────────────────────────────────────────────

function IntegrationTile({ item }: { item: IntegrationHealthItem }) {
  const light = integrationLight(item);
  const expired = item.tokenExpiry && item.tokenExpiry.daysRemaining <= 0;
  const expiringSoon =
    item.tokenExpiry && item.tokenExpiry.daysRemaining > 0 && item.tokenExpiry.daysRemaining <= 14;

  let detail: string | null = null;
  if (item.status === 'disabled') detail = 'disabled by operator';
  else if (item.status === 'auth_failed') detail = 'authentication failed';
  else if (item.status === 'unreachable') detail = 'unreachable';
  else if (expired) detail = `token expired ${Math.abs(item.tokenExpiry!.daysRemaining)} d ago`;
  else if (expiringSoon) detail = `token expires in ${item.tokenExpiry!.daysRemaining} d`;
  else if (item.status === 'not_configured') detail = 'not configured';
  else if (item.status === 'ok' && item.latencyMs !== undefined) detail = `${item.latencyMs} ms`;
  else if (item.status === 'unknown' && item.configured) detail = 'configured';

  return (
    <div
      className={
        'rounded-md border bg-card px-3 py-3 flex items-start gap-3 ' +
        (light === 'error'
          ? 'border-destructive/40'
          : item.status === 'disabled'
            ? 'border-border opacity-60'
            : 'border-border')
      }
    >
      <StatusLight state={light} size="md" label={item.status} className="mt-1" />
      <div className="min-w-0 flex-1">
        <div className="flex items-center justify-between gap-2">
          <p className="font-medium truncate">{item.name}</p>
          {(expired || expiringSoon) && (
            <KeyRound className={`h-3.5 w-3.5 shrink-0 ${expired ? 'text-destructive' : 'text-amber-500'}`} />
          )}
        </div>
        {detail && (
          <p className={`text-xs num truncate ${light === 'error' ? 'text-destructive' : 'text-muted-foreground'}`}>
            {detail}
          </p>
        )}
        {item.error && light === 'error' && (
          <p className="text-xs text-muted-foreground/80 truncate" title={item.error}>
            {item.error.slice(0, 80)}
          </p>
        )}
      </div>
    </div>
  );
}
