import { useMemo } from "react";
import { Link, useNavigate } from "react-router-dom";
import { useQueries } from "@tanstack/react-query";
import {
  Cell,
  Pie,
  PieChart,
  ResponsiveContainer,
  Bar,
  BarChart,
  XAxis,
  YAxis,
  Tooltip,
} from "recharts";
import { Clock, GitBranch, Timer } from "lucide-react";
import {
  getStatsObjectTypes,
  getStatsReasons,
  getStatsValidation,
  listRepos,
} from "../api/service";
import type { RepositoryRecord } from "../api/schemas";
import { DataTable, type Column } from "../components/DataTable";
import { KpiCard } from "../components/KpiCard";
import { PageHeader } from "../components/PageHeader";
import { Panel } from "../components/Panel";
import { StatusPill } from "../components/StatusPill";
import { ErrorBlock, LoadingBlock } from "../components/StateBlock";
import {
  formatDurationMs,
  formatInt,
  formatPercent,
  formatRelative,
  formatUtc,
  objectTypeLabel,
  truncateMiddle,
} from "../lib/format";
import { withRunParam } from "../lib/run";
import { useRun, runErrorTitle } from "../lib/useRun";

/** Semantic colors keyed by validation result — never assigned by index. */
const RESULT_COLORS: Record<string, string> = {
  ok: "#16a34a",
  valid: "#16a34a",
  warnings: "#d97706",
  warning: "#d97706",
  error: "#dc2626",
  invalid: "#dc2626",
  rejected: "#dc2626",
  skipped: "#94a3b8",
  unknown: "#94a3b8",
};
const FALLBACK_COLORS = ["#2563eb", "#0ea5e9", "#6366f1", "#8b5cf6", "#64748b"];
const TYPE_PALETTE = ["#1d4ed8", "#2563eb", "#3b82f6", "#60a5fa", "#93c5fd", "#0ea5e9", "#38bdf8", "#7dd3fc"];

function colorForResult(name: string, index: number): string {
  return RESULT_COLORS[name.toLowerCase()] ?? FALLBACK_COLORS[index % FALLBACK_COLORS.length];
}

