export function defaultPermissionSelection(catalog) {
    return catalog
        .filter((permission) => permission.defaultGranted)
        .reduce(
            (selected, permission) => updatePermissionSelection(catalog, selected, permission.code, true),
            [],
        );
}

export function updatePermissionSelection(catalog, current, code, checked) {
    const permissionMap = new Map(catalog.map((permission) => [permission.code, permission]));
    const selected = new Set(current.filter((permissionCode) => permissionMap.has(permissionCode)));

    if (checked) {
        // 目录依赖由后端维护；勾选业务动作时递归补齐前置能力，保证提交的是可执行权限快照。
        addWithDependencies(code, permissionMap, selected, new Set());
    } else {
        selected.delete(code);
        // 取消前置能力后同步移除所有失去依赖的动作，避免保存一个界面无法真实使用的组合。
        removeBrokenDependents(permissionMap, selected);
    }

    return catalog.map((permission) => permission.code).filter((permissionCode) => selected.has(permissionCode));
}

export function updatePermissionGroup(catalog, current, groupCodes, checked) {
    return groupCodes.reduce(
        (next, code) => updatePermissionSelection(catalog, next, code, checked),
        current,
    );
}

function addWithDependencies(code, permissionMap, selected, visiting) {
    if (!permissionMap.has(code) || visiting.has(code)) {
        return;
    }
    visiting.add(code);
    const permission = permissionMap.get(code);
    (permission.dependencies || []).forEach((dependency) =>
        addWithDependencies(dependency, permissionMap, selected, visiting),
    );
    selected.add(code);
    visiting.delete(code);
}

function removeBrokenDependents(permissionMap, selected) {
    let changed = true;
    while (changed) {
        changed = false;
        selected.forEach((code) => {
            const dependencies = permissionMap.get(code)?.dependencies || [];
            if (dependencies.some((dependency) => !selected.has(dependency))) {
                selected.delete(code);
                changed = true;
            }
        });
    }
}
