'use client';

import { useEffect, useState } from 'react';
import {
  Activity,
  AlertTriangle,
  CheckCircle2,
  Clock3,
  Database,
  Loader2,
  RefreshCw,
  ServerCog,
} from 'lucide-react';
import { RouteGuard } from '@/components/auth/Guard';
import { api } from '@/lib/api';

type JobStatus = 'queued' | 'running' | 'succeeded' | 'failed';

interface OpsRuntimeSnapshot {
  collectedAt: string;
  thresholds: {
    apiSlowRequestMs: number;
    prismaSlowQueryMs: number;
  };
  database: {
    ok: boolean;
    error?: string;
  };
  slowRequests: Array<{
    id: string;
    method: string;
    path: string;
    durationMs: number;
    thresholdMs: number;
    occurredAt: string;
  }>;
  slowQueries: Array<{
    id: string;
    queryPreview: string;
    durationMs: number;
    thresholdMs: number;
    occurredAt: string;
  }>;
  jobQueue: {
    totals: Record<JobStatus, number> & { total: number };
    byType: Array<Record<JobStatus, number> & {
      type: string;
      total: number;
      oldestQueuedAt?: string;
      nextLeaseExpiresAt?: string;
    }>;
    recentFailures: Array<{
      id: string;
      type: string;
      attempts: number;
      maxAttempts: number;
      lastError: string;
      updatedAt?: string;
    }>;
  };
  dirtySummaryCount: number;
  access: {
    requiredPermission: string;
    backendEnforced: boolean;
    adapter: string;
  };
}

const STATUS_LABEL: Record<JobStatus, string> = {
  queued: '排队',
  running: '运行',
  succeeded: '成功',
  failed: '失败',
};

export default function OpsPage() {
  return (
    <RouteGuard permission="ops:view">
      <OpsPageContent />
    </RouteGuard>
  );
}

function OpsPageContent() {
  const [snapshot, setSnapshot] = useState<OpsRuntimeSnapshot | null>(null);
  const [loading, setLoading] = useState(true);
  const [refreshing, setRefreshing] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fetchSnapshot = async (initial = false) => {
    if (initial) setLoading(true);
    else setRefreshing(true);
    try {
      const next = await api.get<OpsRuntimeSnapshot>('/ops/runtime');
      setSnapshot(next);
      setError(null);
    } catch (e: any) {
      setError(e?.message || '读取失败');
    } finally {
      setLoading(false);
      setRefreshing(false);
    }
  };

  useEffect(() => {
    void fetchSnapshot(true);
    const timer = window.setInterval(() => { void fetchSnapshot(); }, 30_000);
    return () => window.clearInterval(timer);
  }, []);

  return (
    <div className="flex h-full flex-col bg-[var(--bg)]">
      <header className="flex h-14 shrink-0 items-center justify-between border-b border-[var(--line)] bg-[var(--bg-card)] px-5">
        <div className="flex items-center gap-2.5">
          <Activity className="h-4 w-4 text-blue-600" strokeWidth={2} />
          <h1 className="text-[15px] font-semibold tracking-tight text-[var(--ink)]">运维看板</h1>
          {snapshot && (
            <span className="rounded-md bg-[var(--bg-subtle)] px-1.5 py-0.5 text-[11px] font-medium tabular-nums text-[var(--ink-soft)]">
              {formatClock(snapshot.collectedAt)}
            </span>
          )}
        </div>
        <button
          onClick={() => fetchSnapshot()}
          disabled={refreshing}
          className="flex h-8 items-center gap-1.5 rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] font-medium text-[var(--ink-soft)] transition-colors hover:bg-[var(--bg-subtle)] disabled:cursor-not-allowed disabled:opacity-60"
        >
          {refreshing ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <RefreshCw className="h-3.5 w-3.5" />}
          刷新
        </button>
      </header>

      <main className="flex-1 overflow-y-auto px-5 py-4">
        {loading ? (
          <div className="flex h-full items-center justify-center text-[13px] text-[var(--ink-muted)]">
            <Loader2 className="mr-2 h-4 w-4 animate-spin" />
            加载中
          </div>
        ) : error ? (
          <div className="rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-[13px] text-red-700">{error}</div>
        ) : snapshot ? (
          <div className="space-y-4">
            <OverviewStrip snapshot={snapshot} />
            <div className="grid gap-4 xl:grid-cols-[minmax(0,1fr)_420px]">
              <div className="space-y-4">
                <SlowRequestsPanel snapshot={snapshot} />
                <SlowQueriesPanel snapshot={snapshot} />
              </div>
              <div className="space-y-4">
                <JobQueuePanel snapshot={snapshot} />
                <FailuresPanel snapshot={snapshot} />
              </div>
            </div>
          </div>
        ) : null}
      </main>
    </div>
  );
}

