// @File: src/components/admin/ModuleSyncPanel.tsx
// @Desc: Reusable "Fetch Data Toggle" panel for every reseller module
//        (UptimeRobot, Bizmail360, WhatsApp, …). Drop it into any admin
//        page with: <ModuleSyncPanel moduleName="uptimerobot" />
//
//        Features:
//        - Three toggle cards: Fetch Clients / Accounts / Domains
//        - Green (enabled), Gray (disabled), Red (last sync failed)
//        - Last sync time, total fetched count, last error
//        - Per-card "Fetch now" button + a global "Fetch All Now"
//        - "Run Diagnostics" + "View Raw API Log" buttons
import { useCallback, useEffect, useMemo, useState } from "react";
import {
  AlertTriangle,
  Check,
  CheckCircle2,
  Cloud,
  Database,
  Globe,
  Loader2,
  PlayCircle,
  RefreshCw,
  ScrollText,
  Stethoscope,
  Users,
  X,
  XCircle,
} from "lucide-react";
import { toast } from "sonner";
import {
  fetchAllNow,
  fetchNow,
  getModule,
  listLogs,
  runDiagnostics,
  updateToggles,
  type ModuleDiagnosticsResult,
  type ModuleSyncLogItem,
  type ModuleSyncSettings,
  type SyncStatus,
  type SyncType,
} from "@/lib/moduleSyncApi";

interface Props {
  moduleName: string;
  /** Optional title above the three cards. Defaults to "Data Fetch Controls". */
  title?: string;
}

type ToggleField =
  | "fetch_clients_enabled"
  | "fetch_accounts_enabled"
  | "fetch_domains_enabled";

interface CardDef {
  syncType: SyncType;
  toggleField: ToggleField;
  statusField: "clients_sync_status" | "accounts_sync_status" | "domains_sync_status";
  lastField: "last_clients_sync" | "last_accounts_sync" | "last_domains_sync";
  countField: "clients_count" | "accounts_count" | "domains_count";
  title: string;
  description: string;
  Icon: React.ComponentType<{ className?: string }>;
}

const CARDS: CardDef[] = [
  {
    syncType: "clients",
    toggleField: "fetch_clients_enabled",
    statusField: "clients_sync_status",
    lastField: "last_clients_sync",
    countField: "clients_count",
    title: "Fetch Clients",
    description: "Fetch WHMCS clients linked to this module.",
    Icon: Users,
  },
  {
    syncType: "accounts",
    toggleField: "fetch_accounts_enabled",
    statusField: "accounts_sync_status",
    lastField: "last_accounts_sync",
    countField: "accounts_count",
    title: "Fetch Accounts",
    description: "Fetch module accounts (monitors, mailboxes, devices, …).",
    Icon: Cloud,
  },
  {
    syncType: "domains",
    toggleField: "fetch_domains_enabled",
    statusField: "domains_sync_status",
    lastField: "last_domains_sync",
    countField: "domains_count",
    title: "Fetch Domains",
    description: "Fetch WHMCS domains and match them with module accounts.",
    Icon: Globe,
  },
];

function formatDate(dt: string | null): string {
  if (!dt) return "Never";
  try {
    return new Date(dt).toLocaleString();
  } catch {
    return dt;
  }
}

function statusBadge(status: SyncStatus): { text: string; className: string; Icon: React.ComponentType<{ className?: string }> } {
  switch (status) {
    case "ok":
      return { text: "Synced", className: "bg-emerald-100 text-emerald-700 border-emerald-200", Icon: CheckCircle2 };
    case "failed":
      return { text: "Failed", className: "bg-red-100 text-red-700 border-red-200", Icon: XCircle };
    case "skipped":
      return { text: "Skipped", className: "bg-slate-100 text-slate-600 border-slate-200", Icon: AlertTriangle };
    default:
      return { text: "Never", className: "bg-slate-100 text-slate-500 border-slate-200", Icon: Database };
  }
}

function toggleDot(enabled: boolean, status: SyncStatus): string {
  if (status === "failed") return "bg-red-500";
  return enabled ? "bg-emerald-500" : "bg-slate-400";
}

