import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { Ban, Check, RotateCcw, Shield, Trash2, UserPlus, X } from "lucide-react";
import { api, type AdminUserRow, type Invite, type Me } from "../lib/api";
import { notify } from "../lib/notifications";
import { ADMIN_USERS_TAB_KEY } from "../lib/adminUsersTab";
import Tooltip from "./Tooltip";
import { Section } from "./ui/form";
import { useConfirm } from "./ConfirmProvider";
import Tabs, { usePersistedTab } from "./Tabs";

// Admin-only user & access management: roles, access requests (the Invite whitelist), and the
// demo whitelist + reset. Each section is its own tab (persisted across reloads); the Access tab
// carries a badge with the count of pending requests so it's visible without switching to it.
// (The tab key + a "focus the Access tab" helper live in lib/adminUsersTab so callers can
// pre-select the tab without importing this lazy-loaded page — see that file.)

export default function AdminUsers({ me }: { me: Me }) {
  const { t } = useTranslation();
  const [tab, setTab] = usePersistedTab(ADMIN_USERS_TAB_KEY, "roles");
  const tabs = [
    { id: "roles", label: t("users.tabs.roles") },
    { id: "access", label: t("users.tabs.access"), badge: me.pending_invites },
    { id: "demo", label: t("users.tabs.demo") },
  ];
  const active = tabs.some((x) => x.id === tab) ? tab : "roles";
  return (
    <div className="p-4 max-w-3xl w-full mx-auto">
      <Tabs tabs={tabs} active={active} onChange={setTab} />
      {active === "roles" && <UsersRoles me={me} />}
      {active === "access" && <AdminInvites />}
      {active === "demo" && <AdminDemo />}
    </div>
  );
}

function Badge({ tone, children }: { tone: "accent" | "muted" | "warning"; children: React.ReactNode }) {
  const cls =
    tone === "accent"
      ? "border-accent/40 text-accent"
      : tone === "warning"
        ? "border-amber-500/40 text-amber-500"
        : "border-border text-muted";
  return (
    <span className={`shrink-0 text-[11px] px-2 py-0.5 rounded-full border ${cls}`}>{children}</span>
  );
}

