"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveSpaceAccess = void 0;
const space_1 = require("../../types/space");
const projectMemberRole_1 = require("../../utils/projectMemberRole");
const getUserOrganizationRole = (organizationAccess, userUuid) => {
    const userOrgAccess = organizationAccess.filter((a) => a.userUuid === userUuid);
    return {
        type: 'organization',
        role: userOrgAccess.length > 0
            ? (0, projectMemberRole_1.convertOrganizationRoleToProjectRole)(userOrgAccess[0].role)
            : undefined,
    };
};
const getUserProjectRole = (projectAccess, userUuid) => {
    const userProjectAccess = projectAccess.filter((a) => a.userUuid === userUuid &&
        a.from === space_1.ProjectSpaceAccessOrigin.PROJECT_MEMBERSHIP);
    return {
        type: 'project',
        role: userProjectAccess.length > 0
            ? userProjectAccess[0].role
            : undefined,
    };
};
const getUserProjectGroupRoles = (projectAccess, userUuid) => {
    const userProjectGroups = projectAccess.filter((a) => a.userUuid === userUuid &&
        a.from === space_1.ProjectSpaceAccessOrigin.GROUP_MEMBERSHIP);
    return userProjectGroups.map((entry) => ({
        type: 'group',
        role: entry.role,
    }));
};
const getUserDirectGroupAccess = (directAccess, userUuid) => {
    const userDirectGroups = directAccess.filter((a) => a.userUuid === userUuid &&
        a.from === space_1.DirectSpaceAccessOrigin.GROUP_ACCESS);
    return userDirectGroups.map((entry) => ({
        type: 'space_group',
        role: (0, projectMemberRole_1.convertSpaceRoleToProjectRole)(entry.role),
    }));
};
const getSpaceRole = (highestProjectRole, userUuid, chainDirectAccess, leafSpaceUuid, inheritsFromOrgOrProject) => {
    // Collect all direct access entries for this user across the entire chain
    const allUserEntries = [];
    for (const chainLevel of chainDirectAccess) {
        for (const access of chainLevel.directAccess) {
            if (access.userUuid === userUuid) {
                allUserEntries.push({
                    role: access.role,
                    spaceUuid: chainLevel.spaceUuid,
                });
            }
        }
    }
    if (allUserEntries.length > 0) {
        // Most permissive wins: highest role across all chain levels, all origins
        const highestDirectRole = (0, projectMemberRole_1.getHighestSpaceRole)(allUserEntries.map((e) => e.role));
        if (!highestDirectRole)
            return undefined;
        // Check if the winning role came from a parent space (not the leaf)
        const winningEntry = allUserEntries.find((e) => e.role === highestDirectRole);
        const fromParent = winningEntry?.spaceUuid !== leafSpaceUuid;
        return { role: highestDirectRole, fromParent };
    }
    // No direct access anywhere in chain — fall through to project/org inheritance
    if (inheritsFromOrgOrProject) {
        return {
            role: (0, projectMemberRole_1.convertProjectRoleToSpaceRole)(highestProjectRole),
            fromParent: false, // not from a parent space — access is from org/project level
        };
    }
    return undefined;
};
const resolveUserSpaceAccess = (userUuid, input) => {
    const { spaceUuid, inheritsFromOrgOrProject, chainDirectAccess, projectAccess, organizationAccess, } = input;
    // Step 1: Compute highest project-level role (same as existing logic)
    const organizationRole = getUserOrganizationRole(organizationAccess, userUuid);
    const projectRole = getUserProjectRole(projectAccess, userUuid);
    const groupRoles = getUserProjectGroupRoles(projectAccess, userUuid);
    // Flatten all direct access for group role computation at project level
    const allDirectAccess = chainDirectAccess.flatMap((c) => c.directAccess);
    const spaceGroupAccessRoles = getUserDirectGroupAccess(allDirectAccess, userUuid);
    const highestRole = (0, projectMemberRole_1.getHighestProjectRole)([
        organizationRole,
        projectRole,
        ...groupRoles,
        ...spaceGroupAccessRoles,
    ]);
    if (!highestRole)
        return undefined;
    // Step 2: Compute effective space role using "most permissive wins"
    const spaceRoleResult = getSpaceRole(highestRole.role, userUuid, chainDirectAccess, spaceUuid, inheritsFromOrgOrProject);
    if (!spaceRoleResult)
        return undefined;
    // Step 3: Determine hasDirectAccess (leaf space only)
    const leafLevel = chainDirectAccess.find((c) => c.spaceUuid === spaceUuid);
    const hasDirectAccess = leafLevel
        ? leafLevel.directAccess.some((a) => a.userUuid === userUuid)
        : false;
    // Step 4: Compute projectRole metadata (org + direct project only)
    const highestProjectRole = (0, projectMemberRole_1.getHighestProjectRole)([
        organizationRole,
        projectRole,
    ]);
    // Step 5: Determine inheritedFrom — use chain-wide check (not leaf-only)
    const hasAccessInChain = allDirectAccess.some((a) => a.userUuid === userUuid);
    const inheritedFrom = hasAccessInChain && spaceRoleResult.fromParent
        ? 'parent_space'
        : highestRole.type;
    return {
        userUuid,
        role: spaceRoleResult.role,
        hasDirectAccess,
        inheritedRole: highestRole.role,
        inheritedFrom,
        projectRole: highestProjectRole?.role,
    };
};
const resolveSpaceAccess = (input) => {
    const { chainDirectAccess, projectAccess, organizationAccess } = input;
    const allDirectAccess = chainDirectAccess.flatMap((c) => c.directAccess);
    // Collect all unique user UUIDs
    const uniqueUserUuids = new Set([...allDirectAccess, ...projectAccess, ...organizationAccess].map((e) => e.userUuid));
    return Array.from(uniqueUserUuids)
        .map((userUuid) => resolveUserSpaceAccess(userUuid, input))
        .filter((share) => share !== undefined);
};
exports.resolveSpaceAccess = resolveSpaceAccess;
//# sourceMappingURL=spaceAccessResolver.js.map