import { useQuery } from "@tanstack/react-query";
import { AlertTriangle, ArrowUpRight, CheckCircle2, Clock3, ShieldCheck } from "lucide-react";
import { objectTypeRows, overviewKpis, topRepositories, validationIssues, validationSlices } from "../../test/fixtures/dashboard";
import {
  getLatestRun,
  getStatsObjectTypes,
  getStatsReasons,
  getStatsValidation,
  listRepos,
  type CountsByKey,
  type RepositoryRecord,
  type RunRecord
} from "../../api/queryService";
import { normalizeApiError } from "../../api/client";
import { CopyableValue } from "../../components/common/CopyableValue";

const validationColors = ["#0ca678", "#facc15", "#e11d48", "#94a3b8"];
const objectTypeLabels: Record<string, string> = {
  aspa: "ASPA",
  certificate: "CER / RC",
  crl: "CRL",
  gbr: "GBR",
  manifest: "MFT",
  roa: "ROA",
  router_certificate: "Router Cert"
};

export function OverviewPage() {
  const latestRunQuery = useQuery({
    queryKey: ["latest-run"],
    queryFn: getLatestRun
  });
  const liveRun = latestRunQuery.data?.data;
  const runId = liveRun?.runId ?? "latest";
  const enabled = Boolean(liveRun);
  const objectTypesQuery = useQuery({
    queryKey: ["stats-object-types", runId],
    queryFn: () => getStatsObjectTypes(runId),
    enabled
  });
  const validationQuery = useQuery({
    queryKey: ["stats-validation", runId],
    queryFn: () => getStatsValidation(runId),
    enabled
  });
  const reasonsQuery = useQuery({
    queryKey: ["stats-reasons", runId],
    queryFn: () => getStatsReasons(runId),
    enabled
  });
  const reposQuery = useQuery({
    queryKey: ["top-repos", runId],
    queryFn: () => listRepos(runId, 8),
    enabled
  });

  const error = latestRunQuery.error ? normalizeApiError(latestRunQuery.error) : null;
  const kpis = liveRun ? kpisFromRun(liveRun) : overviewKpis;
  const objectRows = objectTypesQuery.data?.data ? objectRowsFromStats(objectTypesQuery.data.data) : objectTypeRows;
  const validationRows = validationQuery.data?.data ? validationRowsFromStats(validationQuery.data.data) : validationSlices;
  const validPercent = percent(validationQuery.data?.data?.ok ?? validationRows[0]?.value ?? 0, sumValues(validationQuery.data?.data) || 100);
  const repoRows = reposQuery.data?.data ? reposFromApi(reposQuery.data.data) : reposFromFixtures();
  const issueRows = reasonsQuery.data?.data ? issuesFromReasons(reasonsQuery.data.data) : validationIssues;
  const statusText = liveRun ? statusForRun(liveRun) : "Static fixture";
  const statusSubtext = liveRun ? `run ${liveRun.runSeq ?? liveRun.runId} · ${formatDuration(liveRun.wallMs)}` : "query service not connected";

  return (
    <section className="page-stack" aria-labelledby="overview-heading">
      {error ? (
        <div className="alert-banner" role="status">
          <strong>Query service unavailable</strong>
          <span>{error.message}. Showing static fallback data for layout inspection.</span>
        </div>
      ) : null}
      <div className="hero-dashboard">
        <div>
          <p className="eyebrow">{liveRun ? `Latest ready run · ${liveRun.syncMode ?? "unknown"} mode` : "Latest ready run · fallback"}</p>
          <h2 id="overview-heading">Global RPKI validation health</h2>
          <p>
            {liveRun
              ? `Live query-service view for ${liveRun.runId}, validated at ${formatTimestamp(liveRun.validationTime)}.`
              : "Static fallback showing how operators inspect validation output, repository health, and input quality."}
          </p>
        </div>
        <div className="hero-status">
          <ShieldCheck size={20} />
          <div>
            <strong>{statusText}</strong>
            <span>{statusSubtext}</span>
          </div>
        </div>
      </div>

      <div className="metric-grid" aria-label="Overview KPI cards">
        {kpis.map((metric) => (
          <article className={`metric-card tone-${metric.tone}`} key={metric.label}>
            <span>{metric.label}</span>
            <strong>{metric.value}</strong>
            <small>{metric.delta}</small>
          </article>
        ))}
      </div>

      <div className="dashboard-grid">
        <section className="panel validation-card">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Validation</p>
              <h3>Result distribution</h3>
            </div>
            <CheckCircle2 className="panel-icon success" size={22} />
          </div>
          <div className="donut-wrap">
            <div className="donut" aria-label="Validation distribution donut" style={{ background: donutGradient(validationRows) }} />
            <div className="donut-center">
              <strong>{validPercent}%</strong>
              <span>usable</span>
            </div>
          </div>
          <div className="legend-list">
            {validationRows.map((slice) => (
              <div className="legend-row" key={slice.label}>
                <span style={{ backgroundColor: slice.color }} />
                <label>{slice.label}</label>
                <strong>{slice.value}%</strong>
              </div>
            ))}
          </div>
        </section>

        <section className="panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Objects</p>
              <h3>Object type mix</h3>
            </div>
            <Clock3 className="panel-icon" size={22} />
          </div>
          <div className="bar-list">
            {objectRows.map((row) => (
              <div className="bar-row" key={row.type}>
                <div className="bar-meta">
                  <strong>{row.type}</strong>
                  <span>{row.count}</span>
                </div>
                <div className="bar-track">
                  <span style={{ width: `${row.percent}%` }} />
                </div>
              </div>
            ))}
          </div>
        </section>

        <section className="panel table-panel wide-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Repositories</p>
              <h3>Top repositories by workload</h3>
            </div>
            <button className="ghost-button" type="button">
              View all <ArrowUpRight size={16} />
            </button>
          </div>
          <table>
            <thead>
              <tr>
                <th>Host</th>
                <th>Transport</th>
                <th>Duration</th>
                <th>Objects</th>
                <th>Status</th>
              </tr>
            </thead>
            <tbody>
              {repoRows.map((repo) => (
                <tr key={repo.id}>
                  <td>{repo.host}</td>
                  <td>{repo.transport}</td>
                  <td>{repo.duration}</td>
                  <td>{repo.objects}</td>
                  <td>
                    <span className={`status-badge ${repo.status}`}>{repo.status}</span>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </section>

        <section className="panel issue-panel">
          <div className="panel-heading">
            <div>
              <p className="eyebrow">Triage</p>
              <h3>Recent validation issues</h3>
            </div>
            <AlertTriangle className="panel-icon warning" size={22} />
          </div>
          <div className="issue-list">
            {issueRows.map((issue) => (
              <article className="issue-card" key={issue.uri}>
                <div>
                  <span className={`severity ${issue.severity}`}>{issue.severity}</span>
                  <strong>{issue.type}</strong>
                </div>
                <p>{issue.reason}</p>
                <code><CopyableValue label="issue URI" value={issue.uri} /></code>
                <small>{issue.repo}</small>
              </article>
            ))}
          </div>
        </section>
      </div>
    </section>
  );
}

function kpisFromRun(run: RunRecord) {
  return [
    { label: "VRPs", value: formatNumber(run.counts.vrps), delta: "latest run", tone: "blue" },
    { label: "ASPAs", value: formatNumber(run.counts.aspas), delta: "latest run", tone: "cyan" },
    { label: "Objects", value: formatNumber(run.counts.objects), delta: "indexed inputs", tone: "blue" },
    { label: "Publication Points", value: formatNumber(run.counts.publicationPoints), delta: "indexed", tone: "purple" },
    { label: "Rejected Objects", value: formatNumber(run.counts.rejectedObjects), delta: "validation rejects", tone: "red" },
    { label: "Warnings", value: formatNumber(run.counts.warnings), delta: `${formatDuration(run.wallMs)} wall`, tone: "amber" }
  ];
}

function objectRowsFromStats(stats: CountsByKey) {
  const total = sumValues(stats) || 1;
  return Object.entries(stats)
    .sort(([, left], [, right]) => right - left)
    .slice(0, 7)
    .map(([type, count]) => ({
      type: objectTypeLabels[type] ?? type,
      count: formatNumber(count),
      percent: Math.max(1, Math.round((count / total) * 100))
    }));
}

function validationRowsFromStats(stats: CountsByKey) {
  const total = sumValues(stats) || 1;
  return Object.entries(stats)
    .sort(([, left], [, right]) => right - left)
    .map(([label, count], index) => ({
      label: titleCase(label),
      value: Math.round((count / total) * 100),
      color: validationColors[index] ?? "#94a3b8"
    }));
}

function reposFromApi(repos: RepositoryRecord[]) {
  return [...repos]
    .sort((left, right) => right.objects - left.objects)
    .slice(0, 6)
    .map((repo) => ({
      host: repo.host,
      id: repo.repoId,
      transport: repo.transport.toUpperCase(),
      duration: formatDuration(repo.syncDurationMsTotal),
      objects: formatNumber(repo.objects),
      status: repoStatus(repo)
    }));
}

function reposFromFixtures() {
  return topRepositories.map((repo, index) => ({
    ...repo,
    id: fallbackRepoId(repo, index)
  }));
}

function fallbackRepoId(repo: { host: string; transport: string; duration: string; objects: string }, index: number) {
  return `${repo.host}-${repo.transport}-${repo.duration}-${repo.objects}-${index}`;
}

function issuesFromReasons(reasons: CountsByKey) {
  const entries = Object.entries(reasons).sort(([, left], [, right]) => right - left);
  if (entries.length === 0) {
    return [
      {
        severity: "low",
        type: "OK",
        reason: "No validation reject reasons reported in the latest run.",
        uri: "query-service://validation/reasons",
        repo: "latest run"
      }
    ];
  }
  return entries.slice(0, 4).map(([reason, count], index) => ({
    severity: index === 0 ? "high" : index === 1 ? "medium" : "low",
    type: "Reject",
    reason: `${formatNumber(count)} object(s): ${reason}`,
    uri: `query-service://validation/reasons/${index + 1}`,
    repo: "latest run"
  }));
}

function repoStatus(repo: RepositoryRecord) {
  if (repo.terminalStates.failed_no_cache || repo.phases.rrdp_failed_rsync_failed) {
    return "warning";
  }
  if (repo.terminalStates.fallback_current_instance || repo.phases.rsync_ok) {
    return "fallback";
  }
  return "healthy";
}

function statusForRun(run: RunRecord) {
  if (run.counts.rejectedObjects > 0 || run.counts.warnings > 0) {
    return "Healthy with warnings";
  }
  return "Healthy";
}

function donutGradient(rows: Array<{ value: number; color: string }>) {
  let start = 0;
  const parts = rows.map((row) => {
    const end = Math.min(100, start + row.value);
    const segment = `${row.color} ${start}% ${end}%`;
    start = end;
    return segment;
  });
  return `conic-gradient(${parts.join(", ")})`;
}

function sumValues(values?: CountsByKey) {
  return Object.values(values ?? {}).reduce((sum, value) => sum + value, 0);
}

function percent(value: number, total: number) {
  if (total <= 0) {
    return 0;
  }
  return Math.round((value / total) * 100);
}

function formatNumber(value: number) {
  return new Intl.NumberFormat("en-US").format(value);
}

function formatDuration(ms: number | null) {
  if (ms === null || ms === undefined) {
    return "—";
  }
  if (ms < 1000) {
    return `${ms}ms`;
  }
  return `${(ms / 1000).toFixed(1)}s`;
}

function formatTimestamp(value: string | null) {
  if (!value) {
    return "unknown time";
  }
  return value.replace("T", " ").replace("Z", " UTC");
}

function titleCase(value: string) {
  return value.replace(/_/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
}
