import { PermissionKey, SystemRole } from "@capakraken/shared";
import type { ToolAccessRequirements, ToolContext, ToolDef } from "./shared.js";
import { AssistantVisibleError } from "./helpers.js";

export const CONTROLLER_ASSISTANT_ROLES = [
  SystemRole.ADMIN,
  SystemRole.MANAGER,
  SystemRole.CONTROLLER,
] as const;

export const LEGACY_MONOLITHIC_TOOL_ACCESS: Partial<Record<string, ToolAccessRequirements>> = {
  search_projects: { allowedSystemRoles: [...CONTROLLER_ASSISTANT_ROLES] },
  get_project: { allowedSystemRoles: [...CONTROLLER_ASSISTANT_ROLES] },
  update_project: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
  create_project: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
  delete_project: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
  generate_project_cover: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
  remove_project_cover: { requiredPermissions: [PermissionKey.MANAGE_PROJECTS] },
};

export type AssistantToolAccessEvaluationContext = Pick<ToolContext, "permissions" | "userRole">;

export type AssistantToolAccessFailure =
  | { type: "role" }
  | {
      type: "permission";
      permission?: PermissionKey;
      message?: string;
    };

function hasAssistantResourceOverviewAccess(permissions: Set<PermissionKey>): boolean {
  return (
    permissions.has(PermissionKey.VIEW_ALL_RESOURCES) ||
    permissions.has(PermissionKey.MANAGE_RESOURCES)
  );
}

export function getAssistantToolAccessRequirements(
  tool: ToolDef,
): ToolAccessRequirements | undefined {
  return tool.access ?? LEGACY_MONOLITHIC_TOOL_ACCESS[tool.function.name];
}

export function getAssistantToolAccessFailure(
  tool: ToolDef,
  ctx: AssistantToolAccessEvaluationContext,
): AssistantToolAccessFailure | null {
  const access = getAssistantToolAccessRequirements(tool);
  if (!access) {
    return null;
  }

  if (
    access.allowedSystemRoles &&
    !access.allowedSystemRoles.includes(ctx.userRole as SystemRole)
  ) {
    return { type: "role" };
  }

  const missingRequiredPermission = access.requiredPermissions?.find(
    (permission) => !ctx.permissions.has(permission),
  );
  if (missingRequiredPermission) {
    return {
      type: "permission",
      permission: missingRequiredPermission,
    };
  }

  if (access.requiresPlanningRead && !ctx.permissions.has(PermissionKey.VIEW_PLANNING)) {
    return {
      type: "permission",
      permission: PermissionKey.VIEW_PLANNING,
    };
  }

  if (access.requiresCostView && !ctx.permissions.has(PermissionKey.VIEW_COSTS)) {
    return {
      type: "permission",
      permission: PermissionKey.VIEW_COSTS,
    };
  }

  if (
    access.requiresAdvancedAssistant &&
    !ctx.permissions.has(PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS)
  ) {
    return {
      type: "permission",
      permission: PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS,
    };
  }

  if (access.requiresResourceOverview && !hasAssistantResourceOverviewAccess(ctx.permissions)) {
    return {
      type: "permission",
      message: "Permission denied: you need resource overview access to perform this action.",
    };
  }

  return null;
}

export function toAssistantToolAccessError(
  failure: AssistantToolAccessFailure,
): AssistantVisibleError {
  if (failure.type === "role") {
    return new AssistantVisibleError("You do not have permission to perform this action.");
  }

  if (failure.permission) {
    return new AssistantVisibleError(
      `Permission denied: you need the "${failure.permission}" permission to perform this action.`,
    );
  }

  return new AssistantVisibleError(
    failure.message ?? "You do not have permission to perform this action.",
  );
}

export function canAccessAssistantTool(
  tool: ToolDef,
  ctx: AssistantToolAccessEvaluationContext,
): boolean {
  return getAssistantToolAccessFailure(tool, ctx) === null;
}

export function getAvailableAssistantToolsForContext(
  allTools: ToolDef[],
  permissions: Set<PermissionKey>,
  userRole: string,
): ToolDef[] {
  return allTools.filter((tool) => canAccessAssistantTool(tool, { permissions, userRole }));
}
