import React, { useCallback, useEffect, useMemo, useState } from "react";
import { Gauge, KeyRound, Pencil, RefreshCw, Shield, Trash2, UserPlus, Users, X, type LucideIcon } from "lucide-react";
import { createUser, listClusters, listUsers, updateUser, deleteUser, type ClusterResponse, type UserResponse } from "@/api";
import { useToast } from "@/shared";
import { Button, Input, Badge, LoadingState } from "@/shared/components";
import { formatApiError } from "@/shared/utils";
import { useAuth } from "@/app/providers";

type LimitsEditorMode = "edit" | "downgrade";

const UserManagementPage: React.FC = () => {
  const { user } = useAuth();
  const { success, error: toastError } = useToast();
  const [users, setUsers] = useState<UserResponse[]>([]);
  const [clusters, setClusters] = useState<ClusterResponse[]>([]);
  const [loading, setLoading] = useState(false);
  const [creating, setCreating] = useState(false);
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [role, setRole] = useState("user");
  const [namespace, setNamespace] = useState("");
  const [defaultClusterId, setDefaultClusterId] = useState("");
  const [quotaCpu, setQuotaCpu] = useState("");
  const [quotaMemory, setQuotaMemory] = useState("");
  const [quotaGpu, setQuotaGpu] = useState("0");
  const [quotaGpuMemory, setQuotaGpuMemory] = useState("0");
  const [mustChangePassword, setMustChangePassword] = useState(true);
  const [editingLimits, setEditingLimits] = useState<UserResponse | null>(null);
  const [editNamespace, setEditNamespace] = useState("");
  const [editDefaultClusterId, setEditDefaultClusterId] = useState("");
  const [editQuotaCpu, setEditQuotaCpu] = useState("");
  const [editQuotaMemory, setEditQuotaMemory] = useState("");
  const [editQuotaGpu, setEditQuotaGpu] = useState("");
  const [editQuotaGpuMemory, setEditQuotaGpuMemory] = useState("");
  const [savingLimits, setSavingLimits] = useState(false);
  const [limitsEditorMode, setLimitsEditorMode] = useState<LimitsEditorMode>("edit");

  const sortedUsers = useMemo(
    () => [...users].sort((a, b) => (a.username ?? "").localeCompare(b.username ?? "")),
    [users]
  );

  const loadUsers = useCallback(async () => {
    setLoading(true);
    try {
      setUsers(await listUsers());
    } catch (err) {
      toastError(formatApiError(err) || "Failed to load users");
    } finally {
      setLoading(false);
    }
  }, [toastError]);

  const loadClusters = useCallback(async () => {
    try {
      const data = await listClusters();
      const available = data.filter((cluster) => typeof cluster.id === "string" && cluster.id.length > 0);
      setClusters(available);
      setDefaultClusterId((current) => current || available[0]?.id || "");
    } catch (err) {
      toastError(formatApiError(err) || "Failed to load clusters");
    }
  }, [toastError]);

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

  const handleCreate = async (event: React.FormEvent) => {
    event.preventDefault();
    if (!username.trim() || !password.trim()) {
      toastError("Username and initial password are required.");
      return;
    }
    const effectiveNamespace = namespace.trim() || namespaceForUsername(username);
    setCreating(true);
    try {
      await createUser({
        username: username.trim(),
        password,
        role,
        ...(role === "user"
          ? {
              namespace: effectiveNamespace,
              defaultClusterId: defaultClusterId.trim(),
              quotaCpu: quotaCpu.trim(),
              quotaMemory: quotaMemory.trim(),
              quotaGpu: quotaGpu.trim(),
              quotaGpuMemory: quotaGpuMemory.trim(),
            }
          : {}),
        mustChangePassword,
        isActive: true,
      });
      success("User created");
      setUsername("");
      setPassword("");
      setRole("user");
      setNamespace("");
      setDefaultClusterId(clusters[0]?.id || "");
      setQuotaCpu("");
      setQuotaMemory("");
      setQuotaGpu("0");
      setQuotaGpuMemory("0");
      setMustChangePassword(true);
      await loadUsers();
    } catch (err) {
      toastError(formatApiError(err) || "Failed to create user");
    } finally {
      setCreating(false);
    }
  };

  useEffect(() => {
    if (role !== "user") {
      return;
    }
    setNamespace((current) => {
      if (current.trim() && !current.startsWith("ocdp-u-")) {
        return current;
      }
      return namespaceForUsername(username);
    });
  }, [username, role]);

  const toggleActive = async (target: UserResponse) => {
    if (!target.id) return;
    try {
      await updateUser(target.id, { isActive: !target.isActive });
      success(target.isActive ? "User disabled" : "User enabled");
      await loadUsers();
    } catch (err) {
      toastError(formatApiError(err) || "Failed to update user");
    }
  };

  const toggleRole = async (target: UserResponse) => {
    if (!target.id) return;
    const nextRole = target.role === "admin" ? "user" : "admin";
    if (nextRole === "user") {
      openLimitsEditor(target, "downgrade");
      return;
    }
    try {
      await updateUser(target.id, { role: nextRole });
      success("User role updated");
      await loadUsers();
    } catch (err) {
      toastError(formatApiError(err) || "Failed to update role");
    }
  };

  const handleDelete = async (target: UserResponse) => {
    if (!target.id || target.id === user?.userId) return;
    if (!window.confirm(`Delete user ${target.username}? This cannot be undone.`)) return;
    try {
      await deleteUser(target.id);
      success("User deleted");
      await loadUsers();
    } catch (err) {
      toastError(formatApiError(err) || "Failed to delete user");
    }
  };

  const openLimitsEditor = (target: UserResponse, mode: LimitsEditorMode = "edit") => {
    setLimitsEditorMode(mode);
    setEditingLimits(target);
    setEditNamespace(target.namespace || namespaceForUsername(target.username || ""));
    setEditDefaultClusterId(target.defaultClusterId || clusters[0]?.id || "");
    setEditQuotaCpu(target.quotaCpu || "");
    setEditQuotaMemory(target.quotaMemory || "");
    setEditQuotaGpu(target.quotaGpu || "0");
    setEditQuotaGpuMemory(target.quotaGpuMemory || "0");
  };

  const saveLimits = async (event: React.FormEvent) => {
    event.preventDefault();
    if (!editingLimits?.id) return;
    setSavingLimits(true);
    try {
      await updateUser(editingLimits.id, {
        ...(limitsEditorMode === "downgrade" ? { role: "user" } : {}),
        namespace: editNamespace.trim(),
        defaultClusterId: editDefaultClusterId.trim(),
        quotaCpu: quotaForApi(editQuotaCpu, true),
        quotaMemory: quotaForApi(editQuotaMemory, true),
        quotaGpu: editQuotaGpu.trim(),
        quotaGpuMemory: editQuotaGpuMemory.trim(),
      });
      success(limitsEditorMode === "downgrade" ? "User role and limits updated" : "User limits updated");
      setEditingLimits(null);
      await loadUsers();
    } catch (err) {
      toastError(formatApiError(err) || "Failed to update user limits");
    } finally {
      setSavingLimits(false);
    }
  };

  return (
    <div className="mx-auto max-w-screen-2xl px-4 py-6 sm:px-6 lg:px-8">
      <div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
        <div>
          <div className="mb-2 flex items-center gap-2 text-sm font-medium text-blue-700">
            <Shield className="h-4 w-4" />
            Admin only
          </div>
          <h1 className="text-2xl font-semibold text-slate-950">User Management</h1>
          <p className="mt-1 text-sm text-slate-500">
            Create accounts, assign roles, and disable access without public self-registration.
          </p>
        </div>
        <Button type="button" variant="secondary" icon={RefreshCw} onClick={loadUsers} loading={loading}>
          Refresh
        </Button>
      </div>

      <div className="grid gap-6 xl:grid-cols-[380px_minmax(0,1fr)]">
        <form onSubmit={handleCreate} className="rounded-lg border border-slate-200 bg-white p-5 shadow-soft">
          <div className="mb-4 flex items-center gap-2">
            <UserPlus className="h-5 w-5 text-blue-600" />
            <h2 className="text-base font-semibold text-slate-900">Create User</h2>
          </div>
          <div className="space-y-4">
            <label className="block text-sm font-medium text-slate-700">
              Username
              <Input value={username} onChange={(e) => setUsername(e.target.value)} className="mt-1" required />
            </label>
            <label className="block text-sm font-medium text-slate-700">
              Initial password
              <Input
                type="password"
                value={password}
                onChange={(e) => setPassword(e.target.value)}
                className="mt-1"
                required
              />
            </label>
            <label className="block text-sm font-medium text-slate-700">
              Role
              <select
                value={role}
                onChange={(event) => setRole(event.target.value)}
                className="mt-1 w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-100"
              >
                <option value="user">User</option>
                <option value="admin">Admin</option>
              </select>
            </label>
            {role === "user" && (
              <div className="rounded-lg border border-slate-200 bg-slate-50 p-3">
                <div className="mb-3 flex items-center gap-2 text-sm font-semibold text-slate-900">
                  <KeyRound className="h-4 w-4 text-blue-600" />
                  Tenant namespace
                </div>
                <label className="block text-sm font-medium text-slate-700">
                  Namespace
                  <Input
                    value={namespace}
                    onChange={(e) => setNamespace(e.target.value)}
                    className="mt-1 font-mono"
                    placeholder={namespaceForUsername(username)}
                    required
                  />
                </label>
                <label className="mt-3 block text-sm font-medium text-slate-700">
                  Default cluster
                  <select
                    value={defaultClusterId}
                    onChange={(event) => setDefaultClusterId(event.target.value)}
                    className="mt-1 w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-100"
                  >
                    <option value="">Select a cluster</option>
                    {clusters.map((cluster) => (
                      <option key={cluster.id} value={cluster.id}>
                        {cluster.name || cluster.id}
                      </option>
                    ))}
                  </select>
                </label>
              </div>
            )}
            {role === "user" && (
              <div className="rounded-lg border border-slate-200 bg-slate-50 p-3">
                <div className="mb-3 flex items-center gap-2 text-sm font-semibold text-slate-900">
                  <Gauge className="h-4 w-4 text-blue-600" />
                  Resource limits
                </div>
                <div className="grid grid-cols-2 gap-3">
                  <label className="block text-sm font-medium text-slate-700">
                    CPU
                    <Input value={quotaCpu} onChange={(e) => setQuotaCpu(e.target.value)} className="mt-1" placeholder="Unlimited" />
                  </label>
                  <label className="block text-sm font-medium text-slate-700">
                    Memory
                    <Input value={quotaMemory} onChange={(e) => setQuotaMemory(e.target.value)} className="mt-1" placeholder="Unlimited" />
                  </label>
                  <label className="block text-sm font-medium text-slate-700">
                    GPU
                    <Input value={quotaGpu} onChange={(e) => setQuotaGpu(e.target.value)} className="mt-1" placeholder="0" />
                  </label>
                  <label className="block text-sm font-medium text-slate-700">
                    GPU Mem
                    <Input value={quotaGpuMemory} onChange={(e) => setQuotaGpuMemory(e.target.value)} className="mt-1" placeholder="0" />
                  </label>
                </div>
                <p className="mt-2 text-xs text-slate-500">
                  Leave CPU or memory blank for no platform quota. GPU and GPU memory default to 0. GPU memory is integer MB, for example 10000.
                </p>
              </div>
            )}
            <label className="flex items-center gap-2 text-sm text-slate-700">
              <input
                type="checkbox"
                checked={mustChangePassword}
                onChange={(event) => setMustChangePassword(event.target.checked)}
                className="h-4 w-4 rounded border-slate-300"
              />
              Require password change after first login
            </label>
            <Button type="submit" variant="primary" icon={UserPlus} loading={creating} className="w-full">
              Create User
            </Button>
          </div>
        </form>

        <section className="min-w-0 rounded-lg border border-slate-200 bg-white shadow-soft">
          <div className="flex items-center justify-between border-b border-slate-200 px-5 py-4">
            <div className="flex items-center gap-2">
              <Users className="h-5 w-5 text-slate-500" />
              <h2 className="text-base font-semibold text-slate-900">Accounts</h2>
            </div>
            <Badge variant="secondary" size="sm">{users.length} users</Badge>
          </div>
          {loading ? (
            <LoadingState message="Loading users..." />
          ) : (
            <div className="divide-y divide-slate-100">
              {sortedUsers.map((target) => (
                <article key={target.id} className="min-w-0 overflow-hidden px-4 py-4 hover:bg-slate-50 sm:px-5">
                  <div className="flex min-w-0 flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
                    <div className="min-w-0">
                      <div className="flex flex-wrap items-center gap-2">
                        <h3 className="min-w-0 truncate text-sm font-semibold text-slate-950">{target.username}</h3>
                        <Badge variant={target.role === "admin" ? "info" : "secondary"} size="sm">
                          {target.role}
                        </Badge>
                        <Badge variant={target.isActive ? "success" : "warning"} size="sm">
                          {target.isActive ? "Active" : "Disabled"}
                        </Badge>
                      </div>
                      <div className="mt-1 truncate text-xs text-slate-500">{target.email || target.id}</div>
                    </div>

                    <div className="grid w-full min-w-0 grid-cols-2 gap-2 sm:grid-cols-4 xl:w-auto xl:min-w-[360px] xl:max-w-[480px]">
                      <ActionButton onClick={() => toggleRole(target)} title={`Make ${target.role === "admin" ? "User" : "Admin"}`}>
                        {target.role === "admin" ? "To User" : "To Admin"}
                      </ActionButton>
                      {target.role !== "admin" && (
                        <ActionButton variant="secondary" icon={Pencil} onClick={() => openLimitsEditor(target)}>
                          Limits
                        </ActionButton>
                      )}
                      <ActionButton
                        variant="secondary"
                        onClick={() => toggleActive(target)}
                        disabled={target.id === user?.userId}
                      >
                        {target.isActive ? "Disable" : "Enable"}
                      </ActionButton>
                      <ActionButton
                        variant="danger"
                        icon={Trash2}
                        onClick={() => handleDelete(target)}
                        disabled={target.id === user?.userId}
                      >
                        Delete
                      </ActionButton>
                    </div>
                  </div>

                  <div className="mt-4 grid min-w-0 gap-4 lg:grid-cols-[minmax(240px,0.85fr)_minmax(0,1.15fr)]">
                    <div className="min-w-0 rounded-md border border-slate-200 bg-slate-50 px-3 py-2">
                      <div className="grid gap-1 text-xs">
                        <div className="flex min-w-0 items-center justify-between gap-3">
                          <span className="shrink-0 text-slate-500">Namespace</span>
                          <span className="min-w-0 truncate font-mono text-slate-800">{target.namespace || "-"}</span>
                        </div>
                        <div className="flex min-w-0 items-center justify-between gap-3">
                          <span className="shrink-0 text-slate-500">Workspace</span>
                          <span className="min-w-0 truncate text-slate-700">{target.workspaceName || target.workspaceId || "-"}</span>
                        </div>
                        <div className="flex min-w-0 items-center justify-between gap-3">
                          <span className="shrink-0 text-slate-500">Cluster</span>
                          <span className="min-w-0 truncate text-blue-700">
                            {target.defaultClusterId ? clusterName(clusters, target.defaultClusterId) : "-"}
                          </span>
                        </div>
                      </div>
                    </div>

                    <div className="min-w-0">
                      {target.role === "admin" ? (
                        <div className="inline-flex rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-xs text-slate-500">
                          default workspace
                        </div>
                      ) : (
                        <div className="grid min-w-0 grid-cols-2 gap-2 sm:grid-cols-4">
                          {quotaChip("CPU", target.quotaCpu || "Unlimited")}
                          {quotaChip("Memory", target.quotaMemory || "Unlimited")}
                          {quotaChip("GPU", target.quotaGpu || "0")}
                          {quotaChip("GPU Mem", target.quotaGpuMemory || "0")}
                        </div>
                      )}
                    </div>
                  </div>
                </article>
              ))}
            </div>
          )}
        </section>
      </div>
      {editingLimits && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/45 p-4 backdrop-blur-sm">
          <form onSubmit={saveLimits} className="w-full max-w-xl rounded-xl border border-slate-200 bg-white shadow-2xl">
            <div className="flex items-start justify-between border-b border-slate-200 px-6 py-5">
              <div>
                <div className="flex items-center gap-2 text-sm font-semibold text-blue-700">
                  <Gauge className="h-4 w-4" />
                  {limitsEditorMode === "downgrade" ? "Convert admin to user" : "Tenant limits"}
                </div>
                <h2 className="mt-1 text-xl font-semibold text-slate-950">{editingLimits.username}</h2>
                <p className="mt-1 text-sm text-slate-500">
                  {limitsEditorMode === "downgrade"
                    ? "Set the tenant namespace, default cluster, and resource quota before applying the user role."
                    : "Changes are applied to workspace metadata and the next tenant binding/deploy refreshes Kubernetes ResourceQuota."}
                </p>
              </div>
              <button type="button" onClick={() => setEditingLimits(null)} className="rounded-lg p-2 text-slate-500 hover:bg-slate-100 hover:text-slate-900">
                <X className="h-5 w-5" />
              </button>
            </div>
            <div className="space-y-4 p-6">
              <label className="block text-sm font-medium text-slate-700">
                Namespace
                <Input value={editNamespace} onChange={(e) => setEditNamespace(e.target.value)} className="mt-1 font-mono" required />
              </label>
              <label className="block text-sm font-medium text-slate-700">
                Default cluster
                <select
                  value={editDefaultClusterId}
                  onChange={(event) => setEditDefaultClusterId(event.target.value)}
                  className="mt-1 w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-100"
                >
                  <option value="">Select a cluster</option>
                  {clusters.map((cluster) => (
                    <option key={cluster.id} value={cluster.id}>
                      {cluster.name || cluster.id}
                    </option>
                  ))}
                </select>
              </label>
              <div className="grid gap-3 sm:grid-cols-2">
                <label className="block text-sm font-medium text-slate-700">
                  CPU
                  <Input value={editQuotaCpu} onChange={(e) => setEditQuotaCpu(e.target.value)} className="mt-1" placeholder="Unlimited" />
                </label>
                <label className="block text-sm font-medium text-slate-700">
                  Memory
                  <Input value={editQuotaMemory} onChange={(e) => setEditQuotaMemory(e.target.value)} className="mt-1" placeholder="Unlimited" />
                </label>
                <label className="block text-sm font-medium text-slate-700">
                  GPU
                  <Input value={editQuotaGpu} onChange={(e) => setEditQuotaGpu(e.target.value)} className="mt-1" required />
                </label>
                <label className="block text-sm font-medium text-slate-700">
                  GPU memory
                  <Input value={editQuotaGpuMemory} onChange={(e) => setEditQuotaGpuMemory(e.target.value)} className="mt-1" placeholder="10000" required />
                </label>
              </div>
            </div>
            <div className="flex justify-end gap-2 border-t border-slate-200 px-6 py-4">
              <Button type="button" variant="secondary" onClick={() => setEditingLimits(null)}>
                Cancel
              </Button>
              <Button type="submit" variant="primary" loading={savingLimits}>
                {limitsEditorMode === "downgrade" ? "Save Role and Limits" : "Save Limits"}
              </Button>
            </div>
          </form>
        </div>
      )}
    </div>
  );
};

