// app/admin/configuracion/page.tsx
// Per-event configuration (admin.md section 2.6): pricing freeze, MININTER
// resolution reference, bases-published flag, draw config (winners per prize,
// multi-win), and the guarded status transitions (open / close) behind the
// publish gate. Admin role for all mutations (enforced in the server actions).

import * as React from "react";
import { redirect } from "next/navigation";
import { requireRole, getSession, roleSatisfies, AuthError } from "@/lib/auth";
import {
  listRaffles,
  getRaffle,
  getPrizeGateStats,
} from "@/app/admin/_lib/queries";
import {
  getRaffleConfig,
  evaluatePublishGate,
} from "@/app/admin/_lib/config";
import { RaffleSwitcher } from "@/components/admin/RaffleSwitcher";
import { ConfigPanel } from "@/components/admin/ConfigPanel";
import { CutoffEditor } from "@/components/admin/CutoffEditor";
import { Card, Badge } from "@/components/ui";
import { formatPEN } from "@/lib/money";

export const dynamic = "force-dynamic";

export default async function ConfigPage({
  searchParams,
}: {
  searchParams: Promise<{ raffle?: string }>;
}) {
  try {
    await requireRole("viewer");
  } catch (err) {
    if (err instanceof AuthError) redirect("/admin/login");
    throw err;
  }
  const session = await getSession();
  const isAdmin = session ? roleSatisfies(session.role, "admin") : false;

  const raffles = await listRaffles();
  if (raffles.length === 0) {
    return (
      <div>
        <h1 className="font-impact text-heading-lg font-bold text-ink-strong">
          Configuración
        </h1>
        <p className="mt-4 font-body text-body-lg text-muted">
          Aún no hay sorteos creados.
        </p>
      </div>
    );
  }

  const { raffle: raffleParam } = await searchParams;
  const selected = raffles.find((r) => r.id === raffleParam) ?? raffles[0];
  const full = await getRaffle(selected.id);
  const [config, gate] = await Promise.all([
    getRaffleConfig(selected.id),
    getPrizeGateStats(selected.id),
  ]);

  const blockers = evaluatePublishGate({
    config,
    prizeCount: gate.prizeCount,
    pricedPrizeCount: gate.pricedPrizeCount,
    basesUrlPresent: Boolean(full?.basesUrl),
  });

  return (
    <div className="flex flex-col gap-lg">
      <div className="flex flex-wrap items-center justify-between gap-md">
        <h1 className="font-impact text-heading-lg font-bold text-ink-strong">
          Configuración del sorteo
        </h1>
        <RaffleSwitcher
          raffles={raffles.map((r) => ({ id: r.id, name: r.name, status: r.status }))}
          selectedId={selected.id}
        />
      </div>

      <Card elevation="tight" className="p-lg">
        <div className="flex flex-wrap items-center gap-3">
          <h2 className="font-display text-heading-md font-bold text-ink-strong">
            {full?.name}
          </h2>
          <Badge tone={selected.status === "open" ? "blue" : "neutral"}>
            {selected.status}
          </Badge>
        </div>
        <dl className="mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2">
          <Meta term="Precio base por oportunidad" value={formatPEN(full?.basePriceCents ?? 0)} />
          <Meta term="Máximo de oportunidades por compra" value={String(full?.maxChancesPerPurchase ?? "")} />
          <Meta term="Apertura" value={full ? new Date(full.opensAt).toLocaleString("es-PE") : ""} />
          <Meta term="Cierre" value={full ? new Date(full.closesAt).toLocaleString("es-PE") : ""} />
          <Meta term="Sorteo" value={full ? new Date(full.drawAt).toLocaleString("es-PE") : ""} />
          <Meta term="PDF de bases" value={full?.basesUrl ? "cargado" : "pendiente"} />
        </dl>
        <p className="mt-3 font-body text-caption text-muted">
          El precio base, los tiers y las ventanas son configuración por evento.
          El precio debe congelarse antes de presentar las bases al MININTER.
        </p>
      </Card>

      {!isAdmin ? (
        <p className="rounded-md border border-hairline px-4 py-3 font-body text-body-md text-muted">
          Solo un administrador puede editar la configuración, congelar el precio
          y abrir o cerrar el sorteo.
        </p>
      ) : (
        <>
          {full ? (
            <CutoffEditor
              raffleId={selected.id}
              closesAtLocal={toPeruLocalInput(new Date(full.closesAt))}
              drawAtLocal={toPeruLocalInput(new Date(full.drawAt))}
              closesAtLabel={peruLabel(new Date(full.closesAt))}
              drawAtLabel={peruLabel(new Date(full.drawAt))}
              locked={!(selected.status === "draft" || selected.status === "open")}
              lockedReason={`el sorteo está en estado "${selected.status}" y el pool ya está congelado.`}
            />
          ) : null}
          <ConfigPanel
            raffleId={selected.id}
            status={selected.status}
            config={{
              mininterResolutionRef: config.mininterResolutionRef,
              pricingFrozenAt: config.pricingFrozenAt,
              basesPublished: config.basesPublished,
              winnersPerPrize: config.winnersPerPrize,
              allowMultiWin: config.allowMultiWin,
              exclusionNote: config.exclusionNote,
            }}
            blockers={blockers}
          />
        </>
      )}
    </div>
  );
}

/** Format a Date as "YYYY-MM-DDTHH:mm" in Peru time, for a datetime-local input. */
function toPeruLocalInput(d: Date): string {
  const parts = new Intl.DateTimeFormat("en-CA", {
    timeZone: "America/Lima",
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
    hour12: false,
  }).formatToParts(d);
  const g = (t: string) => parts.find((p) => p.type === t)?.value ?? "00";
  return `${g("year")}-${g("month")}-${g("day")}T${g("hour")}:${g("minute")}`;
}

/** Human-readable Peru-time label for the locked (read-only) view. */
function peruLabel(d: Date): string {
  return d.toLocaleString("es-PE", {
    timeZone: "America/Lima",
    dateStyle: "medium",
    timeStyle: "short",
  });
}

function Meta({ term, value }: { term: string; value: string }) {
  return (
    <div>
      <dt className="font-body text-caption text-muted-label">{term}</dt>
      <dd className="font-body text-body-md text-ink-strong">{value}</dd>
    </div>
  );
}