export default function OverviewPage() {
  const { runId, runQuery } = useRun();
  const navigate = useNavigate();

  const [validationQuery, typesQuery, reasonsQuery, reposQuery] = useQueries({
    queries: [
      {
        queryKey: ["stats", runId, "validation"],
        queryFn: () => getStatsValidation(runId),
        staleTime: 60_000,
      },
      {
        queryKey: ["stats", runId, "object-types"],
        queryFn: () => getStatsObjectTypes(runId),
        staleTime: 60_000,
      },
      {
        queryKey: ["stats", runId, "reasons"],
        queryFn: () => getStatsReasons(runId),
        staleTime: 60_000,
      },
      {
        queryKey: ["repos", runId, "top"],
        queryFn: () => listRepos(runId, { limit: 8 }),
        staleTime: 60_000,
      },
    ],
  });

  const run = runQuery.data;
  const counts = run?.counts;

  const validationData = useMemo(() => {
    const map = validationQuery.data ?? {};
    return Object.entries(map)
      .map(([name, value]) => ({ name, value }))
      .sort((a, b) => b.value - a.value);
  }, [validationQuery.data]);

  const validationTotal = useMemo(
    () => validationData.reduce((sum, entry) => sum + entry.value, 0),
    [validationData],
  );

  const typeData = useMemo(() => {
    const map = typesQuery.data ?? {};
    return Object.entries(map)
      .map(([name, value]) => ({ name: objectTypeLabel(name), value }))
      .sort((a, b) => b.value - a.value)
      .slice(0, 8);
  }, [typesQuery.data]);

  const reasonRows = useMemo(() => {
    const map = reasonsQuery.data ?? {};
    return Object.entries(map)
      .map(([reason, count]) => ({ reason, count }))
      .sort((a, b) => b.count - a.count)
      .slice(0, 8);
  }, [reasonsQuery.data]);

  const maxReason = reasonRows[0]?.count ?? 0;

  if (runQuery.isError) {
    return (
      <div className="page">
        <PageHeader title="Overview" />
        <ErrorBlock
          error={runQuery.error}
          onRetry={() => runQuery.refetch()}
          title={runErrorTitle(runId, runQuery.error)}
        />
      </div>
    );
  }

  const repoColumns: Column<RepositoryRecord>[] = [
    {
      key: "host",
      header: "Repository",
      render: (repo) => (
        <div>
          <div className="cell-main">{repo.host}</div>
          <div className="text-faint text-small mono ellipsis" style={{ maxWidth: 260 }}>
            {truncateMiddle(repo.uri, 56)}
          </div>
        </div>
      ),
    },
    {
      key: "transport",
      header: "Transport",
      render: (repo) => <span className="chip">{repo.transport ?? "unknown"}</span>,
    },
    { key: "objects", header: "Objects", numeric: true, render: (repo) => formatInt(repo.objects) },
    {
      key: "rejected",
      header: "Rejected",
      numeric: true,
      render: (repo) =>
        repo.rejectedObjects ? (
          <span style={{ color: "var(--red-700)", fontWeight: 600 }}>
            {formatInt(repo.rejectedObjects)}
          </span>
        ) : (
          "0"
        ),
    },
    {
      key: "duration",
      header: "Sync time",
      numeric: true,
      render: (repo) => formatDurationMs(repo.syncDurationMsTotal),
    },
    {
      key: "terminal",
      header: "Terminal states",
      render: (repo) => (
        <span className="chip-list">
          {Object.entries(repo.terminalStates ?? {}).map(([state, count]) => (
            <StatusPill key={state} status={state} label={`${state} ${formatInt(count)}`} />
          ))}
        </span>
      ),
    },
  ];

  return (
    <div className="page">
      <PageHeader
        title="Overview"
        subtitle={
          run ? (
            <span className="overview-run-strip">
              <span className="run-strip-item mono">{run.runId}</span>
              <span className="run-strip-item">
                <Clock size={13} aria-hidden="true" />
                <span title={formatUtc(run.validationTime)}>
                  validated {formatRelative(run.validationTime)}
                </span>
              </span>
              {run.syncMode ? (
                <span className="run-strip-item">
                  <GitBranch size={13} aria-hidden="true" /> {run.syncMode} sync
                </span>
              ) : null}
              <span className="run-strip-item">
                <Timer size={13} aria-hidden="true" /> wall {formatDurationMs(run.wallMs)}
              </span>
              {run.indexStatus ? <StatusPill status={run.indexStatus} label={`index ${run.indexStatus}`} /> : null}
            </span>
          ) : undefined
        }
      />

      {runQuery.isPending ? (
        <LoadingBlock label="Loading latest run…" />
      ) : (
        <>
          <div className="kpi-grid">
            <KpiCard label="VRPs" value={formatInt(counts?.vrps)} to={withRunParam("/objects?type=roa", runId)} />
            <KpiCard label="ASPAs" value={formatInt(counts?.aspas)} to={withRunParam("/objects?type=aspa", runId)} />
            <KpiCard label="Objects" value={formatInt(counts?.objects)} to={withRunParam("/objects", runId)} />
            <KpiCard
              label="Publication points"
              value={formatInt(counts?.publicationPoints)}
              to={withRunParam("/publication-points", runId)}
            />
            <KpiCard
              label="Rejected"
              value={formatInt(counts?.rejectedObjects)}
              tone="red"
              to={withRunParam("/validation", runId)}
            />
            <KpiCard
              label="Warnings"
              value={formatInt(counts?.warnings)}
              tone="amber"
              sub="objects with warnings"
              to={withRunParam("/validation", runId)}
            />
          </div>

          <div className="overview-charts">
            <Panel title="Validation results" subtitle="Object audit results for this run">
              {validationQuery.isError ? (
                <ErrorBlock error={validationQuery.error} onRetry={() => validationQuery.refetch()} />
              ) : validationQuery.isPending ? (
                <LoadingBlock />
              ) : validationData.length === 0 ? (
                <p className="text-muted">No validation stats recorded.</p>
              ) : (
                <>
                  <div className="chart-box">
                    <ResponsiveContainer initialDimension={{ width: 400, height: 240 }}>
                      <PieChart>
                        <Pie
                          data={validationData}
                          dataKey="value"
                          nameKey="name"
                          innerRadius="58%"
                          outerRadius="88%"
                          paddingAngle={2}
                          strokeWidth={0}
                        >
                          {validationData.map((entry, index) => (
                            <Cell key={entry.name} fill={colorForResult(entry.name, index)} />
                          ))}
                        </Pie>
                        <Tooltip
                          formatter={(value, name) => [
                            `${formatInt(Number(value))} (${formatPercent(Number(value), validationTotal)})`,
                            String(name),
                          ]}
                        />
                      </PieChart>
                    </ResponsiveContainer>
                  </div>
                  <div className="chart-legend">
                    {validationData.map((entry, index) => (
                      <span className="legend-item" key={entry.name}>
                        <span
                          className="legend-swatch"
                          style={{ background: colorForResult(entry.name, index) }}
                        />
                        {entry.name} · {formatInt(entry.value)} ({formatPercent(entry.value, validationTotal)})
                      </span>
                    ))}
                  </div>
                </>
              )}
            </Panel>

            <Panel title="Object types" subtitle="Objects by parsed type">
              {typesQuery.isError ? (
                <ErrorBlock error={typesQuery.error} onRetry={() => typesQuery.refetch()} />
              ) : typesQuery.isPending ? (
                <LoadingBlock />
              ) : typeData.length === 0 ? (
                <p className="text-muted">No object type stats recorded.</p>
              ) : (
                <div className="chart-box">
                  <ResponsiveContainer initialDimension={{ width: 400, height: 240 }}>
                    <BarChart data={typeData} layout="vertical" margin={{ left: 12, right: 24 }}>
                      <XAxis type="number" hide />
                      <YAxis
                        type="category"
                        dataKey="name"
                        width={104}
                        tickLine={false}
                        axisLine={false}
                        tick={{ fontSize: 12, fill: "var(--text-2)" }}
                      />
                      <Tooltip formatter={(value) => formatInt(Number(value))} />
                      <Bar dataKey="value" radius={[0, 4, 4, 0]} barSize={16}>
                        {typeData.map((entry, index) => (
                          <Cell key={entry.name} fill={TYPE_PALETTE[index % TYPE_PALETTE.length]} />
                        ))}
                      </Bar>
                    </BarChart>
                  </ResponsiveContainer>
                </div>
              )}
            </Panel>
          </div>

          <div className="overview-bottom">
            <Panel
              title="Top repositories"
              subtitle="First repositories by index order"
              tools={
                <Link className="btn small" to={withRunParam("/repositories", runId)}>
                  View all
                </Link>
              }
              flush
            >
              {reposQuery.isError ? (
                <div className="panel-body">
                  <ErrorBlock error={reposQuery.error} onRetry={() => reposQuery.refetch()} />
                </div>
              ) : (
                <DataTable
                  columns={repoColumns}
                  rows={reposQuery.data?.items ?? []}
                  rowKey={(repo) => repo.repoId}
                  loading={reposQuery.isPending}
                  emptyTitle="No repositories indexed"
                  onRowClick={(repo) =>
                    navigate(withRunParam(`/repositories/${encodeURIComponent(repo.repoId)}`, runId))
                  }
                />
              )}
            </Panel>

            <Panel
              title="Top reject reasons"
              subtitle="Click a reason to inspect matching objects"
              tools={
                <Link className="btn small" to={withRunParam("/validation", runId)}>
                  Validation
                </Link>
              }
            >
              {reasonsQuery.isError ? (
                <ErrorBlock error={reasonsQuery.error} onRetry={() => reasonsQuery.refetch()} />
              ) : reasonsQuery.isPending ? (
                <LoadingBlock />
              ) : reasonRows.length === 0 ? (
                <p className="text-muted">No rejected objects in this run.</p>
              ) : (
                <div className="reason-list">
                  {reasonRows.map((row) => (
                    <Link
                      key={row.reason}
                      className="reason-row"
                      to={withRunParam(`/validation?reason=${encodeURIComponent(row.reason)}`, runId)}
                      title={row.reason}
                    >
                      <span className="reason-text">{row.reason}</span>
                      <span className="reason-count">{formatInt(row.count)}</span>
                      <span className="reason-bar" aria-hidden="true">
                        <span style={{ width: `${maxReason ? (row.count / maxReason) * 100 : 0}%` }} />
                      </span>
                    </Link>
                  ))}
                </div>
              )}
            </Panel>
          </div>
        </>
      )}
    </div>
  );
}
