import React, { useEffect, useMemo, useState } from "react";
import { Gauge, KeyRound, Pencil, RefreshCw, Shield, Trash2, UserPlus, Users, X } 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";

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("4");
  const [quotaMemory, setQuotaMemory] = useState("16Gi");
  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 sortedUsers = useMemo(
    () => [...users].sort((a, b) => (a.username ?? "").localeCompare(b.username ?? "")),
    [users]
  );

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

  const loadClusters = 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");
    }
  };

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

  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("4");
      setQuotaMemory("16Gi");
      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";
    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) => {
    setEditingLimits(target);
    setEditNamespace(target.namespace || namespaceForUsername(target.username || ""));
    setEditDefaultClusterId(target.defaultClusterId || clusters[0]?.id || "");
    setEditQuotaCpu(target.quotaCpu || "4");
    setEditQuotaMemory(target.quotaMemory || "16Gi");
    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, {
        namespace: editNamespace.trim(),
        defaultClusterId: editDefaultClusterId.trim(),
        quotaCpu: editQuotaCpu.trim(),
        quotaMemory: editQuotaMemory.trim(),
        quotaGpu: editQuotaGpu.trim(),
        quotaGpuMemory: editQuotaGpuMemory.trim(),
      });
      success("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-7xl 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 lg:grid-cols-[360px_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="4" />
                  </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="16Gi" />
                  </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">
                  CPU and memory use Kubernetes quantities. GPU memory is an integer MB value, 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="overflow-x-auto">
              <table className="min-w-full divide-y divide-slate-200 text-sm">
                <thead className="bg-slate-50 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">
                  <tr>
                    <th className="px-5 py-3">User</th>
                    <th className="px-5 py-3">Role</th>
                    <th className="px-5 py-3">Status</th>
                    <th className="px-5 py-3">Namespace</th>
                    <th className="px-5 py-3">Quota</th>
                    <th className="sticky right-0 z-10 bg-slate-50 px-5 py-3 text-right shadow-[-12px_0_18px_-18px_rgba(15,23,42,0.35)]">
                      Actions
                    </th>
                  </tr>
                </thead>
                <tbody className="divide-y divide-slate-100">
                  {sortedUsers.map((target) => (
                    <tr key={target.id} className="group hover:bg-slate-50">
                      <td className="px-5 py-3">
                        <div className="font-medium text-slate-900">{target.username}</div>
                        <div className="text-xs text-slate-500">{target.email}</div>
                      </td>
                      <td className="px-5 py-3">
                        <Badge variant={target.role === "admin" ? "info" : "secondary"} size="sm">
                          {target.role}
                        </Badge>
                      </td>
                      <td className="px-5 py-3">
                        <Badge variant={target.isActive ? "success" : "warning"} size="sm">
                          {target.isActive ? "Active" : "Disabled"}
                        </Badge>
                      </td>
                      <td className="px-5 py-3">
                        <div className="font-mono text-xs text-slate-700">{target.namespace || "-"}</div>
                        <div className="text-xs text-slate-500">{target.workspaceName || target.workspaceId}</div>
                        {target.defaultClusterId && (
                          <div className="mt-1 text-xs text-blue-700">{clusterName(clusters, target.defaultClusterId)}</div>
                        )}
                      </td>
                      <td className="px-5 py-3 text-xs text-slate-600">
                        {target.role === "admin" ? (
                          <span className="text-slate-400">default workspace</span>
                        ) : (
                          <div className="grid gap-1">
                            <span>CPU {target.quotaCpu || "-"}</span>
                            <span>Mem {target.quotaMemory || "-"}</span>
                            <span>GPU {target.quotaGpu || "0"} / Mem {target.quotaGpuMemory || "0"}</span>
                          </div>
                        )}
                      </td>
                      <td className="sticky right-0 bg-white px-5 py-3 shadow-[-12px_0_18px_-18px_rgba(15,23,42,0.35)] group-hover:bg-slate-50">
                        <div className="grid w-[260px] grid-cols-2 gap-2">
                          <Button type="button" variant="ghost" size="sm" onClick={() => toggleRole(target)}>
                            Make {target.role === "admin" ? "User" : "Admin"}
                          </Button>
                          {target.role !== "admin" && (
                            <Button type="button" variant="secondary" size="sm" icon={Pencil} onClick={() => openLimitsEditor(target)}>
                              Limits
                            </Button>
                          )}
                          <Button
                            type="button"
                            variant="secondary"
                            size="sm"
                            onClick={() => toggleActive(target)}
                            disabled={target.id === user?.userId}
                          >
                            {target.isActive ? "Disable" : "Enable"}
                          </Button>
                          <Button
                            type="button"
                            variant="danger"
                            size="sm"
                            icon={Trash2}
                            onClick={() => handleDelete(target)}
                            disabled={target.id === user?.userId}
                          >
                            Delete
                          </Button>
                        </div>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </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" />
                  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">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" required />
                </label>
                <label className="block text-sm font-medium text-slate-700">
                  Memory
                  <Input value={editQuotaMemory} onChange={(e) => setEditQuotaMemory(e.target.value)} className="mt-1" required />
                </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}>
                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;
};

export default UserManagementPage;
