// app/(public)/sorteo/verificar/page.tsx
// PUBLIC draw-verification page. No login. Anyone (a losing participant, a
// journalist, INDECOPI, a government veedor) can confirm the winners were drawn
// fairly and were not manipulated. It renders the PII-free verification bundle +
// the server-side verifyDraw() verdict (shared getDrawVerification), a plain-
// language explainer of the commit-reveal + drand scheme, and a link to the public
// drand beacon so the randomness can be checked against a third party.

import * as React from "react";
import Link from "next/link";
import { listRaffles } from "@/app/admin/_lib/queries";
import { getDrawVerification, type DrawVerification } from "@/lib/draw/certificate";
import { DRAND_QUICKNET_CHAIN_HASH } from "@/lib/draw/drand";
import { Card } from "@/components/ui";

export const dynamic = "force-dynamic";

const mono: React.CSSProperties = {
  fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
};

export const metadata = {
  title: "Verifica el sorteo | Rifa Teletón",
  description:
    "Comprueba de forma independiente que el sorteo de la Rifa Solidaria Teletón fue justo y no fue manipulado.",
};

export default async function VerifyPage({
  searchParams,
}: {
  searchParams: Promise<{ raffle?: string }>;
}) {
  const { raffle: raffleParam } = await searchParams;
  const raffles = await listRaffles();

  // Only raffles that already have a committed draw are verifiable.
  const withDraw = (
    await Promise.all(
      raffles.map(async (r) => ({
        raffle: r,
        v: await getDrawVerification(r.id),
      })),
    )
  ).filter((x): x is { raffle: (typeof raffles)[number]; v: DrawVerification } =>
    x.v !== null,
  );

  const selected =
    withDraw.find((x) => x.raffle.id === raffleParam) ?? withDraw[0] ?? null;

  return (
    <div className="mx-auto flex w-full max-w-[720px] flex-col gap-lg px-5 py-10">
      <div className="flex flex-col gap-2">
        <h1 className="font-display text-heading-lg text-ink-strong">
          Verifica el sorteo
        </h1>
        <p className="font-body text-body-md text-muted">
          El sorteo de la Rifa Solidaria Teletón es transparente y reproducible.
          Cualquier persona puede comprobar, con esta misma página o con sus propias
          herramientas, que los ganadores salieron de forma justa y que la
          organización no eligió el resultado.
        </p>
      </div>

      {selected === null ? (
        <Card elevation="tight" className="p-lg">
          <p className="font-body text-body-md text-ink-strong">
            Aún no se ha realizado ningún sorteo.
          </p>
          <p className="mt-1 font-body text-body-sm text-muted">
            Cuando el sorteo se realice, esta página mostrará el certificado
            verificable con los números ganadores.
          </p>
        </Card>
      ) : (
        <>
          {withDraw.length > 1 ? (
            <nav className="flex flex-wrap gap-2" aria-label="Sorteos verificables">
              {withDraw.map((x) => {
                const active = x.raffle.id === selected.raffle.id;
                return (
                  <Link
                    key={x.raffle.id}
                    href={`/sorteo/verificar?raffle=${x.raffle.id}`}
                    className={`inline-flex min-h-11 items-center rounded-full border px-4 font-body text-body-sm ${
                      active
                        ? "border-primary bg-primary text-on-primary"
                        : "border-hairline text-ink-strong hover:border-ink-strong"
                    }`}
                  >
                    {x.raffle.name}
                  </Link>
                );
              })}
            </nav>
          ) : null}

          <Verdict data={selected.v} raffleName={selected.raffle.name} />

          <CertificateCard data={selected.v} raffleId={selected.raffle.id} />

          <Explainer round={selected.v.bundle.drandRound} />
        </>
      )}
    </div>
  );
}

function Verdict({
  data,
  raffleName,
}: {
  data: DrawVerification;
  raffleName: string;
}) {
  const { verification } = data;

  if (verification === null) {
    return (
      <Card elevation="tight" className="p-lg">
        <p className="font-body text-caption uppercase tracking-wide text-muted-label">
          {raffleName}
        </p>
        <p className="mt-1 font-display text-heading-md text-ink-strong">
          Sorteo comprometido, aún no revelado
        </p>
        <p className="mt-2 font-body text-body-md text-muted">
          La organización ya publicó su compromiso (el hash de la semilla, el
          snapshot de los boletos y la ronda drand futura) antes de conocer el
          resultado. Cuando la ronda drand se publique y el sorteo se revele, aquí
          aparecerán los ganadores y la verificación completa.
        </p>
      </Card>
    );
  }

  const ok = verification.matches;
  return (
    <Card elevation="tight" className="p-lg">
      <p className="font-body text-caption uppercase tracking-wide text-muted-label">
        {raffleName}
      </p>
      <p
        className={`mt-1 font-display text-heading-md ${ok ? "text-ink-strong" : "text-primary"}`}
      >
        {ok ? "Sorteo verificado" : "Se detectó una discrepancia"}
      </p>
      <p className="mt-2 font-body text-body-md text-muted">
        {ok
          ? "Los ganadores se reprodujeron exactamente a partir del certificado público. Nadie pudo elegir ni alterar el resultado."
          : "La reproducción del sorteo no coincide con lo registrado. Revisa el detalle de las comprobaciones."}
      </p>

      <ul className="mt-4 flex flex-col gap-2">
        {verification.checks.map((c, i) => (
          <li key={i} className="flex items-start gap-2">
            <span
              aria-hidden
              className={`mt-0.5 font-body text-body-md ${c.ok ? "text-ink-strong" : "text-primary"}`}
            >
              {c.ok ? "✓" : "✗"}
            </span>
            <span className="font-body text-body-sm text-ink-strong">
              {c.label}
              {c.detail ? (
                <span className="mt-0.5 block text-caption text-muted" style={mono}>
                  {c.detail}
                </span>
              ) : null}
            </span>
          </li>
        ))}
      </ul>

      {verification.recomputedWinnerTicketNos.length > 0 ? (
        <div className="mt-4 border-t border-hairline pt-3">
          <p className="font-body text-caption uppercase tracking-wide text-muted-label">
            Boletos ganadores
          </p>
          <p className="mt-1 font-body text-body-md font-semibold text-ink-strong tabular-nums">
            {verification.recomputedWinnerTicketNos.join(", ")}
          </p>
        </div>
      ) : null}
    </Card>
  );
}

