/*
 * 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.wso2.carbon.database.utils.jdbc.NamedJdbcTemplate;
import org.wso2.carbon.database.utils.jdbc.exceptions.DataAccessException;
import org.wso2.carbon.database.utils.jdbc.exceptions.TransactionException;
import org.wso2.carbon.identity.core.migrate.MigrationClientException;

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

import static org.wso2.carbon.is.migration.service.v700.util.Utils.getNewTemplateForSharedDB;

public class RoleV1DAO {

    private static final String GET_V1_ROLES = "SELECT UM_ROLE_NAME FROM UM_HYBRID_ROLE WHERE UM_TENANT_ID = ? AND " +
            "UM_AUDIENCE_REF_ID = -1";
    private static final String GET_ROLE_ID_BY_NAME = "SELECT UM_ID FROM UM_HYBRID_ROLE WHERE UM_ROLE_NAME = ? AND " +
            "UM_TENANT_ID = ?";
    private static final String GET_PERMISSIONS_OF_ROLE = "SELECT DISTINCT UM_RESOURCE_ID FROM UM_HYBRID_ROLE " +
            "INNER JOIN UM_ROLE_PERMISSION ON UM_HYBRID_ROLE.UM_ROLE_NAME = UM_ROLE_PERMISSION.UM_ROLE_NAME " +
            "INNER JOIN UM_PERMISSION ON UM_ROLE_PERMISSION.UM_PERMISSION_ID = UM_PERMISSION.UM_ID " +
            "WHERE UM_HYBRID_ROLE.UM_TENANT_ID = UM_ROLE_PERMISSION.UM_TENANT_ID AND UM_HYBRID_ROLE.UM_ROLE_NAME = ?" +
            " AND UM_HYBRID_ROLE.UM_TENANT_ID = ? AND UM_PERMISSION.UM_RESOURCE_ID != '/'";
    private static final String GET_PERMISSIONS_OF_APPLICATION_ROLE = "SELECT DISTINCT UM_RESOURCE_ID FROM UM_ROLE_PERMISSION " +
            "INNER JOIN UM_PERMISSION ON UM_ROLE_PERMISSION.UM_PERMISSION_ID = UM_PERMISSION.UM_ID INNER JOIN UM_DOMAIN " +
            "ON UM_ROLE_PERMISSION.UM_DOMAIN_ID = UM_DOMAIN.UM_DOMAIN_ID WHERE UM_ROLE_PERMISSION.UM_TENANT_ID = ? AND " +
            "UM_ROLE_NAME = ? and UM_DOMAIN.UM_DOMAIN_NAME = 'APPLICATION' AND UM_PERMISSION.UM_RESOURCE_ID != '/' ";

    /**
     * Get V1 roles.
     *
     * @param tenantId tenant id.
     * @return list of roles.
     * @throws MigrationClientException if error occurred while retrieving roles.
     */
    public List<String> getV1Roles(Connection connection, int tenantId) throws MigrationClientException {

        List<String> roles = new ArrayList<>();
        try (PreparedStatement prepStmt = connection.prepareStatement(GET_V1_ROLES)) {
            prepStmt.setInt(1, tenantId);
            ResultSet resultSet = prepStmt.executeQuery();
            while (resultSet.next()) {
                roles.add(resultSet.getString("UM_ROLE_NAME"));
            }
        } catch (SQLException e) {
            throw new MigrationClientException("Error while retrieving roles", e);
        }
        return roles;
    }

    public String getRoleIDByName(String roleName, int tenantId) throws MigrationClientException {

        NamedJdbcTemplate namedJdbcTemplate = getNewTemplateForSharedDB();
        try {
            return namedJdbcTemplate.fetchSingleRecord(GET_ROLE_ID_BY_NAME,
                    (resultSet, rowNumber) -> resultSet.getString("UM_ID"),
                    namedPreparedStatement -> {
                        namedPreparedStatement.setString(1, roleName);
                        namedPreparedStatement.setInt(2, tenantId);
                    });
        } catch (DataAccessException e) {
            throw new MigrationClientException("Error while retrieving role id.", e);
        }
    }

    public List<String> getRolePermissions(String roleName, int tenantID) throws MigrationClientException {

        NamedJdbcTemplate namedJdbcTemplate = getNewTemplateForSharedDB();
        try {
            return namedJdbcTemplate.withTransaction(template -> template.executeQuery(GET_PERMISSIONS_OF_ROLE,
                    (resultSet, rowNumber) -> resultSet.getString(1),
                    namedPreparedStatement -> {
                        namedPreparedStatement.setString(1, roleName);
                        namedPreparedStatement.setInt(2, tenantID);
                    }));
        } catch (TransactionException e) {
            throw new MigrationClientException("Error while retrieving all the permissions of the role.", e);
        }
    }

    /**
     * Get the permission list of the previous application roles.
     *
     * @param applicationRole The application role name.
     * @param tenantID        The tenant ID.
     * @return List of permissions.
     * @throws MigrationClientException
     */
    public List<String> getRolePermissionsApplicationRole(String applicationRole, int tenantID)
            throws MigrationClientException {

        NamedJdbcTemplate namedJdbcTemplate = getNewTemplateForSharedDB();
        try {
            return namedJdbcTemplate.withTransaction(
                    template -> template.executeQuery(GET_PERMISSIONS_OF_APPLICATION_ROLE,
                            (resultSet, rowNumber) -> resultSet.getString(1),
                            namedPreparedStatement -> {
                                namedPreparedStatement.setInt(1, tenantID);
                                namedPreparedStatement.setString(2, applicationRole);
                            }));
        } catch (TransactionException e) {
            throw new MigrationClientException("Error while retrieving all the permissions of the application role.",
                    e);
        }
    }
}