function UsersRoles({ me }: { me: Me }) {
  const { t } = useTranslation();
  const qc = useQueryClient();
  const confirm = useConfirm();
  const q = useQuery({ queryKey: ["admin-users"], queryFn: api.adminUsers });
  // Which rows have an action in flight, so we disable ONLY those rows' buttons (SC1) — a Set, since
  // with per-row disabling the admin can now start actions on several rows concurrently.
  const [pendingIds, setPendingIds] = useState<Set<number>>(new Set());
  const startPending = (id: number) => setPendingIds((s) => new Set(s).add(id));
  const endPending = (id: number) =>
    setPendingIds((s) => {
      const n = new Set(s);
      n.delete(id);
      return n;
    });
  const setRole = useMutation({
    mutationFn: ({ id, role }: { id: number; role: "user" | "admin"; email: string }) =>
      api.setUserRole(id, role),
    onMutate: (vars) => startPending(vars.id),
    onSuccess: (_d, vars) => {
      qc.invalidateQueries({ queryKey: ["admin-users"] });
      notify({ level: "success", message: t("users.roles.updated", { email: vars.email }) });
    },
    onSettled: (_d, _e, vars) => endPending(vars.id),
    // Errors (e.g. last-admin / self) surface via the global error dialog with the server's detail.
  });

  const suspend = useMutation({
    mutationFn: ({ id, suspended }: { id: number; suspended: boolean; email: string }) =>
      api.setUserSuspended(id, suspended),
    onMutate: (vars) => startPending(vars.id),
    onSuccess: (_d, vars) => {
      qc.invalidateQueries({ queryKey: ["admin-users"] });
      notify({
        level: "success",
        message: t(vars.suspended ? "users.suspend.done" : "users.suspend.undone", {
          email: vars.email,
        }),
      });
    },
    onSettled: (_d, _e, vars) => endPending(vars.id),
    // Guards (demo / self / last admin) surface via the global error dialog.
  });
  const del = useMutation({
    mutationFn: ({ id }: { id: number; email: string }) => api.adminDeleteUser(id),
    onMutate: (vars) => startPending(vars.id),
    onSuccess: (_d, vars) => {
      qc.invalidateQueries({ queryKey: ["admin-users"] });
      notify({ level: "success", message: t("users.delete.done", { email: vars.email }) });
    },
    onSettled: (_d, _e, vars) => endPending(vars.id),
  });

  const onToggle = async (u: AdminUserRow) => {
    const makeAdmin = u.role !== "admin";
    const ok = await confirm({
      title: makeAdmin ? t("users.roles.promoteTitle") : t("users.roles.demoteTitle"),
      message: t(makeAdmin ? "users.roles.promoteConfirm" : "users.roles.demoteConfirm", {
        email: u.email,
      }),
      confirmLabel: makeAdmin ? t("users.roles.makeAdmin") : t("users.roles.makeUser"),
      danger: !makeAdmin,
    });
    if (ok) setRole.mutate({ id: u.id, role: makeAdmin ? "admin" : "user", email: u.email });
  };

  const onSuspend = async (u: AdminUserRow) => {
    const willSuspend = !u.is_suspended;
    const ok = await confirm({
      title: t(willSuspend ? "users.suspend.title" : "users.suspend.undoTitle"),
      message: t(willSuspend ? "users.suspend.confirm" : "users.suspend.undoConfirm", {
        email: u.email,
      }),
      confirmLabel: t(willSuspend ? "users.suspend.action" : "users.suspend.undoAction"),
      danger: willSuspend,
    });
    if (ok) suspend.mutate({ id: u.id, suspended: willSuspend, email: u.email });
  };

  const onDelete = async (u: AdminUserRow) => {
    const ok = await confirm({
      title: t("users.delete.title"),
      message: t("users.delete.confirm", { email: u.email }),
      confirmLabel: t("users.delete.action"),
      danger: true,
    });
    if (ok) del.mutate({ id: u.id, email: u.email });
  };

  const rows = q.data ?? [];

  return (
    <Section card title={t("users.roles.title")}>
      <p className="text-xs text-muted leading-relaxed mb-3">{t("users.roles.intro")}</p>
      {rows.length === 0 ? (
        <p className="text-sm text-muted">{t("users.roles.empty")}</p>
      ) : (
        <div className="space-y-1.5">
          {rows.map((u) => {
            const self = u.id === me.id;
            return (
              <div key={u.id} className="glass-card flex items-center gap-2.5 p-2.5 rounded-xl">
                <div className="min-w-0 flex-1">
                  <div className="text-sm truncate">
                    {u.display_name ?? u.email.split("@")[0]}
                    {self && <span className="text-muted"> · {t("users.roles.you")}</span>}
                  </div>
                  <div className="text-[11px] text-muted truncate">{u.email}</div>
                </div>
                {u.role === "admin" && <Badge tone="accent">{t("users.roles.admin")}</Badge>}
                {u.is_demo && <Badge tone="muted">{t("users.roles.demo")}</Badge>}
                {u.is_suspended && <Badge tone="warning">{t("users.roles.suspended")}</Badge>}
                {!u.is_active && <Badge tone="warning">{t("users.roles.pending")}</Badge>}
                {/* A Google sign-in proves the email, so "unverified" only applies to a
                    password-only account that hasn't clicked its verification link. */}
                {u.is_active && !u.email_verified && !u.has_google && (
                  <Badge tone="warning">{t("users.roles.unverified")}</Badge>
                )}
                <Tooltip
                  hint={
                    u.is_demo
                      ? t("users.roles.demoLocked")
                      : self
                        ? t("users.roles.selfLocked")
                        : u.role === "admin"
                          ? t("users.roles.makeUser")
                          : t("users.roles.makeAdmin")
                  }
                >
                  <button
                    onClick={() => onToggle(u)}
                    disabled={u.is_demo || self || pendingIds.has(u.id)}
                    className="shrink-0 glass-card glass-hover inline-flex items-center gap-1 px-2.5 py-1.5 rounded-lg text-xs disabled:opacity-40 transition"
                  >
                    <Shield className="w-3.5 h-3.5" />
                    {u.role === "admin" ? t("users.roles.makeUser") : t("users.roles.makeAdmin")}
                  </button>
                </Tooltip>
                <Tooltip
                  hint={
                    u.is_demo
                      ? t("users.suspend.demoLocked")
                      : self
                        ? t("users.suspend.selfLocked")
                        : u.is_suspended
                          ? t("users.suspend.undoAction")
                          : t("users.suspend.action")
                  }
                >
                  <button
                    onClick={() => onSuspend(u)}
                    disabled={u.is_demo || self || pendingIds.has(u.id)}
                    aria-label={u.is_suspended ? t("users.suspend.undoAction") : t("users.suspend.action")}
                    className={`shrink-0 p-1.5 rounded-lg border disabled:opacity-40 transition ${
                      u.is_suspended
                        ? "border-amber-500/40 text-amber-500 hover:bg-amber-500/10"
                        : "border-border text-muted hover:text-amber-500"
                    }`}
                  >
                    {u.is_suspended ? <RotateCcw className="w-4 h-4" /> : <Ban className="w-4 h-4" />}
                  </button>
                </Tooltip>
                <Tooltip hint={u.is_demo || self ? t("users.delete.locked") : t("users.delete.action")}>
                  <button
                    onClick={() => onDelete(u)}
                    disabled={u.is_demo || self || pendingIds.has(u.id)}
                    aria-label={t("users.delete.action")}
                    className="shrink-0 p-1.5 rounded-lg border border-border text-muted hover:text-red-400 disabled:opacity-40 transition"
                  >
                    <Trash2 className="w-4 h-4" />
                  </button>
                </Tooltip>
              </div>
            );
          })}
        </div>
      )}
    </Section>
  );
}

