"use client";

import { useCallback, useEffect, useState } from "react";
import { useCan } from "@/lib/abilities";
import {
  formatDateTime,
  NOTIFICATION_STATUS_LABELS,
  NOTIFICATION_TYPE_LABELS,
} from "@/lib/labels";
import { NotificationLogPanel } from "@/components/NotificationLogPanel";
import { AdminEmailsSetting } from "@/components/AdminEmailsSetting";
import {
  getNotificationStats,
  runAccountStatus,
  runAllNotifications,
  runOutstandingPayments,
  runPaymentConfirmation,
  runTrustConfirmation,
  SERVICIOS_LOG_SCOPE,
} from "@/lib/api";
import type {
  NotificationFlags,
  NotificationJobResponse,
  NotificationRunAllResponse,
  NotificationStats,
} from "@/lib/api";

/**
 * Mass email notifications — the "Servicios" half of /notificaciones. Manual
 * triggers for the four jobs plus a paged log browser. Gated on
 * `notification:send`; a STAFF viewer sees the read-only log table but not the
 * trigger buttons.
 *
 * The send flags come from the shell above the tabs — they are shared with the
 * pólizas half — so this component only consumes them.
 */

type JobKind = "outstanding" | "payment" | "account" | "trust";

interface JobDef {
  kind: JobKind;
  title: string;
  endpoint: string;
  description: string;
  servicio: "Clientes" | "Fideicomiso";
  flagsHint?: string;
}

const JOBS: JobDef[] = [
  {
    kind: "outstanding",
    title: "Pagos pendientes",
    endpoint: "sendOutstandingPaymentAlerts",
    servicio: "Clientes",
    description:
      "Clientes con al menos un movimiento marcado como pendiente (outstanding). Equivale a la columna NOPAGO=1 del antiguo datosfreak.",
  },
  {
    kind: "payment",
    title: "Confirmación de pago",
    endpoint: "sendPaymentConfirmation",
    servicio: "Clientes",
    description:
      "Clientes con un crédito (abono) en las últimas 24 horas. Un correo por cliente con el pago más reciente.",
  },
  {
    kind: "account",
    title: "Estado de cuenta",
    endpoint: "sendAccountStatus",
    servicio: "Clientes",
    description:
      "Alerta amarilla (DEBAJO DEL TIPO) los miércoles y roja (EN ROJO) lunes/miércoles/viernes. El flag ignoreDayRestriction salta los gates.",
    flagsHint: "Solo este job respeta ignoreDayRestriction y useEmailLimit.",
  },
  {
    kind: "trust",
    title: "Confirmación fideicomiso",
    endpoint: "sendConfirmTrustPayment",
    servicio: "Fideicomiso",
    description:
      "Clientes con TrustAccount que recibieron un crédito en el dominio TRUST en las últimas 24 horas.",
  },
];

/** Job title by kind — used by the run-all summary, which only carries kinds. */
const JOB_TITLES: Record<JobKind, string> = JOBS.reduce(
  (acc, j) => ({ ...acc, [j.kind]: j.title }),
  {} as Record<JobKind, string>,
);