function CertificateCard({
  data,
  raffleId,
}: {
  data: DrawVerification;
  raffleId: string;
}) {
  const b = data.bundle;
  return (
    <Card elevation="tight" className="p-lg">
      <div className="flex flex-wrap items-center justify-between gap-2">
        <h2 className="font-body text-caption uppercase tracking-wide text-muted-label">
          Certificado
        </h2>
        <a
          href={`/api/verificar/${raffleId}`}
          className="font-body text-body-sm text-steelblue underline-offset-2 hover:underline"
        >
          Descargar en JSON
        </a>
      </div>
      <dl className="mt-2 flex flex-col gap-2">
        <CertRow label="Hash de la semilla (comprometido antes del sorteo)" value={b.serverSeedHash} />
        <CertRow label="Semilla revelada" value={b.serverSeed ?? "— (aún no revelada)"} />
        <CertRow label="Ronda drand" value={String(b.drandRound)} />
        <CertRow label="Aleatoriedad drand" value={b.drandRandomness ?? "— (aún no publicada)"} />
        <CertRow label="Semilla final = sha256(semilla ‖ aleatoriedad)" value={b.finalSeed ?? "— (aún no revelada)"} />
        <CertRow label="Hash del snapshot de boletos" value={b.snapshotHash} />
        <CertRow label="Boletos en el pool (congelados en el corte)" value={String(b.snapshotTicketCount)} />
      </dl>
      <p className="mt-3 font-body text-caption text-muted">
        El certificado no contiene datos personales: solo números de boleto, hashes
        y la semilla.
      </p>
    </Card>
  );
}

function CertRow({ label, value }: { label: string; value: string }) {
  return (
    <div className="flex flex-col gap-0.5">
      <dt className="font-body text-caption text-muted-label">{label}</dt>
      <dd className="break-all font-body text-body-sm text-ink-strong" style={mono}>
        {value}
      </dd>
    </div>
  );
}

function Explainer({ round }: { round: number }) {
  const drandUrl = `https://api.drand.sh/${DRAND_QUICKNET_CHAIN_HASH}/public/${round}`;
  return (
    <Card elevation="tight" className="p-lg">
      <h2 className="font-body text-caption uppercase tracking-wide text-muted-label">
        Cómo verificarlo tú mismo
      </h2>
      <ol className="mt-2 flex list-decimal flex-col gap-2 pl-5">
        <li className="font-body text-body-sm text-ink-strong">
          <strong>Compromiso previo.</strong> Antes del sorteo, la organización
          publicó el hash de una semilla secreta y eligió una ronda futura de{" "}
          <span className="font-semibold">drand</span> (una red pública de
          aleatoriedad que emite un número impredecible y firmado cada pocos
          segundos). Como la ronda todavía no existía, la semilla no se pudo elegir
          a conveniencia.
        </li>
        <li className="font-body text-body-sm text-ink-strong">
          <strong>Boletos congelados.</strong> El pool de boletos quedó sellado en
          la fecha de corte y su lista quedó resumida en el hash del snapshot.
        </li>
        <li className="font-body text-body-sm text-ink-strong">
          <strong>Revelación.</strong> Al salir la ronda drand, se combinó la
          semilla con esa aleatoriedad pública para obtener la semilla final, y con
          ella se corrió una selección determinista que eligió a los ganadores.
        </li>
        <li className="font-body text-body-sm text-ink-strong">
          <strong>Comprueba la ronda.</strong> La aleatoriedad de arriba debe
          coincidir con la de la red pública de drand:{" "}
          <a
            href={drandUrl}
            target="_blank"
            rel="noopener noreferrer"
            className="text-steelblue underline underline-offset-2"
          >
            ver la ronda #{round} en drand
          </a>
          .
        </li>
      </ol>
    </Card>
  );
}