// --- Access requests (the Invite whitelist) — moved verbatim from Settings → Account -------

function AdminInvites() {
  const { t } = useTranslation();
  const qc = useQueryClient();
  const confirm = useConfirm();
  const invites = useQuery({ queryKey: ["admin-invites"], queryFn: () => api.adminInvites() });
  const [newEmail, setNewEmail] = useState("");
  const refresh = () => {
    qc.invalidateQueries({ queryKey: ["admin-invites"] });
    qc.invalidateQueries({ queryKey: ["me"] }); // updates the pending badge
  };
  const approve = useMutation({
    mutationFn: ({ id }: { id: number; email: string }) => api.approveInvite(id),
    onSuccess: (_d, vars) => {
      refresh();
      notify({ level: "success", message: t("settings.invites.approved", { email: vars.email }) });
    },
    onError: () => notify({ level: "error", message: t("settings.invites.approveFailed") }),
  });
  const deny = useMutation({
    mutationFn: (id: number) => api.denyInvite(id),
    onSuccess: (_d, _id) => {
      refresh();
      notify({ level: "success", message: t("settings.invites.denied") });
    },
    onError: () => notify({ level: "error", message: t("settings.invites.denyFailed") }),
  });
  const onDeny = async (i: { id: number; email: string }) => {
    const ok = await confirm({
      title: t("settings.invites.denyTitle"),
      message: t("settings.invites.denyConfirm", { email: i.email }),
      confirmLabel: t("settings.invites.deny"),
      danger: true,
    });
    if (ok) deny.mutate(i.id);
  };
  const add = useMutation({
    mutationFn: (email: string) => api.addInvite(email),
    onSuccess: (_d, email) => {
      setNewEmail("");
      refresh();
      notify({ level: "success", message: t("settings.invites.addedToWhitelist", { email }) });
    },
    onError: () => notify({ level: "error", message: t("settings.invites.addFailed") }),
  });

  const list = invites.data ?? [];
  const pending = list.filter((i) => i.status === "pending");
  const decided = list.filter((i) => i.status !== "pending");

  return (
    <Section card title={t("settings.invites.title")}>
      {pending.length === 0 ? (
        <p className="text-sm text-muted">{t("settings.invites.noPending")}</p>
      ) : (
        <div className="space-y-1.5">
          {pending.map((i) => (
            <InviteRow
              key={i.id}
              inv={i}
              onApprove={() => approve.mutate({ id: i.id, email: i.email })}
              onDeny={() => onDeny(i)}
              busy={approve.isPending || deny.isPending}
            />
          ))}
        </div>
      )}

      <form
        onSubmit={(e) => {
          e.preventDefault();
          if (newEmail.trim()) add.mutate(newEmail.trim());
        }}
        className="flex items-center gap-2 mt-3"
      >
        <input
          type="email"
          value={newEmail}
          onChange={(e) => setNewEmail(e.target.value)}
          placeholder={t("settings.invites.addPlaceholder")}
          className="flex-1 min-w-0 bg-card border border-border rounded-xl px-3 py-2 text-sm outline-none focus:border-accent"
        />
        <button
          type="submit"
          className="shrink-0 glass-card glass-hover flex items-center gap-1.5 px-3 py-2 rounded-xl text-sm transition"
        >
          <UserPlus className="w-4 h-4" /> {t("settings.invites.add")}
        </button>
      </form>

      {decided.length > 0 && (
        <details className="mt-3">
          <summary className="text-xs text-muted cursor-pointer">
            {t("settings.invites.decided", { count: decided.length })}
          </summary>
          <div className="mt-2 space-y-1 text-xs text-muted">
            {decided.map((i) => (
              <div key={i.id} className="flex items-center justify-between gap-2">
                <span className="truncate">{i.email}</span>
                <span className={i.status === "approved" ? "text-accent" : "text-red-400"}>
                  {i.status}
                </span>
              </div>
            ))}
          </div>
        </details>
      )}
    </Section>
  );
}