export function NotificacionesServicios({ flags }: { flags: NotificationFlags }) {
  const allowed = useCan("notification:send");

  const [stats, setStats] = useState<NotificationStats | null>(null);
  /** Raised after every run so the shared log panel reloads. */
  const [logToken, setLogToken] = useState(0);
  const [busy, setBusy] = useState<JobKind | "all" | null>(null);
  const [lastResult, setLastResult] = useState<
    NotificationJobResponse | NotificationRunAllResponse | null
  >(null);
  const [error, setError] = useState<string | null>(null);

  const refresh = useCallback(async () => {
    try {
      setStats(await getNotificationStats(SERVICIOS_LOG_SCOPE));
      setLogToken((t) => t + 1);
      setError(null);
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    }
  }, []);

  useEffect(() => {
    void refresh();
  }, [refresh]);

  const run = useCallback(
    async (job: JobDef) => {
      if (!allowed) return;
      setBusy(job.kind);
      setError(null);
      try {
        let res: NotificationJobResponse;
        if (job.kind === "outstanding") res = await runOutstandingPayments(flags);
        else if (job.kind === "payment") res = await runPaymentConfirmation(flags);
        else if (job.kind === "account") res = await runAccountStatus(flags);
        else res = await runTrustConfirmation(flags);
        setLastResult(res);
        await refresh();
      } catch (e) {
        setError(e instanceof Error ? e.message : String(e));
      } finally {
        setBusy(null);
      }
    },
    [allowed, flags, refresh],
  );

  // "Ejecutar todos" — one POST, the API runs the four jobs sequentially with
  // the same flags. Confirmation only matters when debug is off, since that
  // is the case where real customers receive mail.
  const runAll = useCallback(async () => {
    if (!allowed) return;
    if (!flags.debug) {
      const ok = window.confirm(
        "debug está desactivado: los cuatro envíos irán a los correos reales de los clientes. ¿Ejecutar todos?",
      );
      if (!ok) return;
    }
    setBusy("all");
    setError(null);
    try {
      const res = await runAllNotifications(flags);
      setLastResult(res);
      await refresh();
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setBusy(null);
    }
  }, [allowed, flags, refresh]);

  return (
    <div style={{ display: "grid", gap: 20 }}>
      <p className="muted" style={{ maxWidth: 760, margin: 0 }}>
        Disparo manual de los cuatro envíos equivalentes a los scripts PHP de{" "}
        <code>email.notifications/</code>. Cada ejecución registra todas las filas
        (enviado, fallido, omitido) en <code>email_notification_log</code>.
      </p>

      {!allowed && (
        <div className="empty-inline">
          Tu rol no incluye <code>notification:send</code>. Solo puedes ver el
          registro. Para disparar envíos pide a un MANAGER/ADMIN.
        </div>
      )}

      {error && <div className="state-box state-error">{error}</div>}

      <section className="card" style={{ padding: 20 }}>
        <h2 className="section-title">Ejecutar ahora</h2>
        <div
          style={{
            display: "flex",
            alignItems: "center",
            gap: 12,
            flexWrap: "wrap",
            marginTop: 12,
          }}
        >
          <button
            type="button"
            className="btn btn-primary btn-sm"
            disabled={!allowed || busy !== null}
            onClick={() => void runAll()}
          >
            {busy === "all" ? "Ejecutando todos…" : "Ejecutar todos"}
          </button>
          <span className="muted small">
            Dispara los cuatro envíos en orden (pagos pendientes, confirmación
            de pago, estado de cuenta, fideicomiso) con los flags de arriba. Si
            uno falla, los demás continúan. Es lo mismo que ejecuta la corrida
            programada de Servicios.
          </span>
        </div>
      </section>

      <section
        style={{
          display: "grid",
          gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))",
          gap: 12,
        }}
      >
        {JOBS.map((j) => (
          <article
            key={j.kind}
            className="card"
            style={{ padding: 18, display: "grid", gap: 8, alignContent: "start" }}
          >
            <header
              style={{
                display: "flex",
                justifyContent: "space-between",
                alignItems: "center",
                gap: 8,
              }}
            >
              <strong>{j.title}</strong>
              <span
                className={
                  j.servicio === "Fideicomiso"
                    ? "badge badge-fideicomiso"
                    : "badge badge-servicios"
                }
              >
                <span className="dot" />
                {j.servicio}
              </span>
            </header>
            <p className="muted small" style={{ margin: 0 }}>
              {j.description}
            </p>
            {j.flagsHint && (
              <p className="section-note" style={{ margin: 0, fontStyle: "italic" }}>
                {j.flagsHint}
              </p>
            )}
            <div className="row-actions" style={{ marginTop: 4 }}>
              <button
                type="button"
                className="btn btn-primary btn-sm"
                disabled={!allowed || busy !== null}
                onClick={() => void run(j)}
              >
                {busy === j.kind ? "Ejecutando…" : "Ejecutar"}
              </button>
            </div>
          </article>
        ))}
      </section>

      {stats && (
        <section className="card" style={{ padding: 20 }}>
          <h2 className="section-title">Estado del transporte</h2>
          <ul className="small" style={{ marginTop: 10, marginBottom: 0, paddingLeft: 18 }}>
            <li>
              SES configurado:{" "}
              <strong
                style={{
                  color: stats.transport.available
                    ? "var(--positive)"
                    : "var(--negative)",
                }}
              >
                {stats.transport.available ? "sí" : "no"}
              </strong>
              {stats.transport.devFallback && " (fallback dev: stdout)"}
            </li>
            <li>
              Último envío registrado:{" "}
              {stats.lastRun
                ? `${NOTIFICATION_TYPE_LABELS[stats.lastRun.notificationType]} — ${formatDateTime(stats.lastRun.sendDate)}`
                : "—"}
            </li>
            <li>
              Totales:{" "}
              {stats.byStatus.map((s) => (
                <span key={s.status} style={{ marginRight: 12 }}>
                  {NOTIFICATION_STATUS_LABELS[s.status]}: {s._count._all}
                </span>
              ))}
            </li>
          </ul>
        </section>
      )}

      <AdminEmailsSetting />

      {lastResult && (
        <section className="card" style={{ padding: 20 }}>
          <h2 className="section-title">Última respuesta</h2>
          {lastResult.type === "RUN_ALL" && (
            <ul
              className="small"
              style={{ marginTop: 10, marginBottom: 0, paddingLeft: 18 }}
            >
              <li>
                Totales: enviados {lastResult.sent} · omitidos{" "}
                {lastResult.skipped} · fallidos {lastResult.failed}
                {lastResult.errors > 0 && ` · jobs con error ${lastResult.errors}`}
              </li>
              {lastResult.jobs.map((j) => (
                <li key={j.kind}>
                  {JOB_TITLES[j.kind]}:{" "}
                  {j.ok && j.result ? (
                    <>
                      enviados {j.result.sent} · omitidos {j.result.skipped} ·
                      fallidos {j.result.failed}
                    </>
                  ) : (
                    <span style={{ color: "var(--negative)" }}>
                      error — {j.error}
                    </span>
                  )}
                </li>
              ))}
            </ul>
          )}
          <pre
            className="mono"
            style={{
              margin: "10px 0 0",
              fontSize: 12,
              overflow: "auto",
              background: "var(--surface-2)",
              border: "1px solid var(--line)",
              borderRadius: "var(--radius-sm)",
              padding: 12,
            }}
          >
            {JSON.stringify(lastResult, null, 2)}
          </pre>
        </section>
      )}

      <NotificationLogPanel
        servicio={SERVICIOS_LOG_SCOPE}
        reloadToken={logToken}
      />
    </div>
  );
}
