import { useState } from "react";
import { ActionPanel, Button, Dialog, useNavigate } from "@tailor-platform/app-shell";
import { useMutation, useQuery } from "urql";
import { Pencil, UserX, UserCheck, ShieldPlus, ArrowLeft } from "lucide-react";
import { graphql, type FragmentOf, readFragment } from "@/graphql";
import { useToast } from "@/hooks/use-toast";

const DeactivateUserMutation = graphql(`
  mutation DeactivateUser($userId: String!) {
    deactivateUser(userId: $userId) {
      id
      status
    }
  }
`);

const ReactivateUserMutation = graphql(`
  mutation ReactivateUser($userId: String!) {
    reactivateUser(userId: $userId) {
      id
      status
    }
  }
`);

const AssignRoleToUserMutation = graphql(`
  mutation AssignRoleToUserAction($userId: String!, $roleId: String!) {
    assignRoleToUser(userId: $userId, roleId: $roleId) {
      userId
      roleId
    }
  }
`);

const RolesForAssignQuery = graphql(`
  query RolesForAssign {
    roles {
      edges {
        node {
          id
          name
        }
      }
    }
  }
`);

const MeForActionsQuery = graphql(`
  query MeForActions {
    me {
      id
    }
  }
`);

export const UserActionsFragment = graphql(`
  fragment UserActions on User {
    id
    status
  }
`);

interface UserActionsProps {
  user: FragmentOf<typeof UserActionsFragment>;
}

export const UserActions = ({ user: userFragment }: UserActionsProps) => {
  const user = readFragment(UserActionsFragment, userFragment);
  const navigate = useNavigate();
  const toast = useToast();
  const [{ fetching: deactivating }, deactivateUser] = useMutation(DeactivateUserMutation);
  const [{ fetching: reactivating }, reactivateUser] = useMutation(ReactivateUserMutation);
  const [{ fetching: assigning }, assignRole] = useMutation(AssignRoleToUserMutation);
  const [{ data: rolesData }] = useQuery({ query: RolesForAssignQuery });
  const [{ data: meData }] = useQuery({ query: MeForActionsQuery });
  const [dialogOpen, setDialogOpen] = useState(false);
  const [selectedRoleIds, setSelectedRoleIds] = useState<Set<string>>(() => new Set());

  const roles = rolesData?.roles.edges.map((edge) => edge.node) ?? [];
  const isSelf = meData?.me?.id === user.id;

  const toggleRole = (id: string) => {
    setSelectedRoleIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const handleAssignRoles = () => {
    if (selectedRoleIds.size === 0) return;
    const selected = roles.filter((r) => selectedRoleIds.has(r.id));
    void Promise.all(
      selected.map((role) =>
        assignRole(
          { userId: user.id, roleId: role.id },
          { additionalTypenames: ["User", "UserRole"] },
        ),
      ),
    ).then((results) => {
      const failed = results.filter((r) => r.error);
      if (failed.length > 0) {
        toast.error(failed[0].error!);
        return;
      }
      const names = selected.map((r) => r.name).join(", ");
      toast.success(`Roles assigned: ${names}`);
      setDialogOpen(false);
      setSelectedRoleIds(new Set());
    });
  };

  return (
    <>
      <ActionPanel
        title="Actions"
        actions={[
          {
            key: "edit",
            label: "Edit User",
            icon: <Pencil />,
            onClick: () => navigate("edit"),
          },
          ...(user.status === "ACTIVE" && !isSelf
            ? [
                {
                  key: "deactivate",
                  label: "Deactivate User",
                  icon: <UserX />,
                  loading: deactivating,
                  onClick: () =>
                    deactivateUser({ userId: user.id }, { additionalTypenames: ["User"] }).then(
                      (result) => {
                        if (result.error) {
                          toast.error(result.error);
                          return;
                        }
                        toast.success("User deactivated successfully");
                      },
                    ),
                },
              ]
            : []),
          ...(user.status === "INACTIVE"
            ? [
                {
                  key: "reactivate",
                  label: "Reactivate User",
                  icon: <UserCheck />,
                  loading: reactivating,
                  onClick: () =>
                    reactivateUser({ userId: user.id }, { additionalTypenames: ["User"] }).then(
                      (result) => {
                        if (result.error) {
                          toast.error(result.error);
                          return;
                        }
                        toast.success("User reactivated successfully");
                      },
                    ),
                },
              ]
            : []),
          {
            key: "assign-role",
            label: "Assign Role",
            icon: <ShieldPlus />,
            onClick: () => setDialogOpen(true),
          },
          {
            key: "back",
            label: "Back to User List",
            icon: <ArrowLeft />,
            onClick: () => navigate("/user-management/user"),
          },
        ]}
      />
      <Dialog.Root open={dialogOpen} onOpenChange={setDialogOpen}>
        <Dialog.Content>
          <Dialog.Header>
            <Dialog.Title>Assign Roles</Dialog.Title>
            <Dialog.Description>Select roles to assign to this user.</Dialog.Description>
          </Dialog.Header>
          <div className="max-h-60 space-y-1 overflow-y-auto py-4">
            {roles.map((role) => (
              <label
                key={role.id}
                className="flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 hover:bg-accent"
              >
                <input
                  type="checkbox"
                  checked={selectedRoleIds.has(role.id)}
                  onChange={() => toggleRole(role.id)}
                  className="h-4 w-4 rounded border-gray-300"
                />
                <span className="text-sm">{role.name}</span>
              </label>
            ))}
            {roles.length === 0 && (
              <p className="text-muted-foreground text-sm">No roles available</p>
            )}
          </div>
          <Dialog.Footer>
            <Button variant="outline" onClick={() => setDialogOpen(false)}>
              Cancel
            </Button>
            <Button onClick={handleAssignRoles} disabled={selectedRoleIds.size === 0 || assigning}>
              Assign
            </Button>
          </Dialog.Footer>
        </Dialog.Content>
      </Dialog.Root>
    </>
  );
};
