import { and, eq } from "drizzle-orm";
import { headers } from "next/headers";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { auditJob, auditReport, db } from "@/db";
import { auth } from "@/lib/auth";
import {
  type FindingGroup,
  groupFindings,
  isFatal,
  labelForKind,
  type Page,
  type RunReport,
  type Severity,
  VERDICT_LABEL,
  verdictOf,
  vetReport,
} from "@/lib/report";

/**
 * The paid half.
 *
 * The full report is read here and nowhere else — no API route serves it. Two
 * conditions guard it, and both are in the same query: a session must exist,
 * and the job must belong to that session's user. Ownership is a WHERE clause
 * rather than a check on the row afterwards, so there is no version of this
 * code that loads somebody else's report before deciding not to show it.
 */
export default async function ReportPage({ params }: { params: Promise<{ id: string }> }) {
  const session = await auth.api.getSession({ headers: await headers() });
  if (!session) redirect("/auth");

  const { id } = await params;
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)) notFound();

  const [row] = await db
    .select({
      origin: auditJob.origin,
      createdAt: auditJob.createdAt,
      document: auditReport.report,
    })
    .from(auditJob)
    .innerJoin(auditReport, eq(auditReport.jobId, auditJob.id))
    .where(and(eq(auditJob.id, id), eq(auditJob.userId, session.user.id)))
    .limit(1);

  if (!row) notFound();

  const report = vetReport(row.document);
  if (!report) notFound();

  const verdict = verdictOf(report);

  return (
    <main className="mx-auto w-full max-w-3xl flex-1 px-6 py-16">
      <Link
        href="/dashboard"
        className="text-sm text-zinc-500 underline underline-offset-4 dark:text-zinc-400"
      >
        ← Mes audits
      </Link>

      <header className="mt-6">
        <h1 className="text-2xl font-semibold tracking-tight text-zinc-900 dark:text-zinc-100">
          {report.site}
        </h1>
        <p className="mt-1 text-sm text-zinc-500 dark:text-zinc-400">
          <time dateTime={row.createdAt.toISOString()}>
            {row.createdAt.toLocaleString("fr-FR", { dateStyle: "long", timeStyle: "short" })}
          </time>
          {" · "}
          nextjs-seo-prerender {report.version}
        </p>
        <p
          className={`mt-4 text-lg font-semibold ${
            verdict === "blocking" || verdict === "fatal"
              ? "text-red-700 dark:text-red-400"
              : "text-emerald-700 dark:text-emerald-400"
          }`}
        >
          {VERDICT_LABEL[verdict]}
        </p>
      </header>

      {report.notes.length > 0 && (
        <ul className="mt-6 space-y-1 rounded-lg bg-zinc-100 p-4 text-sm text-zinc-600 dark:bg-zinc-900 dark:text-zinc-400">
          {report.notes.map((note) => (
            <li key={note}>{note}</li>
          ))}
        </ul>
      )}

      {isFatal(report) ? (
        <section className="mt-8 rounded-xl border border-red-300 bg-red-50 p-6 dark:border-red-900 dark:bg-red-950">
          <p className="font-medium text-red-900 dark:text-red-200">{report.fatal.message}</p>
          {report.fatal.detail && (
            <ul className="mt-3 space-y-1 text-sm text-red-800 dark:text-red-300">
              {report.fatal.detail.map((line) => (
                <li key={line}>{line}</li>
              ))}
            </ul>
          )}
          <p className="mt-4 text-sm text-red-800 dark:text-red-300">
            Rien n&apos;a pu être vérifié&nbsp;: ce n&apos;est pas un résultat positif.
          </p>
        </section>
      ) : (
        <RunBody report={report} />
      )}
    </main>
  );
}

function RunBody({ report }: { report: RunReport }) {
  const groups = groupFindings(report);
  const blocking = groups.filter((group) => group.severity === "error");
  const warned = groups.filter((group) => group.severity === "warn");
  const noted = groups.filter((group) => group.severity === "info");

  return (
    <>
      <section className="mt-8 grid grid-cols-2 gap-4 sm:grid-cols-4">
        <Metric label="Pages vérifiées" value={`${report.summary.checked}/${report.discovery.total}`} />
        <Metric label="Bloquants" value={report.summary.blocking} alarming={report.summary.blocking > 0} />
        <Metric label="Avertissements" value={report.warnings} />
        <Metric label="Rendus dynamiques" value={report.summary.dynamic} />
      </section>

      <p className="mt-3 text-xs text-zinc-500 dark:text-zinc-400">
        Découverte&nbsp;: {report.discovery.source}
        {report.discovery.rebased ? ` · ${report.discovery.rebased}` : ""}
      </p>

      {/* Grouped by problem, not by page: one broken template produces the same
          finding on forty pages, and reading it forty times teaches nothing. */}
      <Groups title="À corriger" groups={blocking} tone="error" />
      <Groups title="À surveiller" groups={warned} tone="warn" />
      <Groups title="Pour information" groups={noted} tone="info" />

      {groups.length === 0 && (
        <p className="mt-8 rounded-xl border border-emerald-300 bg-emerald-50 p-6 text-emerald-900 dark:border-emerald-900 dark:bg-emerald-950 dark:text-emerald-200">
          Aucun problème relevé sur les pages vérifiées.
        </p>
      )}

      <Pages pages={report.pages} />
    </>
  );
}

