// components/admin/TransactionTable.tsx
// Client transaction table with an inline refund control (operator+). The refund
// posts to /api/admin/purchases/[id]/refund (which calls the provider, voids
// tickets, and writes the audit log). Status is shown as text + a tone class
// (never color-only). Refund requires picking a reason.

"use client";

import * as React from "react";
import { useRouter } from "next/navigation";
import { Badge } from "@/components/ui";
import { formatPEN } from "@/lib/money";
import { logTransactionUnmaskAction } from "@/app/admin/_lib/actions";
import type { PurchaseStatus } from "@/lib/types";

export interface TransactionTableRow {
  id: string;
  createdAt: string;
  paidAt: string | null;
  participantName: string;
  /** Masked contact, always present (shown by default). */
  phoneMasked: string;
  emailMasked: string;
  /** Raw contact, sent to operator+ only; revealed after a logged unmask. */
  phoneRaw: string | null;
  emailRaw: string | null;
  status: PurchaseStatus;
  chances: number;
  amountCents: number;
  feeCoverCents: number;
  method: string | null;
  providerName: string;
  providerChargeId: string | null;
  providerStatus: string | null;
  channel: string | null;
}

const REASONS = [
  { value: "duplicate_charge", label: "Cargo duplicado" },
  { value: "proven_error", label: "Error comprobado" },
  { value: "other", label: "Otro (requiere nota)" },
] as const;