function AdminDemo() {
  const { t } = useTranslation();
  const qc = useQueryClient();
  const confirm = useConfirm();
  const list = useQuery({ queryKey: ["demo-whitelist"], queryFn: () => api.adminDemoWhitelist() });
  const [newEmail, setNewEmail] = useState("");

  const add = useMutation({
    mutationFn: (email: string) => api.addDemoWhitelist(email),
    onSuccess: (_d, email) => {
      setNewEmail("");
      qc.invalidateQueries({ queryKey: ["demo-whitelist"] });
      notify({ level: "success", message: t("settings.demo.added", { email }) });
    },
    onError: () => notify({ level: "error", message: t("settings.demo.addFailed") }),
  });
  const remove = useMutation({
    mutationFn: (id: number) => api.removeDemoWhitelist(id),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ["demo-whitelist"] });
      notify({ level: "success", message: t("settings.demo.removed") });
    },
    onError: () => notify({ level: "error", message: t("settings.demo.removeFailed") }),
  });
  const onRemove = async (r: { id: number; email: string }) => {
    const ok = await confirm({
      title: t("settings.demo.removeTitle"),
      message: t("settings.demo.removeConfirm", { email: r.email }),
      confirmLabel: t("settings.demo.remove"),
      danger: true,
    });
    if (ok) remove.mutate(r.id);
  };
  const reset = useMutation({
    mutationFn: () => api.resetDemo(),
    onSuccess: (r: { playlists_seeded: number }) =>
      notify({
        level: "success",
        message: t("settings.demo.resetDone", { count: r.playlists_seeded }),
      }),
    onError: () => notify({ level: "error", message: t("settings.demo.resetFailed") }),
  });

  const rows = list.data ?? [];

  return (
    <Section card title={t("settings.demo.title")}>
      <p className="text-xs text-muted leading-relaxed mb-2">{t("settings.demo.intro")}</p>

      {rows.length > 0 && (
        <div className="space-y-1.5 mb-3">
          {rows.map((r) => (
            <div key={r.id} className="glass-card flex items-center gap-2 p-2.5 rounded-xl">
              <div className="min-w-0 flex-1">
                <div className="text-sm truncate">{r.email}</div>
                {r.added_by && (
                  <div className="text-[11px] text-muted truncate">
                    {t("settings.demo.addedBy", { who: r.added_by })}
                  </div>
                )}
              </div>
              <Tooltip hint={t("settings.demo.removeHint")}>
                <button
                  onClick={() => onRemove(r)}
                  disabled={remove.isPending}
                  className="shrink-0 p-1.5 rounded-lg border border-border text-muted hover:text-red-400 disabled:opacity-50 transition"
                  aria-label={t("settings.demo.remove")}
                >
                  <Trash2 className="w-4 h-4" />
                </button>
              </Tooltip>
            </div>
          ))}
        </div>
      )}

      <form
        onSubmit={(e) => {
          e.preventDefault();
          if (newEmail.trim()) add.mutate(newEmail.trim());
        }}
        className="flex items-center gap-2"
      >
        <input
          type="email"
          value={newEmail}
          onChange={(e) => setNewEmail(e.target.value)}
          placeholder={t("settings.demo.addPlaceholder")}
          className="flex-1 min-w-0 bg-card border border-border rounded-xl px-3 py-2 text-sm outline-none focus:border-accent"
        />
        <button
          type="submit"
          className="shrink-0 glass-card glass-hover flex items-center gap-1.5 px-3 py-2 rounded-xl text-sm transition"
        >
          <UserPlus className="w-4 h-4" /> {t("settings.demo.add")}
        </button>
      </form>

      <div className="mt-4 pt-3 border-t border-border">
        <Tooltip hint={t("settings.demo.resetHint")}>
          <button
            onClick={async () => {
              if (
                await confirm({
                  title: t("settings.demo.resetTitle"),
                  message: t("settings.demo.resetConfirm"),
                  confirmLabel: t("settings.demo.reset"),
                  danger: true,
                })
              )
                reset.mutate();
            }}
            disabled={reset.isPending}
            className="glass-card glass-hover flex items-center gap-2 px-3 py-2 rounded-xl text-sm disabled:opacity-50 transition"
          >
            <RotateCcw className={`w-4 h-4 ${reset.isPending ? "animate-spin" : ""}`} />
            {t("settings.demo.reset")}
          </button>
        </Tooltip>
      </div>
    </Section>
  );
}

