// app/admin/participantes/[id]/page.tsx
// Participant drill-down (admin.md 2.2 — the dispute-handling view). Shows the
// ACTUAL ticket numbers a participant holds, their total paid, and every purchase
// with status, for one raffle. Scoped by ?raffle=<id> (defaults to the newest).
//
// PII: phone/email/DNI render MASKED here and the RAW values are never sent to the
// client — the audited CSV export is the path for full contact data. So this page
// is safe for any viewer+ and adds no new PII-on-the-wire surface.

import * as React from "react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { requireRole, AuthError } from "@/lib/auth";
import { listRaffles, getParticipantDetail } from "@/app/admin/_lib/queries";
import { maskPhone, maskEmail } from "@/app/admin/_lib/format";
import { formatPEN } from "@/lib/money";
import { Card } from "@/components/ui";
import type { PurchaseStatus } from "@/lib/types";

export const dynamic = "force-dynamic";

const STATUS_LABEL: Record<PurchaseStatus, string> = {
  paid: "Pagada",
  pending: "Pendiente",
  failed: "Fallida",
  expired: "Expirada",
  refunded: "Reembolsada",
};

/** Mask a DNI to its last 3 digits ("70801042" -> "*****042"). Staff can confirm
 *  the right person without exposing the full national id; the CSV export carries
 *  the full value under the audited path. */
function maskDni(dni: string | null): string {
  if (!dni) return "—";
  if (dni.length <= 3) return "*".repeat(dni.length);
  return "*".repeat(dni.length - 3) + dni.slice(-3);
}

export default async function ParticipantDetailPage({
  params,
  searchParams,
}: {
  params: Promise<{ id: string }>;
  searchParams: Promise<{ raffle?: string }>;
}) {
  try {
    await requireRole("viewer");
  } catch (err) {
    if (err instanceof AuthError) redirect("/admin/login");
    throw err;
  }

  const { id } = await params;
  const { raffle: raffleParam } = await searchParams;

  const raffles = await listRaffles();
  if (raffles.length === 0) {
    return (
      <p className="font-body text-body-lg text-muted">Aún no hay sorteos creados.</p>
    );
  }
  const selected = raffles.find((r) => r.id === raffleParam) ?? raffles[0];
  const backHref = `/admin/participantes?raffle=${selected.id}`;

  const detail = await getParticipantDetail(selected.id, id);
  if (!detail) {
    return (
      <div className="flex flex-col gap-md">
        <Link
          href={backHref}
          className="font-body text-body-md text-steelblue hover:underline"
        >
          ← Volver a participantes
        </Link>
        <p className="font-body text-body-lg text-muted">
          No encontramos este participante.
        </p>
      </div>
    );
  }

  return (
    <div className="flex flex-col gap-lg">
      <div className="flex flex-col gap-1">
        <Link
          href={backHref}
          className="font-body text-caption text-steelblue hover:underline"
        >
          ← Participantes
        </Link>
        <h1 className="font-impact text-heading-lg font-bold text-ink-strong">
          {detail.fullName}
        </h1>
        <p className="font-body text-caption text-muted">En {selected.name}</p>
      </div>

      {/* Paid totals */}
      <div className="grid grid-cols-2 gap-md sm:grid-cols-4">
        <Stat label="Total pagado" value={formatPEN(detail.totalPaidCents)} />
        <Stat label="Compras pagadas" value={String(detail.paidPurchases)} />
        <Stat label="Oportunidades" value={String(detail.chances)} />
        <Stat label="Boletos activos" value={String(detail.activeTickets)} />
      </div>

      {/* The actual ticket numbers (R5) */}
      <Card elevation="tight" className="p-lg">
        <h2 className="font-body text-caption uppercase tracking-wide text-muted-label">
          Números de boleto
        </h2>
        {detail.ticketNumbers.length > 0 ? (
          <p className="mt-2 font-body text-body-md font-semibold text-ink-strong tabular-nums">
            {detail.ticketNumbers.join(", ")}
          </p>
        ) : (
          <p className="mt-2 font-body text-body-md text-muted">
            Sin boletos activos en este sorteo.
          </p>
        )}
      </Card>

      {/* Identity (masked) */}
      <Card elevation="tight" className="p-lg">
        <h2 className="font-body text-caption uppercase tracking-wide text-muted-label">
          Datos
        </h2>
        <dl className="mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2">
          <Field label="DNI" value={maskDni(detail.dni)} />
          <Field label="Teléfono" value={maskPhone(detail.phoneE164)} />
          <Field label="Correo" value={maskEmail(detail.emailNormalized)} />
          <Field label="Marketing" value={detail.marketingConsent ? "Sí" : "No"} />
          <Field
            label="Registrado"
            value={new Date(detail.createdAt).toLocaleDateString("es-PE")}
          />
        </dl>
        <p className="mt-3 font-body text-caption text-muted">
          Datos de contacto enmascarados. Para el contacto completo usa la
          exportación CSV auditada.
        </p>
      </Card>

      {/* Every purchase (R3/R4 per purchase) */}
      <Card elevation="tight" className="p-lg">
        <h2 className="font-body text-caption uppercase tracking-wide text-muted-label">
          Compras
        </h2>
        {detail.purchases.length > 0 ? (
          <div className="mt-2 overflow-x-auto">
            <table className="w-full border-collapse text-left">
              <thead>
                <tr className="border-b border-hairline">
                  <Th>Fecha</Th>
                  <Th>Estado</Th>
                  <Th>Monto</Th>
                  <Th>Oportunidades</Th>
                  <Th>Método</Th>
                  <Th>Cargo proveedor</Th>
                </tr>
              </thead>
              <tbody>
                {detail.purchases.map((pr) => (
                  <tr
                    key={pr.id}
                    className="border-b border-hairline last:border-0"
                  >
                    <Td>{new Date(pr.createdAt).toLocaleString("es-PE")}</Td>
                    <Td>{STATUS_LABEL[pr.status]}</Td>
                    <Td>
                      {formatPEN(pr.amountCents)}
                      {pr.feeCoverCents > 0
                        ? ` (+${formatPEN(pr.feeCoverCents)})`
                        : ""}
                    </Td>
                    <Td>{pr.chances.toLocaleString("es-PE")}</Td>
                    <Td>{pr.method ?? "—"}</Td>
                    <Td>{pr.providerChargeId ?? "—"}</Td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        ) : (
          <p className="mt-2 font-body text-body-md text-muted">
            Sin compras en este sorteo.
          </p>
        )}
      </Card>
    </div>
  );
}

function Stat({ label, value }: { label: string; value: string }) {
  return (
    <Card elevation="tight" className="p-md">
      <p className="font-body text-caption uppercase tracking-wide text-muted-label">
        {label}
      </p>
      <p className="mt-1 font-impact text-heading-md font-bold text-ink-strong tabular-nums">
        {value}
      </p>
    </Card>
  );
}

function Field({ 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="font-body text-body-md text-ink-strong">{value}</dd>
    </div>
  );
}

function Th({ children }: { children: React.ReactNode }) {
  return (
    <th
      scope="col"
      className="py-2 pr-4 font-body text-caption font-medium text-muted-label"
    >
      {children}
    </th>
  );
}
function Td({ children }: { children: React.ReactNode }) {
  return (
    <td className="py-2 pr-4 font-body text-body-md text-ink-strong">
      {children}
    </td>
  );
}