const namespaceForUsername = (username: string): string => {
  const label = username
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "");
  return `ocdp-u-${label || "user"}`.slice(0, 63).replace(/-+$/g, "");
};

const clusterName = (clusters: ClusterResponse[], clusterId: string): string => {
  const cluster = clusters.find((candidate) => candidate.id === clusterId);
  return cluster?.name || clusterId;
};

const quotaChip = (label: string, value: React.ReactNode): React.ReactElement => (
  <div className="min-w-0 rounded-md border border-slate-200 bg-white px-3 py-2">
    <div className="text-[11px] font-medium uppercase tracking-wide text-slate-500">{label}</div>
    <div className="mt-0.5 truncate font-mono text-sm text-slate-900">{value}</div>
  </div>
);

const ActionButton = ({
  children,
  icon,
  variant = "ghost",
  ...props
}: React.ButtonHTMLAttributes<HTMLButtonElement> & {
  children: React.ReactNode;
  icon?: LucideIcon;
  variant?: "secondary" | "danger" | "ghost";
}): React.ReactElement => (
  <Button
    type="button"
    variant={variant}
    size="sm"
    icon={icon}
    className="min-w-0 max-w-full px-2 text-xs leading-tight [&>svg]:shrink-0"
    {...props}
  >
    <span className="min-w-0 truncate">{children}</span>
  </Button>
);

const quotaForApi = (value: string, blankMeansUnlimited = false): string => {
  const trimmed = value.trim();
  if (!trimmed && blankMeansUnlimited) {
    return "unlimited";
  }
  return trimmed;
};

export default UserManagementPage;
