"use client";

import { ReactElement, ReactNode, cloneElement, isValidElement } from "react";
import { toast } from "sonner";
import { RBAC_UNAUTHORIZED_MESSAGE_AR } from "@/lib/rbac/constants";
import { useResolvedAction } from "@/hooks/use-actions";
import type { ActionKey, ActionMode, ActionRequire, ActionSurface } from "@/lib/rbac/action-access";

type PermissionGateProps = {
  actionKey?: ActionKey;
  permissions?: string | string[];
  require?: ActionRequire;
  mode?: ActionMode;
  message?: string;
  roleAliases?: string[];
  surface?: ActionSurface;
  children: ReactNode;
  fallback?: ReactNode;
};

function asArray(value?: string | string[]): string[] {
  if (!value) {
    return [];
  }

  return Array.isArray(value) ? value : [value];
}

export function PermissionGate({
  actionKey,
  permissions,
  require = "any",
  mode = "hide",
  message = RBAC_UNAUTHORIZED_MESSAGE_AR,
  roleAliases,
  surface,
  children,
  fallback = null,
}: PermissionGateProps) {
  const resolvedAction = useResolvedAction(
    {
      actionKey,
      permissions: asArray(permissions).filter(Boolean),
      require,
      mode,
      message,
      roleAliases,
      surface,
    },
    surface,
  );

  const allowed = resolvedAction.allowed;

  if (allowed) {
    return <>{children}</>;
  }

  if (resolvedAction.hidden) {
    return <>{fallback}</>;
  }

  const handleBlockedClick = (event: React.MouseEvent) => {
    event.preventDefault();
    event.stopPropagation();
    toast.error(resolvedAction.message);
  };

  if (isValidElement(children)) {
    const child = children as ReactElement<Record<string, unknown>>;
    const props: Record<string, unknown> = {
      ...child.props,
      onClick: handleBlockedClick,
      onSelect: handleBlockedClick,
      title: resolvedAction.message,
      "aria-disabled": true,
      className: [child.props.className, "opacity-60"].filter(Boolean).join(" "),
    };

    if ("disabled" in child.props && child.props.disabled) {
      props.disabled = true;
    }

    return cloneElement(child, props);
  }

  return (
    <span className="opacity-60 cursor-not-allowed" title={resolvedAction.message} onClick={handleBlockedClick}>
      {children}
    </span>
  );
}