function InviteRow({
  inv,
  onApprove,
  onDeny,
  busy,
}: {
  inv: Invite;
  onApprove: () => void;
  onDeny: () => void;
  busy: boolean;
}) {
  const { t } = useTranslation();
  return (
    <div className="glass-card flex items-center gap-2 p-2.5 rounded-xl">
      <div className="min-w-0 flex-1">
        <div className="text-sm truncate">{inv.email}</div>
        {inv.requested_at && (
          <div className="text-[11px] text-muted">
            {t("settings.invites.requested", {
              time: new Date(inv.requested_at).toLocaleString(),
            })}
          </div>
        )}
      </div>
      <Tooltip hint={t("settings.invites.approveHint")}>
        <button
          onClick={onApprove}
          disabled={busy}
          className="shrink-0 p-1.5 rounded-lg border border-accent/40 text-accent hover:bg-accent/10 disabled:opacity-50 transition"
          aria-label={t("settings.invites.approve")}
        >
          <Check className="w-4 h-4" />
        </button>
      </Tooltip>
      <Tooltip hint={t("settings.invites.denyHint")}>
        <button
          onClick={onDeny}
          disabled={busy}
          className="shrink-0 p-1.5 rounded-lg border border-border text-muted hover:text-red-400 disabled:opacity-50 transition"
          aria-label={t("settings.invites.deny")}
        >
          <X className="w-4 h-4" />
        </button>
      </Tooltip>
    </div>
  );
}
