/*
 * 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.dao;

import org.json.JSONObject;
import org.wso2.carbon.identity.application.common.model.Scope;
import org.wso2.carbon.identity.core.migrate.MigrationClientException;
import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.user.core.UserCoreConstants;
import org.wso2.carbon.user.core.util.UserCoreUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class OAuth2ScopeDAO {

    private static final String GET_OAUTH2_SCOPES = "SELECT IDN_OAUTH2_SCOPE.SCOPE_ID, NAME, DISPLAY_NAME, " +
            "DESCRIPTION FROM IDN_OAUTH2_SCOPE INNER JOIN IDN_OAUTH2_SCOPE_BINDING " +
            "ON IDN_OAUTH2_SCOPE.SCOPE_ID = IDN_OAUTH2_SCOPE_BINDING.SCOPE_ID WHERE SCOPE_TYPE = 'OAUTH2' AND " +
            "BINDING_TYPE = 'DEFAULT' AND TENANT_ID = ?";
    private static final String GET_SCOPE_BINDINGS = "SELECT IOS.NAME, IOSB.SCOPE_BINDING FROM IDN_OAUTH2_SCOPE IOS " +
            "INNER JOIN IDN_OAUTH2_SCOPE_BINDING IOSB ON IOS.SCOPE_ID = IOSB.SCOPE_ID WHERE TENANT_ID = ?";

    /**
     * Get OAuth2 scopes.
     *
     * @param tenantId Tenant ID.
     * @return List of OAuth2 scopes.
     * @throws MigrationClientException If an error occurs while retrieving OAuth2 scopes.
     */
    public List<Scope> getOAuth2Scopes(int tenantId) throws MigrationClientException {

        try (Connection connection = IdentityDatabaseUtil.getDBConnection(false)) {
            try (PreparedStatement preparedStatement = connection.prepareStatement(GET_OAUTH2_SCOPES)) {
                preparedStatement.setInt(1, tenantId);
                try (ResultSet resultSet = preparedStatement.executeQuery()) {
                    List<Scope> scopes = new ArrayList<>();
                    List<String> uniqueOAuth2ScopeNames = new ArrayList<>();
                    while (resultSet.next()) {
                        Scope scope = new Scope.ScopeBuilder()
                                .id(resultSet.getString("SCOPE_ID"))
                                .name(resultSet.getString("NAME"))
                                .displayName(resultSet.getString("DISPLAY_NAME"))
                                .description(resultSet.getString("DESCRIPTION"))
                                .build();
                        if (!uniqueOAuth2ScopeNames.contains(scope.getName())) {
                            scopes.add(scope);
                            uniqueOAuth2ScopeNames.add(scope.getName());
                        }
                    }
                    return scopes;
                }
            }
        } catch (SQLException e) {
            throw new MigrationClientException("Error while retrieving OAuth2 scopes.", e);
        }
    }

    /**
     * Get scope bindings.
     *
     * @param tenantId Tenant ID.
     * @return Map of roles with their scope bindings.
     * @throws MigrationClientException If an error occurs while retrieving scope bindings.
     */
    public Map<String, List<String>> getScopeBindings(int tenantId) throws MigrationClientException {

        try (Connection connection = IdentityDatabaseUtil.getDBConnection(false);
             PreparedStatement preparedStatement = connection.prepareStatement(GET_SCOPE_BINDINGS)) {
            preparedStatement.setInt(1, tenantId);
            ResultSet resultSet = preparedStatement.executeQuery();
            Map<String, List<String>> scopeBindings = new HashMap<>();
            while (resultSet.next()) {
                String scopeName = resultSet.getString("NAME");
                String roleName = removeInternalDomain(resultSet.getString("SCOPE_BINDING"));
                if (scopeBindings.containsKey(roleName)) {
                    scopeBindings.get(roleName).add(scopeName);
                } else {
                    List<String> scopes = new ArrayList<>();
                    scopes.add(scopeName);
                    scopeBindings.put(roleName, scopes);
                }
            }
            return scopeBindings;
        } catch (SQLException e) {
            throw new MigrationClientException("Error while retrieving scope bindings.", e);
        }
    }

    private String removeInternalDomain(String roleName) {

        if (UserCoreConstants.INTERNAL_DOMAIN.equalsIgnoreCase(IdentityUtil.extractDomainFromName(roleName))) {
            return UserCoreUtil.removeDomainFromName(roleName);
        }
        return roleName;
    }
}