function OverviewStrip({ snapshot }: { snapshot: OpsRuntimeSnapshot }) {
  const cards = [
    {
      label: '慢请求',
      value: snapshot.slowRequests.length,
      sub: `阈值 ${snapshot.thresholds.apiSlowRequestMs}ms`,
      icon: Clock3,
      tone: 'blue',
    },
    {
      label: '慢查询',
      value: snapshot.slowQueries.length,
      sub: `阈值 ${snapshot.thresholds.prismaSlowQueryMs}ms`,
      icon: Database,
      tone: 'amber',
    },
    {
      label: '后台任务',
      value: snapshot.jobQueue.totals.total,
      sub: `${snapshot.jobQueue.totals.queued} 排队 / ${snapshot.jobQueue.totals.running} 运行`,
      icon: ServerCog,
      tone: 'zinc',
    },
    {
      label: '脏 Summary',
      value: snapshot.dirtySummaryCount,
      sub: 'xiaobao_risk_summaries',
      icon: AlertTriangle,
      tone: snapshot.dirtySummaryCount > 0 ? 'red' : 'emerald',
    },
  ];

  return (
    <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
      {cards.map((card) => {
        const Icon = card.icon;
        return (
          <section key={card.label} className="rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-4 py-3 shadow-[var(--shadow-sm)]">
            <div className="flex items-center justify-between gap-3">
              <div className="min-w-0">
                <p className="text-[11px] font-medium text-[var(--ink-muted)]">{card.label}</p>
                <p className="mt-1 text-[24px] font-semibold leading-none tabular-nums text-[var(--ink)]">{card.value}</p>
                <p className="mt-1 truncate text-[11px] text-[var(--ink-soft)]">{card.sub}</p>
              </div>
              <span className={`flex h-9 w-9 shrink-0 items-center justify-center rounded-lg ${toneClass(card.tone)}`}>
                <Icon className="h-4 w-4" strokeWidth={2} />
              </span>
            </div>
          </section>
        );
      })}
    </div>
  );
}

function SlowRequestsPanel({ snapshot }: { snapshot: OpsRuntimeSnapshot }) {
  return (
    <section className="rounded-lg border border-[var(--line)] bg-[var(--bg-card)] shadow-[var(--shadow-sm)]">
      <PanelHeader title="慢请求" right={`${snapshot.slowRequests.length}`} />
      <div className="divide-y divide-[var(--line)]">
        {snapshot.slowRequests.length === 0 ? (
          <EmptyRow label="暂无慢请求" />
        ) : snapshot.slowRequests.map((item) => (
          <div key={item.id} className="grid grid-cols-[76px_minmax(0,1fr)_92px_96px] items-center gap-3 px-4 py-2.5 text-[12px]">
            <span className="font-mono font-medium text-blue-700">{item.method}</span>
            <span className="truncate font-mono text-[var(--ink)]">{item.path}</span>
            <span className="text-right font-mono tabular-nums text-red-600">{item.durationMs}ms</span>
            <span className="text-right text-[var(--ink-muted)]">{formatClock(item.occurredAt)}</span>
          </div>
        ))}
      </div>
    </section>
  );
}

