/*
 * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). All Rights Reserved.
 *
 * This software is the property of WSO2 LLC. and its suppliers, if any.
 * Dissemination of any information or reproduction of any material contained
 * herein in any form is strictly forbidden, unless permitted by WSO2 expressly.
 * You may not alter or remove any copyright or other notice from copies of this content.
 */

package org.wso2.carbon.is.migration.service.v700.service;

import org.wso2.carbon.identity.application.mgt.ApplicationConstants;
import org.wso2.carbon.identity.core.migrate.MigrationClientException;
import org.wso2.carbon.is.migration.internal.ISMigrationServiceDataHolder;
import org.wso2.carbon.is.migration.service.v700.dao.RoleV1DAO;
import org.wso2.carbon.is.migration.service.v700.dao.RoleV2DAO;
import org.wso2.carbon.is.migration.service.v700.model.RoleV2;
import org.wso2.carbon.is.migration.service.v700.util.Utils;
import org.wso2.carbon.is.migration.util.Utility;
import org.wso2.carbon.user.api.Tenant;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.core.UserCoreConstants;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class AssignInternalScopesForRolesService {

    private final RoleV2DAO roleV2DAO = new RoleV2DAO();
    private final RoleV1DAO roleV1DAO = new RoleV1DAO();

    public void execute() throws MigrationClientException {

        Set<Tenant> tenants = Utility.getTenants();
        Tenant superTenant = new Tenant();
        superTenant.setId(-1234);
        tenants.add(superTenant);
        Map<String, String> scopeBindingMap = Utils.loadOauthScopeBinding();
        String applicationRolePrefix = ApplicationConstants.APPLICATION_DOMAIN + UserCoreConstants.DOMAIN_SEPARATOR;
        if (scopeBindingMap == null) {
            throw new MigrationClientException("Error while loading scope binding file.");
        }
        for (Tenant tenant: tenants) {
            String adminRole;
            try {
                adminRole = ISMigrationServiceDataHolder.getRealmService().getTenantUserRealm(tenant.getId())
                        .getRealmConfiguration().getAdminRoleName().replace("Internal/", "");
            } catch (UserStoreException e) {
                throw new MigrationClientException("Error while retrieving default admin role of tenant: " + tenant.getId(), e);
            }

            // Process all the organization roles.
            List<RoleV2> roleV2List = roleV2DAO.getAllOrganizationAudienceRoles(tenant.getId());
            for (RoleV2 roleV2 : roleV2List) {
                // The default admin role scopes are not keep in the table.
                if (roleV2.getRoleName().equals(adminRole)) {
                    continue;
                }

                List<String> permissionsList;
                String roleName = roleV2.getRoleName();
                if (roleName.startsWith(applicationRolePrefix)) {
                    roleName = roleV2.getRoleName().split(applicationRolePrefix)[1];
                    permissionsList = roleV1DAO.getRolePermissionsApplicationRole(roleName, tenant.getId());
                } else {
                    permissionsList = roleV1DAO.getRolePermissions(roleName, tenant.getId());
                }
                if (permissionsList.size() == 0) {
                    continue;
                }
                List<String> scopesList = new ArrayList<>();
                for (Map.Entry<String, String> entry : scopeBindingMap.entrySet()) {
                    for (String permissionString : permissionsList) {
                        if (entry.getKey().startsWith(permissionString)) {
                            if (!scopesList.contains(entry.getValue())) {
                                scopesList.add(entry.getValue());
                            }
                        }
                    }
                }
                if (scopesList.isEmpty()) {
                    continue;
                }
                List<String> authorizedScopes = roleV2DAO.getAssignedScopesForRole(roleV2.getRoleUUID());
                List<String> scopesRequiredToRegister = scopesList.stream()
                        .filter(scope -> !authorizedScopes.contains(scope)).collect(Collectors.toList());
                roleV2DAO.assignInternalSystemScopesToRole(roleV2.getRoleUUID(), scopesRequiredToRegister);
            }
        }
    }
}
