import { useMemo } from "react";
import { Link, useSearchParams } from "react-router-dom";
import { useQueries, useQuery } from "@tanstack/react-query";
import {
  getStatsReasons,
  getStatsValidation,
  listIssues,
  listRepos,
} from "../api/service";
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 { CursorPagerControls } from "../components/CursorPagerControls";
import { DataTable, type Column } from "../components/DataTable";
import { CopyableValue } from "../components/CopyableValue";
import type { ObjectInstanceRecord } from "../api/schemas";
import { useCursorPager } from "../lib/cursor";
import { formatInt, formatPercent, objectTypeLabel, truncateMiddle } from "../lib/format";
import { withRunParam } from "../lib/run";
import { useRun, runErrorTitle } from "../lib/useRun";
import { useNavigate } from "react-router-dom";

export default function ValidationPage() {
  const { runId, runQuery } = useRun();
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();
  const reason = searchParams.get("reason") ?? "";
  const type = searchParams.get("type") ?? "";
  const repoId = searchParams.get("repoId") ?? "";

  const filterKey = JSON.stringify([runId, reason, type, repoId]);
  const pager = useCursorPager(filterKey);

  const [validationQuery, reasonsQuery, reposQuery] = useQueries({
    queries: [
      {
        queryKey: ["stats", runId, "validation"],
        queryFn: () => getStatsValidation(runId),
        staleTime: 60_000,
      },
      {
        queryKey: ["stats", runId, "reasons"],
        queryFn: () => getStatsReasons(runId),
        staleTime: 60_000,
      },
      {
        queryKey: ["repos", runId, "filter-options"],
        queryFn: () => listRepos(runId, { limit: 200 }),
        staleTime: 5 * 60_000,
      },
    ],
  });

  const issuesQuery = useQuery({
    queryKey: ["issues", runId, reason, type, repoId, pager.cursor],
    queryFn: () =>
      listIssues(runId, {
        limit: 50,
        cursor: pager.cursor,
        reason: reason || undefined,
        type: type || undefined,
        repoId: repoId || undefined,
      }),
    placeholderData: (prev) => prev,
  });

  const validationEntries = useMemo(() => {
    const map = validationQuery.data ?? {};
    return Object.entries(map).sort((a, b) => b[1] - a[1]);
  }, [validationQuery.data]);
  const validationTotal = validationEntries.reduce((sum, [, n]) => sum + n, 0);

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

  const setParam = (key: string, value: string) => {
    const params = new URLSearchParams(searchParams);
    if (value) params.set(key, value);
    else params.delete(key);
    setSearchParams(params, { preventScrollReset: true });
  };

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

  const columns: Column<ObjectInstanceRecord>[] = [
    {
      key: "type",
      header: "Type",
      render: (obj) => <span className="chip">{objectTypeLabel(obj.objectType)}</span>,
    },
    {
      key: "uri",
      header: "URI",
      render: (obj) => <CopyableValue value={obj.uri} max={60} label="object URI" />,
    },
    {
      key: "result",
      header: "Result",
      render: (obj) => <StatusPill status={obj.rejected ? "rejected" : obj.result} />,
    },
    {
      key: "reason",
      header: "Reject reason",
      render: (obj) =>
        obj.rejectReason ? (
          <span className="mono text-small" title={obj.rejectReason}>
            {truncateMiddle(obj.rejectReason, 72)}
          </span>
        ) : (
          <span className="text-faint">—</span>
        ),
    },
    {
      key: "source",
      header: "Source",
      render: (obj) => <StatusPill status={obj.sourceSection} />,
    },
  ];

  return (
    <div className="page">
      <PageHeader
        title="Validation"
        subtitle="Rejected and errored objects for the active run, with reason distribution"
      />

      <div className="validation-summary">
        <Panel title="Result distribution" subtitle="Share of audited objects">
          {validationQuery.isError ? (
            <ErrorBlock error={validationQuery.error} onRetry={() => validationQuery.refetch()} />
          ) : validationQuery.isPending ? (
            <LoadingBlock />
          ) : validationEntries.length === 0 ? (
            <p className="text-muted">No validation stats recorded.</p>
          ) : (
            <div className="reason-list">
              {validationEntries.map(([name, count]) => (
                <div className="reason-row" key={name}>
                  <span className="reason-text" style={{ fontFamily: "inherit" }}>
                    <StatusPill status={name} />
                  </span>
                  <span className="reason-count">
                    {formatInt(count)} · {formatPercent(count, validationTotal)}
                  </span>
                </div>
              ))}
            </div>
          )}
        </Panel>

        <Panel title="Reject reasons" subtitle="Click to filter the issue list below">
          {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) => (
                <button
                  key={row.text}
                  type="button"
                  className="reason-row"
                  style={{ border: "none", background: "none", cursor: "pointer", textAlign: "left" }}
                  onClick={() => setParam("reason", row.text === reason ? "" : row.text)}
                  title={row.text}
                  aria-pressed={row.text === reason}
                >
                  <span className="reason-text">{row.text}</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>
                </button>
              ))}
            </div>
          )}
        </Panel>
      </div>

      <Panel
        title="Validation issues"
        subtitle="Objects that were rejected or failed validation"
        tools={
          <div className="filter-bar">
            <div className="filter-field">
              <label htmlFor="issue-type">Type</label>
              <select id="issue-type" value={type} onChange={(e) => setParam("type", e.target.value)}>
                <option value="">all</option>
                {["roa", "manifest", "crl", "certificate", "aspa", "gbr"].map((t) => (
                  <option key={t} value={t}>{objectTypeLabel(t)}</option>
                ))}
              </select>
            </div>
            <div className="filter-field">
              <label htmlFor="issue-repo">Repository</label>
              <select id="issue-repo" value={repoId} onChange={(e) => setParam("repoId", e.target.value)}>
                <option value="">all</option>
                {(reposQuery.data?.items ?? []).map((repo) => (
                  <option key={repo.repoId} value={repo.repoId}>
                    {repo.host}
                  </option>
                ))}
              </select>
            </div>
            <div className="filter-field">
              <label htmlFor="issue-reason">Reason contains</label>
              <input
                id="issue-reason"
                type="text"
                value={reason}
                onChange={(e) => setParam("reason", e.target.value)}
                placeholder="substring…"
                className="mono"
              />
            </div>
            {(reason || type || repoId) && (
              <Link className="btn small" to={withRunParam("/validation", runId)}>
                Clear filters
              </Link>
            )}
          </div>
        }
        flush
      >
        <DataTable
          columns={columns}
          rows={issuesQuery.data?.items ?? []}
          rowKey={(obj) => obj.objectInstanceId}
          loading={issuesQuery.isPending}
          error={issuesQuery.isError ? issuesQuery.error : undefined}
          onRetry={() => issuesQuery.refetch()}
          emptyTitle="No validation issues"
          emptyHint="Nothing was rejected or errored in this run (or filters are too strict)."
          caption="Validation issues"
          onRowClick={(obj) =>
            navigate(withRunParam(`/objects/${encodeURIComponent(obj.objectInstanceId)}`, runId))
          }
        />
        <CursorPagerControls
          page={pager.page}
          canPrev={pager.canPrev}
          hasNext={issuesQuery.data?.nextCursor != null}
          loading={issuesQuery.isFetching}
          onPrev={pager.goPrev}
          onNext={() => pager.goNext(issuesQuery.data?.nextCursor ?? null)}
          itemCount={issuesQuery.data?.items.length}
        />
      </Panel>

      <div className="kpi-grid">
        <KpiCard
          label="Issues on this page"
          value={formatInt(issuesQuery.data?.items.length)}
          tone="red"
        />
        <KpiCard
          label="Distinct reasons"
          value={formatInt(Object.keys(reasonsQuery.data ?? {}).length)}
          tone="amber"
        />
      </div>
    </div>
  );
}