export default function ModuleSyncPanel({ moduleName, title }: Props) {
  const [data, setData] = useState<ModuleSyncSettings | null>(null);
  const [loading, setLoading] = useState(true);
  const [busy, setBusy] = useState<string | null>(null); // which action is running
  const [diagnostics, setDiag] = useState<ModuleDiagnosticsResult | null>(null);
  const [logsOpen, setLogsOpen] = useState(false);
  const [logs, setLogs] = useState<ModuleSyncLogItem[]>([]);
  const [logsLoading, setLogsLoading] = useState(false);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const s = await getModule(moduleName);
      setData(s);
    } catch (e) {
      toast.error(`Load failed: ${e instanceof Error ? e.message : e}`);
    } finally {
      setLoading(false);
    }
  }, [moduleName]);

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

  const onToggle = async (field: ToggleField, next: boolean) => {
    if (!data) return;
    setBusy(`toggle:${field}`);
    try {
      const updated = await updateToggles(moduleName, { [field]: next });
      setData(updated);
      toast.success(`${field.replace(/_/g, " ")} ${next ? "enabled" : "disabled"}.`);
    } catch (e) {
      toast.error(`Update failed: ${e instanceof Error ? e.message : e}`);
    } finally {
      setBusy(null);
    }
  };

  const onFetchOne = async (syncType: SyncType) => {
    setBusy(`fetch:${syncType}`);
    try {
      const r = await fetchNow(moduleName, syncType);
      if (r.status === "ok") {
        toast.success(`Fetched ${r.items_fetched} ${syncType}.`);
      } else {
        toast.error(`${syncType} fetch failed: ${r.error_message ?? "Unknown error"}`);
      }
      await load();
    } catch (e) {
      toast.error(`Fetch failed: ${e instanceof Error ? e.message : e}`);
    } finally {
      setBusy(null);
    }
  };

  const onFetchAll = async () => {
    setBusy("fetch:all");
    try {
      const r = await fetchAllNow(moduleName);
      const fails = r.runs.filter((x) => x.status === "failed");
      if (fails.length === 0) toast.success("All three syncs completed.");
      else toast.error(`${fails.length} sync step(s) failed — see panel for details.`);
      await load();
    } catch (e) {
      toast.error(`Fetch all failed: ${e instanceof Error ? e.message : e}`);
    } finally {
      setBusy(null);
    }
  };

  const onDiagnostics = async () => {
    setBusy("diagnostics");
    try {
      const r = await runDiagnostics(moduleName);
      setDiag(r);
      if (r.ok) toast.success("Diagnostics passed.");
      else toast.error("Some diagnostics failed — see panel below.");
      await load();
    } catch (e) {
      toast.error(`Diagnostics failed: ${e instanceof Error ? e.message : e}`);
    } finally {
      setBusy(null);
    }
  };

  const onOpenLogs = async () => {
    setLogsOpen(true);
    setLogsLoading(true);
    try {
      const res = await listLogs({ module_name: moduleName, limit: 50 });
      setLogs(res.items);
    } catch (e) {
      toast.error(`Load logs failed: ${e instanceof Error ? e.message : e}`);
    } finally {
      setLogsLoading(false);
    }
  };

  const domainSubLine = useMemo(() => {
    if (!data) return "";
    return `${data.domains_linked_count} linked / ${data.domains_unlinked_count} unlinked`;
  }, [data]);

  if (loading) {
    return (
      <div className="flex items-center gap-2 py-6 text-slate-500">
        <Loader2 className="h-4 w-4 animate-spin" /> Loading sync settings…
      </div>
    );
  }

  if (!data) {
    return (
      <div className="rounded-md border border-amber-200 bg-amber-50 p-4 text-sm text-amber-700">
        No sync settings available for module <span className="font-mono">{moduleName}</span>.
      </div>
    );
  }

  return (
    <section className="space-y-4">
      <div className="flex flex-wrap items-center justify-between gap-3">
        <div>
          <h3 className="text-lg font-semibold text-slate-800">{title ?? "Data Fetch Controls"}</h3>
          <p className="text-sm text-slate-500">
            Toggle automatic data fetching for <span className="font-medium">{data.module_label}</span>. Manual runs ignore the toggle state.
          </p>
        </div>
        <div className="flex flex-wrap gap-2">
          <button
            type="button"
            onClick={onFetchAll}
            disabled={busy !== null}
            className="inline-flex items-center gap-2 rounded-md bg-indigo-600 px-3 py-2 text-sm font-medium text-white hover:bg-indigo-700 disabled:opacity-50"
          >
            {busy === "fetch:all" ? <Loader2 className="h-4 w-4 animate-spin" /> : <PlayCircle className="h-4 w-4" />}
            Fetch All Now
          </button>
          <button
            type="button"
            onClick={onDiagnostics}
            disabled={busy !== null}
            className="inline-flex items-center gap-2 rounded-md border border-slate-300 bg-white px-3 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50 disabled:opacity-50"
          >
            {busy === "diagnostics" ? <Loader2 className="h-4 w-4 animate-spin" /> : <Stethoscope className="h-4 w-4" />}
            Run Diagnostics
          </button>
          <button
            type="button"
            onClick={onOpenLogs}
            className="inline-flex items-center gap-2 rounded-md border border-slate-300 bg-white px-3 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50"
          >
            <ScrollText className="h-4 w-4" />
            View Raw API Log
          </button>
          <button
            type="button"
            onClick={() => void load()}
            className="inline-flex items-center gap-2 rounded-md border border-slate-300 bg-white px-2 py-2 text-sm font-medium text-slate-600 hover:bg-slate-50"
            title="Refresh"
          >
            <RefreshCw className="h-4 w-4" />
          </button>
        </div>
      </div>

      {data.last_error ? (
        <div className="rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-700">
          <span className="font-semibold">Last error:</span> {data.last_error}
        </div>
      ) : null}

      <div className="grid gap-4 md:grid-cols-3">
        {CARDS.map((card) => {
          const enabled = Boolean(data[card.toggleField]);
          const status = data[card.statusField] as SyncStatus;
          const sb = statusBadge(status);
          const count = data[card.countField] as number;
          const last = data[card.lastField] as string | null;
          const toggleBusy = busy === `toggle:${card.toggleField}`;
          const fetchBusy = busy === `fetch:${card.syncType}`;
          return (
            <div
              key={card.syncType}
              className="rounded-lg border border-slate-200 bg-white p-4 shadow-sm"
            >
              <div className="flex items-start justify-between">
                <div className="flex items-center gap-2">
                  <span className={`inline-block h-2.5 w-2.5 rounded-full ${toggleDot(enabled, status)}`} />
                  <card.Icon className="h-5 w-5 text-slate-500" />
                  <h4 className="text-sm font-semibold text-slate-800">{card.title}</h4>
                </div>
                <button
                  type="button"
                  onClick={() => void onToggle(card.toggleField, !enabled)}
                  disabled={toggleBusy}
                  className={`relative inline-flex h-6 w-11 items-center rounded-full transition ${enabled ? "bg-emerald-500" : "bg-slate-300"} disabled:opacity-50`}
                  aria-pressed={enabled}
                  aria-label={`Toggle ${card.title}`}
                >
                  <span
                    className={`inline-block h-5 w-5 transform rounded-full bg-white shadow transition ${enabled ? "translate-x-5" : "translate-x-1"}`}
                  />
                </button>
              </div>
              <p className="mt-1 text-xs text-slate-500">{card.description}</p>

              <div className="mt-3 space-y-1 text-sm">
                <div className="flex items-center justify-between">
                  <span className="text-slate-500">Status</span>
                  <span className={`inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs ${sb.className}`}>
                    <sb.Icon className="h-3 w-3" />
                    {sb.text}
                  </span>
                </div>
                <div className="flex items-center justify-between">
                  <span className="text-slate-500">Last sync</span>
                  <span className="text-slate-700">{formatDate(last)}</span>
                </div>
                <div className="flex items-center justify-between">
                  <span className="text-slate-500">Total fetched</span>
                  <span className="font-semibold text-slate-800">{count}</span>
                </div>
                {card.syncType === "domains" ? (
                  <div className="flex items-center justify-between">
                    <span className="text-slate-500">Match</span>
                    <span className="text-slate-700">{domainSubLine}</span>
                  </div>
                ) : null}
              </div>

              <button
                type="button"
                onClick={() => void onFetchOne(card.syncType)}
                disabled={busy !== null}
                className="mt-3 inline-flex w-full items-center justify-center gap-2 rounded-md border border-indigo-200 bg-indigo-50 px-3 py-2 text-sm font-medium text-indigo-700 hover:bg-indigo-100 disabled:opacity-50"
              >
                {fetchBusy ? <Loader2 className="h-4 w-4 animate-spin" /> : <RefreshCw className="h-4 w-4" />}
                Fetch {card.title.replace("Fetch ", "")} Now
              </button>
            </div>
          );
        })}
      </div>

      {diagnostics ? (
        <div className="rounded-lg border border-slate-200 bg-white p-4 shadow-sm">
          <div className="flex items-center justify-between">
            <h4 className="text-sm font-semibold text-slate-800">Diagnostics</h4>
            <span
              className={`inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs ${diagnostics.ok ? "bg-emerald-100 text-emerald-700 border-emerald-200" : "bg-red-100 text-red-700 border-red-200"}`}
            >
              {diagnostics.ok ? <CheckCircle2 className="h-3 w-3" /> : <XCircle className="h-3 w-3" />}
              {diagnostics.message ?? (diagnostics.ok ? "OK" : "Failed")}
            </span>
          </div>
          <ul className="mt-2 divide-y divide-slate-100 text-sm">
            {diagnostics.steps.map((s) => (
              <li key={s.step} className="flex items-center justify-between py-2">
                <span className="font-mono text-xs text-slate-600">{s.step}</span>
                <span className="flex items-center gap-2">
                  {s.ok ? <Check className="h-4 w-4 text-emerald-600" /> : <X className="h-4 w-4 text-red-600" />}
                  <span className={s.ok ? "text-emerald-700" : "text-red-700"}>{s.detail ?? (s.ok ? "ok" : "failed")}</span>
                </span>
              </li>
            ))}
          </ul>
        </div>
      ) : null}

      {logsOpen ? (
        <div className="fixed inset-0 z-40 flex items-center justify-center bg-black/40 p-4">
          <div className="max-h-[80vh] w-full max-w-3xl overflow-hidden rounded-lg bg-white shadow-xl">
            <div className="flex items-center justify-between border-b border-slate-200 px-4 py-3">
              <h4 className="text-sm font-semibold text-slate-800">
                Sync Logs — {data.module_label}
              </h4>
              <button
                type="button"
                onClick={() => setLogsOpen(false)}
                className="rounded p-1 text-slate-500 hover:bg-slate-100"
                aria-label="Close"
              >
                <X className="h-4 w-4" />
              </button>
            </div>
            <div className="max-h-[65vh] overflow-auto p-4">
              {logsLoading ? (
                <div className="flex items-center gap-2 text-slate-500">
                  <Loader2 className="h-4 w-4 animate-spin" /> Loading…
                </div>
              ) : logs.length === 0 ? (
                <p className="text-sm text-slate-500">No sync log entries yet.</p>
              ) : (
                <table className="min-w-full text-left text-xs">
                  <thead className="text-slate-500">
                    <tr>
                      <th className="py-2 pr-2">When</th>
                      <th className="py-2 pr-2">Type</th>
                      <th className="py-2 pr-2">Status</th>
                      <th className="py-2 pr-2">Items</th>
                      <th className="py-2 pr-2">Source</th>
                      <th className="py-2 pr-2">Duration</th>
                      <th className="py-2 pr-2">Error</th>
                    </tr>
                  </thead>
                  <tbody className="divide-y divide-slate-100 text-slate-700">
                    {logs.map((l) => (
                      <tr key={l.id}>
                        <td className="py-1 pr-2 whitespace-nowrap">{formatDate(l.started_at)}</td>
                        <td className="py-1 pr-2">{l.sync_type}</td>
                        <td className="py-1 pr-2">{l.status}</td>
                        <td className="py-1 pr-2">{l.items_fetched}</td>
                        <td className="py-1 pr-2">{l.triggered_by}</td>
                        <td className="py-1 pr-2">{l.duration_ms} ms</td>
                        <td className="py-1 pr-2 text-red-600">{l.error_message ?? ""}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              )}
            </div>
          </div>
        </div>
      ) : null}
    </section>
  );
}