const { roleAllows } = require("./permissions");

const ROLE_RANK = Object.freeze({ user: 1, mod: 2, admin: 3 });
const FORBIDDEN_DEFINITION_KEYS = Object.freeze([
  "shell",
  "sql",
  "filesystem",
  "network",
  "code_execution",
  "eval"
]);

function registerManagedTool(registry, metadata, definition) {
  validateManagedDefinition(metadata, definition);
  const metadataRole = metadataRequiredRole(metadata.permissions);
  const backendRole = normalizeRole(definition.required_role);
  const requiredRole = stricterRole(metadataRole, backendRole);
  const backendPermissionCheck = definition.permission_check;
  const promptPermissionCheck = definition.prompt_permission_check;
  const mutating = definition.mutating === true ||
    ["sensitive", "high", "destructive"].includes(String(definition.risk_level || metadata.risk_level || "").toLowerCase());
  return registry.register({
    ...definition,
    owning_plugin: metadata.tool_id,
    required_role: requiredRole,
    required_permission: String(definition.required_permission || `${metadata.tool_id}.use`),
    audit_category: String(definition.audit_category || metadata.tool_type || "ai_tool"),
    read_only: definition.read_only === true,
    use_cases: normalizeTextArray(definition.use_cases || metadata.capabilities),
    output_expectations: String(definition.output_expectations || metadata.output_expectations || ""),
    confirmation_required: mutating || metadata.confirmation_required === true
      ? true
      : definition.confirmation_required !== false,
    permission_check: (input) => {
      const actualRole = input.user?.isAdmin ? "admin" : input.user?.isMod ? "mod" : "user";
      if (!roleAllows(actualRole, requiredRole)) return false;
      return backendPermissionCheck(input) === true;
    },
    prompt_permission_check: typeof promptPermissionCheck === "function"
      ? (input) => promptPermissionCheck(input) === true
      : undefined
  });
}

function normalizeTextArray(value) {
  return Array.isArray(value) ? value.map(String).map((entry) => entry.trim()).filter(Boolean) : [];
}

function validateManagedDefinition(metadata, definition) {
  if (!definition || typeof definition !== "object") throw new Error("AI tool definition is required.");
  const namespace = String(metadata.tool_namespace || metadata.tool_id);
  if (!/^[a-z][a-z0-9_-]*$/i.test(namespace)) throw new Error("AI tool namespace is invalid.");
  if (!String(definition.tool_id || "").startsWith(`${namespace}.`)) {
    throw new Error(`Registered tool IDs must use the ${namespace}. namespace.`);
  }
  if (typeof definition.permission_check !== "function" || typeof definition.workflow_handler !== "function") {
    throw new Error("Managed AI tools require backend permission and workflow handlers.");
  }
  for (const key of FORBIDDEN_DEFINITION_KEYS) {
    if (definition[key] != null) throw new Error(`Managed AI tools cannot request generic ${key} access.`);
  }
}

function metadataRequiredRole(permissions) {
  if (typeof permissions === "string") return normalizeRole(permissions);
  if (Array.isArray(permissions)) {
    return permissions.map(normalizeRole).sort((a, b) => ROLE_RANK[b] - ROLE_RANK[a])[0] || "user";
  }
  return normalizeRole(permissions?.required_role || permissions?.role);
}

function normalizeRole(value) {
  return Object.hasOwn(ROLE_RANK, value) ? value : "user";
}

function stricterRole(left, right) {
  return ROLE_RANK[left] >= ROLE_RANK[right] ? left : right;
}

module.exports = {
  FORBIDDEN_DEFINITION_KEYS,
  registerManagedTool,
  validateManagedDefinition,
  metadataRequiredRole,
  stricterRole
};