function SlowQueriesPanel({ snapshot }: { snapshot: OpsRuntimeSnapshot }) {
  return (
    <section className="rounded-lg border border-[var(--line)] bg-[var(--bg-card)] shadow-[var(--shadow-sm)]">
      <PanelHeader title="慢查询" right={`${snapshot.slowQueries.length}`} />
      <div className="divide-y divide-[var(--line)]">
        {snapshot.slowQueries.length === 0 ? (
          <EmptyRow label="暂无慢查询" />
        ) : snapshot.slowQueries.map((item) => (
          <div key={item.id} className="grid grid-cols-[minmax(0,1fr)_92px_96px] items-start gap-3 px-4 py-2.5 text-[12px]">
            <code className="min-w-0 break-words font-mono text-[11px] leading-5 text-[var(--ink)]">{item.queryPreview}</code>
            <span className="text-right font-mono tabular-nums text-amber-700">{item.durationMs}ms</span>
            <span className="text-right text-[var(--ink-muted)]">{formatClock(item.occurredAt)}</span>
          </div>
        ))}
      </div>
    </section>
  );
}

function JobQueuePanel({ snapshot }: { snapshot: OpsRuntimeSnapshot }) {
  const rows = snapshot.jobQueue.byType;
  return (
    <section className="rounded-lg border border-[var(--line)] bg-[var(--bg-card)] shadow-[var(--shadow-sm)]">
      <PanelHeader title="后台任务" right={`${snapshot.jobQueue.totals.total}`} />
      <div className="border-b border-[var(--line)] px-4 py-3">
        <StatusBars totals={snapshot.jobQueue.totals} />
      </div>
      <div className="divide-y divide-[var(--line)]">
        {rows.length === 0 ? (
          <EmptyRow label="暂无任务" />
        ) : rows.map((row) => (
          <div key={row.type} className="px-4 py-3">
            <div className="flex items-center justify-between gap-3">
              <span className="min-w-0 truncate font-mono text-[12px] font-medium text-[var(--ink)]">{row.type}</span>
              <span className="text-[11px] font-medium tabular-nums text-[var(--ink-muted)]">{row.total}</span>
            </div>
            <div className="mt-2 grid grid-cols-4 gap-1.5">
              {(['queued', 'running', 'succeeded', 'failed'] as JobStatus[]).map((status) => (
                <StatusPill key={status} status={status} count={row[status]} />
              ))}
            </div>
            {(row.oldestQueuedAt || row.nextLeaseExpiresAt) && (
              <div className="mt-2 flex flex-wrap gap-2 text-[11px] text-[var(--ink-muted)]">
                {row.oldestQueuedAt && <span>最早排队 {formatClock(row.oldestQueuedAt)}</span>}
                {row.nextLeaseExpiresAt && <span>Lease {formatClock(row.nextLeaseExpiresAt)}</span>}
              </div>
            )}
          </div>
        ))}
      </div>
    </section>
  );
}

