"use client";

import { isApiSuccess } from "@/lib/api-messages";
import * as React from "react";

import { Check, KeyRound } from "lucide-react";
import { useRouter } from "next/navigation";
import { toast } from "sonner";

import { ErrorBanner } from "@/components/shared/error-banner";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { requestDashboardApi } from "@/lib/dashboard-api-client";
import { PermissionPicker } from "@/components/admins/rbac/permission-picker";
import { RoleBadge } from "@/components/admins/rbac/role-badge";
import { RoleCapabilityBadge } from "@/components/admins/rbac/role-capability-badge";
import type { Role } from "@/components/admins/rbac/types";
import type { UserDetail } from "../../_lib/users-server-api";

type UserAccessPageClientProps = {
  user: UserDetail;
  roles: Role[];
  rolesErrorMessage: string | null;
};

type AssignRolesResponse = {
  status?: string;
  message?: string;
  user?: UserDetail;
};

type AssignPermissionsResponse = {
  status?: string;
  message?: string;
  user?: UserDetail;
};

export function UserAccessPageClient({
  user,
  roles,
  rolesErrorMessage,
}: UserAccessPageClientProps) {
  const router = useRouter();
  const [selectedRoleIds, setSelectedRoleIds] = React.useState<string[]>(user.roleIds ?? []);
  const [directPermissions, setDirectPermissions] = React.useState(user.directPermissions);
  const [effectivePermissions, setEffectivePermissions] = React.useState(user.effectivePermissions);
  const [savingRoles, setSavingRoles] = React.useState(false);
  const [savingPermissions, setSavingPermissions] = React.useState(false);

  const toggleRole = (roleId: string, checked: boolean) => {
    setSelectedRoleIds((current) =>
      checked
        ? [...new Set([...current, roleId])]
        : current.filter((id) => id !== roleId),
    );
  };

  const saveRoles = async () => {
    setSavingRoles(true);

    try {
      const data = await requestDashboardApi<AssignRolesResponse>({
        url: "/dashboard/admins/users/assign-roles",
        method: "POST",
        body: {
          userId: user.userId,
          roleIds: selectedRoleIds,
        },
        fallbackError: "Could not update user roles.",
        validate: (payload) => isApiSuccess(payload),
      });

      if (data.user) {
        setSelectedRoleIds(data.user.roleIds ?? []);
        setDirectPermissions(data.user.directPermissions);
        setEffectivePermissions(data.user.effectivePermissions);
      }

      toast.success(data.message ?? "User roles updated.");
      router.refresh();
    } catch (error) {
      const message = error instanceof Error ? error.message : "Could not update user roles.";
      toast.error(message);
    } finally {
      setSavingRoles(false);
    }
  };

  const saveDirectPermissions = async () => {
    setSavingPermissions(true);

    try {
      const data = await requestDashboardApi<AssignPermissionsResponse>({
        url: "/dashboard/admins/users/assign-permissions",
        method: "POST",
        body: {
          userId: user.userId,
          permissions: directPermissions,
          mode: "set",
        },
        fallbackError: "Could not update direct permissions.",
        validate: (payload) => isApiSuccess(payload),
      });

      if (data.user) {
        setDirectPermissions(data.user.directPermissions);
        setEffectivePermissions(data.user.effectivePermissions);
      }

      toast.success(data.message ?? "Direct permissions updated.");
      router.refresh();
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "Could not update direct permissions.";
      toast.error(message);
    } finally {
      setSavingPermissions(false);
    }
  };

  return (
    <div className="space-y-6">
      <ErrorBanner message={rolesErrorMessage} />

      <div className="rounded-2xl border bg-card p-4 shadow-sm">
        <div className="flex flex-wrap items-start justify-between gap-3">
          <div>
            <div className="flex flex-wrap items-center gap-2">
              <KeyRound className="size-5 text-primary" />
              <h2 className="font-semibold text-lg">Manage access</h2>
            </div>
            <p className="mt-1 text-muted-foreground text-sm">
              {user.displayName || user.email} · <span className="font-mono">{user.principal}</span>
            </p>
          </div>
        </div>
      </div>

      <div className="grid gap-4 xl:grid-cols-[minmax(0,1fr)_minmax(360px,0.8fr)]">
        <section className="rounded-2xl border bg-card p-4 shadow-sm">
          <div className="flex flex-wrap items-center justify-between gap-2">
            <div>
              <h3 className="font-semibold text-base">Roles</h3>
              <p className="text-muted-foreground text-sm">
                Select which roles should be assigned to this backend user.
              </p>
            </div>
            <div className="flex items-center gap-2">
              <Badge variant="secondary">{selectedRoleIds.length} selected</Badge>
              <Button type="button" onClick={saveRoles} disabled={savingRoles} size="sm">
                <Check className="size-4" />
                {savingRoles ? "Saving..." : "Save roles"}
              </Button>
            </div>
          </div>

          <div className="mt-4 grid gap-3 lg:grid-cols-2">
            {roles.map((role) => {
              const checked = selectedRoleIds.includes(role.id);
              return (
                <label
                  key={role.id}
                  className={`flex cursor-pointer items-start gap-3 rounded-xl border p-3 transition-colors ${
                    checked ? "border-primary/30 bg-primary/5" : "hover:bg-muted/50"
                  }`}
                >
                  <Checkbox
                    checked={checked}
                    onCheckedChange={(value) => toggleRole(role.id, value === true)}
                    className="mt-0.5"
                  />
                  <div className="min-w-0 flex-1">
                    <div className="flex flex-wrap items-center gap-2">
                      <span className="font-mono font-medium text-sm">{role.name}</span>
                      <RoleBadge type={role.type} />
                      {role.capability ? (
                        <RoleCapabilityBadge capability={role.capability} />
                      ) : null}
                    </div>
                    <p className="mt-1 text-muted-foreground text-xs">{role.description}</p>
                    <p className="mt-2 text-muted-foreground text-xs">
                      {role.permissionCount ?? role.permissions.length} permissions
                    </p>
                  </div>
                </label>
              );
            })}
          </div>
        </section>

        <section className="space-y-4">
          <div className="rounded-2xl border bg-card p-4 shadow-sm">
            <div className="flex flex-wrap items-start justify-between gap-2">
              <div>
                <h3 className="font-semibold text-base">Direct permissions</h3>
                <p className="text-muted-foreground text-sm">
                  Permissions assigned directly to this user, outside of roles.
                </p>
              </div>
              <Button
                type="button"
                onClick={saveDirectPermissions}
                disabled={savingPermissions}
                size="sm"
              >
                <Check className="size-4" />
                {savingPermissions ? "Saving..." : "Save permissions"}
              </Button>
            </div>
            <div className="mt-4">
              <PermissionPicker
                value={directPermissions}
                onChange={setDirectPermissions}
                compact
              />
            </div>
          </div>

          <PermissionPanel
            title="Effective permissions"
            description="Combined permissions from roles and direct grants."
            permissions={effectivePermissions}
            emptyText="No effective permissions"
          />
        </section>
      </div>
    </div>
  );
}

function PermissionPanel({
  title,
  description,
  permissions,
  emptyText,
}: {
  title: string;
  description: string;
  permissions: string[];
  emptyText: string;
}) {
  return (
    <div className="rounded-2xl border bg-card p-4 shadow-sm">
      <div className="flex flex-wrap items-start justify-between gap-2">
        <div>
          <h3 className="font-semibold text-base">{title}</h3>
          <p className="text-muted-foreground text-sm">{description}</p>
        </div>
        <Badge variant="secondary">{permissions.length}</Badge>
      </div>
      {permissions.length ? (
        <div className="mt-4 flex max-h-72 flex-wrap gap-2 overflow-y-auto">
          {permissions.map((permission) => (
            <Badge key={permission} variant="outline" className="font-mono">
              {permission}
            </Badge>
          ))}
        </div>
      ) : (
        <p className="mt-4 text-muted-foreground text-sm">{emptyText}</p>
      )}
    </div>
  );
}