const TONE: Record<Severity, string> = {
  error: "border-red-300 dark:border-red-900",
  warn: "border-amber-300 dark:border-amber-900",
  info: "border-zinc-200 dark:border-zinc-800",
};

const BADGE: Record<Severity, string> = {
  error: "bg-red-100 text-red-800 dark:bg-red-950 dark:text-red-300",
  warn: "bg-amber-100 text-amber-900 dark:bg-amber-950 dark:text-amber-300",
  info: "bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300",
};

function Groups({
  title,
  groups,
  tone,
}: {
  title: string;
  groups: FindingGroup[];
  tone: Severity;
}) {
  if (groups.length === 0) return null;
  return (
    <section className="mt-10">
      <h2 className="text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
        {title}
      </h2>
      <div className="mt-3 space-y-4">
        {groups.map((group) => (
          <article
            key={`${group.kind}:${group.severity}`}
            className={`rounded-xl border bg-white p-5 dark:bg-zinc-900 ${TONE[tone]}`}
          >
            <div className="flex items-start justify-between gap-4">
              <h3 className="font-medium text-zinc-900 dark:text-zinc-100">
                {labelForKind(group.kind)}
              </h3>
              <span
                className={`shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium ${BADGE[tone]}`}
              >
                {group.pages.length} page{group.pages.length > 1 ? "s" : ""}
              </span>
            </div>
            <p className="mt-1.5 text-sm text-zinc-600 dark:text-zinc-400">{group.message}</p>

            <ul className="mt-4 space-y-2 text-sm">
              {group.pages.map((page) => (
                <li key={page.url}>
                  <a
                    href={page.url}
                    rel="noreferrer nofollow"
                    target="_blank"
                    className="break-all text-zinc-700 underline underline-offset-2 hover:text-zinc-900 dark:text-zinc-300 dark:hover:text-zinc-100"
                  >
                    {pathOf(page.url)}
                  </a>
                  {page.detail && (
                    <ul className="mt-1 space-y-0.5 pl-4 text-xs text-zinc-500 dark:text-zinc-400">
                      {page.detail.map((line) => (
                        <li key={line} className="break-all">
                          {line}
                        </li>
                      ))}
                    </ul>
                  )}
                </li>
              ))}
            </ul>
          </article>
        ))}
      </div>
    </section>
  );
}

/** The per-page table, for the reader who wants the raw shape of the crawl. */
function Pages({ pages }: { pages: Page[] }) {
  if (pages.length === 0) return null;
  return (
    <section className="mt-12">
      <h2 className="text-sm font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
        Pages vérifiées
      </h2>
      <div className="mt-3 overflow-x-auto">
        <table className="w-full min-w-lg border-collapse text-sm">
          <thead>
            <tr className="border-b border-zinc-200 text-left text-xs uppercase tracking-wide text-zinc-500 dark:border-zinc-800 dark:text-zinc-400">
              <th className="py-2 pr-4 font-medium">Page</th>
              <th className="py-2 pr-4 font-medium">Rendu</th>
              <th className="py-2 pr-4 text-right font-medium">Mots</th>
              <th className="py-2 pr-4 text-right font-medium">Liens</th>
              <th className="py-2 text-right font-medium">TTFB</th>
            </tr>
          </thead>
          <tbody className="divide-y divide-zinc-100 dark:divide-zinc-800">
            {pages.map((page) => (
              <tr key={page.url} className="text-zinc-700 dark:text-zinc-300">
                <td className="max-w-xs truncate py-2 pr-4" title={page.url}>
                  {pathOf(page.url)}
                  {page.outcome !== "checked" && (
                    <span className="ml-2 text-xs text-zinc-500 dark:text-zinc-400">
                      {outcomeLabel(page)}
                    </span>
                  )}
                </td>
                {/* An absent measurement is an em dash, never a zero: the
                    contract is explicit that the two are different facts. */}
                <td className="py-2 pr-4">{page.render_mode ?? "—"}</td>
                <td className="py-2 pr-4 text-right tabular-nums">{page.words ?? "—"}</td>
                <td className="py-2 pr-4 text-right tabular-nums">{page.internal_links ?? "—"}</td>
                <td className="py-2 text-right tabular-nums">
                  {page.ttfb_ms === undefined ? "—" : `${page.ttfb_ms} ms`}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </section>
  );
}

function Metric({
  label,
  value,
  alarming = false,
}: {
  label: string;
  value: number | string;
  alarming?: boolean;
}) {
  return (
    <div className="rounded-xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-900">
      <p
        className={`text-xl font-semibold tabular-nums ${
          alarming ? "text-red-700 dark:text-red-400" : "text-zinc-900 dark:text-zinc-100"
        }`}
      >
        {value}
      </p>
      <p className="mt-1 text-xs text-zinc-500 dark:text-zinc-400">{label}</p>
    </div>
  );
}

function pathOf(url: string): string {
  try {
    const parsed = new URL(url);
    return parsed.pathname + parsed.search || "/";
  } catch {
    return url;
  }
}

function outcomeLabel(page: Page): string {
  if (page.outcome === "redirect") return `→ ${page.redirects_to ?? "redirigée"}`;
  if (page.outcome === "http-error") return `HTTP ${page.status ?? "?"}`;
  if (page.outcome === "not-html") return "non HTML";
  if (page.outcome === "unreachable") return "injoignable";
  return "";
}