function FailuresPanel({ snapshot }: { snapshot: OpsRuntimeSnapshot }) {
  const failures = snapshot.jobQueue.recentFailures;
  const dbOk = snapshot.database.ok;

  return (
    <section className="rounded-lg border border-[var(--line)] bg-[var(--bg-card)] shadow-[var(--shadow-sm)]">
      <PanelHeader title="运行状态" right={dbOk ? 'OK' : 'DB'} />
      <div className="border-b border-[var(--line)] px-4 py-3">
        <div className={`flex items-center gap-2 rounded-md border px-3 py-2 text-[12px] ${dbOk ? 'border-emerald-200 bg-emerald-50 text-emerald-700' : 'border-red-200 bg-red-50 text-red-700'}`}>
          {dbOk ? <CheckCircle2 className="h-4 w-4" /> : <AlertTriangle className="h-4 w-4" />}
          <span className="min-w-0 truncate">{dbOk ? '数据库可读' : snapshot.database.error || '数据库不可读'}</span>
        </div>
      </div>
      <div className="divide-y divide-[var(--line)]">
        {failures.length === 0 ? (
          <EmptyRow label="暂无失败任务" />
        ) : failures.map((item) => (
          <div key={item.id} className="px-4 py-3 text-[12px]">
            <div className="flex items-center justify-between gap-3">
              <span className="min-w-0 truncate font-mono font-medium text-[var(--ink)]">{item.type}</span>
              <span className="shrink-0 font-mono tabular-nums text-red-600">{item.attempts}/{item.maxAttempts}</span>
            </div>
            <p className="mt-1 line-clamp-2 text-[11px] leading-5 text-[var(--ink-soft)]">{item.lastError || '-'}</p>
            {item.updatedAt && <p className="mt-1 text-[11px] text-[var(--ink-muted)]">{formatClock(item.updatedAt)}</p>}
          </div>
        ))}
      </div>
    </section>
  );
}

function StatusBars({ totals }: { totals: OpsRuntimeSnapshot['jobQueue']['totals'] }) {
  const statuses: JobStatus[] = ['queued', 'running', 'succeeded', 'failed'];
  const total = Math.max(1, totals.total);
  return (
    <div className="space-y-2">
      <div className="flex h-2 overflow-hidden rounded-full bg-[var(--bg-subtle)]">
        {statuses.map((status) => (
          <span
            key={status}
            className={statusBarClass(status)}
            style={{ width: `${(totals[status] / total) * 100}%` }}
          />
        ))}
      </div>
      <div className="grid grid-cols-4 gap-1.5">
        {statuses.map((status) => <StatusPill key={status} status={status} count={totals[status]} />)}
      </div>
    </div>
  );
}

function StatusPill({ status, count }: { status: JobStatus; count: number }) {
  return (
    <div className={`flex items-center justify-between gap-1 rounded-md px-2 py-1 text-[11px] ${statusPillClass(status)}`}>
      <span>{STATUS_LABEL[status]}</span>
      <span className="font-mono tabular-nums">{count}</span>
    </div>
  );
}

function PanelHeader({ title, right }: { title: string; right: string }) {
  return (
    <div className="flex h-10 items-center justify-between border-b border-[var(--line)] px-4">
      <h2 className="text-[13px] font-semibold text-[var(--ink)]">{title}</h2>
      <span className="rounded-md bg-[var(--bg-subtle)] px-1.5 py-0.5 text-[11px] font-medium tabular-nums text-[var(--ink-soft)]">{right}</span>
    </div>
  );
}

function EmptyRow({ label }: { label: string }) {
  return <div className="px-4 py-8 text-center text-[12px] text-[var(--ink-muted)]">{label}</div>;
}

function formatClock(value?: string) {
  if (!value) return '-';
  const date = new Date(value);
  if (!Number.isFinite(date.getTime())) return '-';
  return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false });
}

function toneClass(tone: string) {
  if (tone === 'blue') return 'bg-blue-50 text-blue-700';
  if (tone === 'amber') return 'bg-amber-50 text-amber-700';
  if (tone === 'red') return 'bg-red-50 text-red-700';
  if (tone === 'emerald') return 'bg-emerald-50 text-emerald-700';
  return 'bg-zinc-100 text-zinc-700';
}

function statusBarClass(status: JobStatus) {
  if (status === 'queued') return 'bg-blue-500';
  if (status === 'running') return 'bg-amber-500';
  if (status === 'succeeded') return 'bg-emerald-500';
  return 'bg-red-500';
}

function statusPillClass(status: JobStatus) {
  if (status === 'queued') return 'bg-blue-50 text-blue-700';
  if (status === 'running') return 'bg-amber-50 text-amber-700';
  if (status === 'succeeded') return 'bg-emerald-50 text-emerald-700';
  return 'bg-red-50 text-red-700';
}