export function TransactionTable({
  rows,
  canRefund,
  canUnmask = false,
}: {
  rows: TransactionTableRow[];
  canRefund: boolean;
  canUnmask?: boolean;
}) {
  const router = useRouter();
  const [openRefund, setOpenRefund] = React.useState<string | null>(null);
  const [reason, setReason] = React.useState<string>("duplicate_charge");
  const [note, setNote] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [msg, setMsg] = React.useState<{ id: string; text: string; ok: boolean } | null>(null);
  const [revealed, setRevealed] = React.useState<Record<string, boolean>>({});
  const [revealing, setRevealing] = React.useState<string | null>(null);

  async function revealContact(id: string) {
    if (!canUnmask) return;
    setRevealing(id);
    // Write the audit row BEFORE swapping to the raw contact.
    const res = await logTransactionUnmaskAction(id);
    setRevealing(null);
    if (res.ok) {
      setRevealed((prev) => ({ ...prev, [id]: true }));
    }
  }

  async function submitRefund(id: string) {
    setBusy(true);
    setMsg(null);
    try {
      const res = await fetch(`/api/admin/purchases/${id}/refund`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ reason, note: note.trim() || undefined }),
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok) {
        setMsg({ id, text: "Reembolso procesado y oportunidades anuladas.", ok: true });
        setOpenRefund(null);
        setNote("");
        router.refresh();
      } else {
        setMsg({
          id,
          text: data?.error?.message ?? "No se pudo procesar el reembolso.",
          ok: false,
        });
      }
    } catch {
      setMsg({ id, text: "Error de red al procesar el reembolso.", ok: false });
    } finally {
      setBusy(false);
    }
  }

  if (rows.length === 0) {
    return (
      <p className="font-body text-body-md text-muted">
        No se encontraron transacciones con esos filtros.
      </p>
    );
  }

  return (
    <div className="overflow-x-auto">
      <table className="w-full border-collapse text-left">
        <caption className="sr-only">Transacciones del sorteo</caption>
        <thead>
          <tr className="border-b border-hairline">
            <Th>Creada</Th>
            <Th>Participante</Th>
            <Th>Contacto</Th>
            <Th>Estado</Th>
            <Th>Oportunidades</Th>
            <Th>Monto</Th>
            <Th>Medio</Th>
            <Th>Cargo proveedor</Th>
            <Th>Canal</Th>
            {canRefund ? <Th>Acción</Th> : null}
          </tr>
        </thead>
        <tbody>
          {rows.map((r) => (
            <React.Fragment key={r.id}>
              <tr className="border-b border-hairline last:border-0">
                <Td>{new Date(r.createdAt).toLocaleString("es-PE")}</Td>
                <Td>{r.participantName}</Td>
                <Td>
                  {(() => {
                    const isRevealed = canUnmask && revealed[r.id] && r.phoneRaw != null;
                    const phone = isRevealed && r.phoneRaw ? r.phoneRaw : r.phoneMasked;
                    const email =
                      isRevealed && r.emailRaw ? r.emailRaw : r.emailMasked;
                    return (
                      <div className="flex flex-col gap-1">
                        <span>{phone}</span>
                        <span className="text-caption text-muted">{email}</span>
                        {canUnmask ? (
                          isRevealed ? (
                            <span className="font-body text-micro text-muted">
                              Revelado (registrado)
                            </span>
                          ) : (
                            <button
                              type="button"
                              onClick={() => revealContact(r.id)}
                              disabled={revealing === r.id}
                              className="self-start font-body text-micro font-medium text-steelblue underline hover:no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-steelblue disabled:opacity-50"
                            >
                              {revealing === r.id ? "Registrando..." : "Revelar datos"}
                            </button>
                          )
                        ) : null}
                      </div>
                    );
                  })()}
                </Td>
                <Td>
                  <Badge tone={statusTone(r.status)}>{statusLabel(r.status)}</Badge>
                </Td>
                <Td>{r.chances}</Td>
                <Td>
                  {formatPEN(r.amountCents)}
                  {r.feeCoverCents > 0 ? (
                    <span className="block text-micro text-muted">
                      +{formatPEN(r.feeCoverCents)} comisión
                    </span>
                  ) : null}
                </Td>
                <Td>{railLabel(r.method, r.providerName)}</Td>
                <Td>
                  <span className="break-all text-caption">
                    {r.providerChargeId ?? "sin cargo"}
                  </span>
                  {r.providerStatus ? (
                    <span className="block text-micro text-muted">
                      {r.providerStatus}
                    </span>
                  ) : null}
                </Td>
                <Td>{r.channel ?? "directo"}</Td>
                {canRefund ? (
                  <Td>
                    {r.status === "paid" ? (
                      <button
                        type="button"
                        onClick={() =>
                          setOpenRefund(openRefund === r.id ? null : r.id)
                        }
                        className="min-h-11 rounded-md border border-primary px-3 font-body text-caption font-medium text-primary hover:bg-primary hover:text-on-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
                        aria-expanded={openRefund === r.id}
                      >
                        Reembolsar
                      </button>
                    ) : (
                      <span className="text-caption text-muted">n/a</span>
                    )}
                  </Td>
                ) : null}
              </tr>
              {canRefund && openRefund === r.id ? (
                <tr className="border-b border-hairline bg-canvas">
                  <td colSpan={canRefund ? 10 : 9} className="p-4">
                    <fieldset className="flex flex-wrap items-end gap-3">
                      <legend className="mb-2 font-body text-body-md font-bold text-ink-strong">
                        Reembolsar compra
                      </legend>
                      <div className="flex flex-col gap-1.5">
                        <label
                          htmlFor={`reason-${r.id}`}
                          className="font-body text-caption font-medium text-ink-strong"
                        >
                          Motivo
                        </label>
                        <select
                          id={`reason-${r.id}`}
                          value={reason}
                          onChange={(e) => setReason(e.target.value)}
                          className="min-h-11 rounded-md border border-track bg-canvas px-3 font-body text-body-md text-ink-strong"
                        >
                          {REASONS.map((rr) => (
                            <option key={rr.value} value={rr.value}>
                              {rr.label}
                            </option>
                          ))}
                        </select>
                      </div>
                      <div className="flex flex-col gap-1.5">
                        <label
                          htmlFor={`note-${r.id}`}
                          className="font-body text-caption font-medium text-ink-strong"
                        >
                          Nota {reason === "other" ? "(obligatoria)" : "(opcional)"}
                        </label>
                        <input
                          id={`note-${r.id}`}
                          value={note}
                          onChange={(e) => setNote(e.target.value)}
                          className="min-h-11 w-72 rounded-md border border-track bg-canvas px-4 font-body text-body-md text-ink-strong"
                        />
                      </div>
                      <button
                        type="button"
                        disabled={busy || (reason === "other" && !note.trim())}
                        onClick={() => submitRefund(r.id)}
                        className="min-h-11 rounded-md bg-primary px-5 font-body text-body-md font-bold text-on-primary hover:bg-primary-soft focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-steelblue disabled:opacity-50"
                      >
                        {busy ? "Procesando..." : "Confirmar reembolso"}
                      </button>
                    </fieldset>
                  </td>
                </tr>
              ) : null}
              {msg && msg.id === r.id ? (
                <tr>
                  <td colSpan={canRefund ? 10 : 9} className="px-4 pb-3">
                    <p
                      role="alert"
                      className={
                        "font-body text-caption " +
                        (msg.ok ? "text-steelblue" : "text-primary")
                      }
                    >
                      {msg.text}
                    </p>
                  </td>
                </tr>
              ) : null}
            </React.Fragment>
          ))}
        </tbody>
      </table>
    </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 align-top font-body text-body-md text-ink-strong">
      {children}
    </td>
  );
}

function statusTone(s: PurchaseStatus): "primary" | "neutral" | "blue" {
  if (s === "paid") return "blue";
  if (s === "refunded" || s === "failed") return "primary";
  return "neutral";
}
function statusLabel(s: PurchaseStatus): string {
  switch (s) {
    case "paid":
      return "Pagada";
    case "pending":
      return "Pendiente";
    case "failed":
      return "Fallida";
    case "expired":
      return "Expirada";
    case "refunded":
      return "Reembolsada";
    default:
      return s;
  }
}
function railLabel(method: string | null, providerName: string): string {
  if (providerName === "manual") return "Manual";
  switch (method) {
    case "yape":
      return "Yape";
    case "card":
      return "Tarjeta";
    case "pago_efectivo":
      return "PagoEfectivo";
    default:
      return "Otro";
  }
}
