"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RdsModelResourceGenerator = void 0;
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_sns_1 = require("aws-cdk-lib/aws-sns");
const aws_sns_subscriptions_1 = require("aws-cdk-lib/aws-sns-subscriptions");
const graphql_transformer_core_1 = require("@aws-amplify/graphql-transformer-core");
const graphql_transformer_interfaces_1 = require("@aws-amplify/graphql-transformer-interfaces");
const graphql_transformer_common_1 = require("graphql-transformer-common");
const resolvers_1 = require("../resolvers");
const rds_1 = require("../resolvers/rds");
const model_resource_generator_1 = require("./model-resource-generator");
class RdsModelResourceGenerator extends model_resource_generator_1.ModelResourceGenerator {
    constructor() {
        super(...arguments);
        this.generatorType = 'RdsModelResourceGenerator';
        this.generateDataSourceAndResourcesForStrategy = (context, strategy) => {
            const resourceNames = (0, graphql_transformer_core_1.getResourceNamesForStrategy)(strategy);
            const dbType = strategy.dbType;
            const engine = (0, graphql_transformer_core_1.getImportedRDSTypeFromStrategyDbType)(dbType);
            const dbConnectionConfig = strategy.dbConnectionConfig;
            const secretEntry = strategy.dbConnectionConfig;
            const { AmplifySQLLayerNotificationTopicAccount, AmplifySQLLayerNotificationTopicName } = graphql_transformer_common_1.ResourceConstants.RESOURCES;
            const lambdaRoleScope = context.stackManager.getScopeFor(resourceNames.sqlLambdaExecutionRole, resourceNames.sqlStack);
            const lambdaScope = context.stackManager.getScopeFor(resourceNames.sqlLambdaFunction, resourceNames.sqlStack);
            const layerVersionArn = resolveLayerVersion(lambdaScope, context, resourceNames);
            const role = (0, rds_1.createRdsLambdaRole)(context.resourceHelper.generateIAMRoleName(resourceNames.sqlLambdaExecutionRole), lambdaRoleScope, dbConnectionConfig, resourceNames);
            const environment = {
                engine,
            };
            let credentialStorageMethod;
            if ((0, graphql_transformer_interfaces_1.isSqlModelDataSourceSsmDbConnectionConfig)(secretEntry)) {
                environment.CREDENTIAL_STORAGE_METHOD = 'SSM';
                environment.username = secretEntry.usernameSsmPath;
                environment.password = secretEntry.passwordSsmPath;
                environment.host = secretEntry.hostnameSsmPath;
                environment.port = secretEntry.portSsmPath;
                environment.database = secretEntry.databaseNameSsmPath;
                credentialStorageMethod = rds_1.CredentialStorageMethod.SSM;
            }
            else if ((0, graphql_transformer_interfaces_1.isSqlModelDataSourceSecretsManagerDbConnectionConfig)(secretEntry)) {
                environment.CREDENTIAL_STORAGE_METHOD = 'SECRETS_MANAGER';
                environment.secretArn = secretEntry.secretArn;
                environment.port = secretEntry.port.toString();
                environment.database = secretEntry.databaseName;
                environment.host = secretEntry.hostname;
                credentialStorageMethod = rds_1.CredentialStorageMethod.SECRETS_MANAGER;
            }
            const lambda = (0, rds_1.createRdsLambda)(lambdaScope, context.api, role, layerVersionArn, resourceNames, credentialStorageMethod, environment, strategy.vpcConfiguration, strategy.sqlLambdaProvisionedConcurrencyConfig);
            const patchingLambdaRoleScope = context.stackManager.getScopeFor(resourceNames.sqlPatchingLambdaExecutionRole, resourceNames.sqlStack);
            const patchingLambdaRole = (0, rds_1.createRdsPatchingLambdaRole)(context.resourceHelper.generateIAMRoleName(resourceNames.sqlPatchingLambdaExecutionRole), patchingLambdaRoleScope, lambda.functionArn, resourceNames);
            const patchingLambdaScope = context.stackManager.getScopeFor(resourceNames.sqlPatchingLambdaFunction, resourceNames.sqlStack);
            const patchingLambda = (0, rds_1.createRdsPatchingLambda)(patchingLambdaScope, context.api, patchingLambdaRole, resourceNames, {
                LAMBDA_FUNCTION_ARN: lambda.functionArn,
            });
            const topicArn = aws_cdk_lib_1.Fn.join(':', [
                'arn',
                'aws',
                'sns',
                aws_cdk_lib_1.Fn.ref('AWS::Region'),
                AmplifySQLLayerNotificationTopicAccount,
                AmplifySQLLayerNotificationTopicName,
            ]);
            const patchingSubscriptionScope = context.stackManager.getScopeFor(resourceNames.sqlPatchingSubscription, resourceNames.sqlStack);
            const snsTopic = aws_sns_1.Topic.fromTopicArn(patchingSubscriptionScope, resourceNames.sqlPatchingTopic, topicArn);
            const subscription = new aws_sns_subscriptions_1.LambdaSubscription(patchingLambda, {
                filterPolicy: {
                    Region: aws_sns_1.SubscriptionFilter.stringFilter({
                        allowlist: [aws_cdk_lib_1.Fn.ref('AWS::Region')],
                    }),
                },
            });
            snsTopic.addSubscription(subscription);
            const lambdaDataSourceScope = context.stackManager.getScopeFor(resourceNames.sqlLambdaDataSource, resourceNames.sqlStack);
            const sqlDatasource = context.api.host.addLambdaDataSource(resourceNames.sqlLambdaDataSource, lambda, {}, lambdaDataSourceScope);
            return sqlDatasource;
        };
    }
    generateResources(context, strategyOverride) {
        var _a, _b;
        if (!this.isEnabled()) {
            this.generateResolvers(context);
            this.setFieldMappingResolverReferences(context);
            return;
        }
        const strategies = {};
        if (strategyOverride) {
            strategies[strategyOverride.name] = strategyOverride;
        }
        else {
            const dataSourceStrategies = Object.values(context.dataSourceStrategies).filter(graphql_transformer_core_1.isSqlStrategy);
            dataSourceStrategies.forEach((strategy) => (strategies[strategy.name] = strategy));
            const sqlDirectiveDataSourceStrategies = (_b = (_a = context.sqlDirectiveDataSourceStrategies) === null || _a === void 0 ? void 0 : _a.map((dss) => dss.strategy)) !== null && _b !== void 0 ? _b : [];
            sqlDirectiveDataSourceStrategies.forEach((strategy) => (strategies[strategy.name] = strategy));
        }
        if (Object.keys(strategies).length === 0) {
            throw new Error('No SQL datasource types are detected. This is an unexpected error.');
        }
        const modelStrategyMatches = (model, strategyName) => {
            const strategyFromContext = context.dataSourceStrategies[model.name.value];
            if ((0, graphql_transformer_core_1.isSqlStrategy)(strategyFromContext)) {
                return strategyFromContext.name === strategyName;
            }
            else {
                return false;
            }
        };
        for (const strategy of Object.values(strategies)) {
            const dataSource = this.generateDataSourceAndResourcesForStrategy(context, strategy);
            const strategyName = strategy.name;
            this.models
                .filter((model) => modelStrategyMatches(model, strategyName))
                .forEach((model) => {
                context.dataSources.add(model, dataSource);
                this.datasourceMap[model.name.value] = dataSource;
            });
        }
        this.generateResolvers(context);
        this.setFieldMappingResolverReferences(context);
    }
    getVTLGenerator() {
        return new resolvers_1.RDSModelVTLGenerator();
    }
    setFieldMappingResolverReferences(context) {
        this.models.forEach((def) => {
            var _a;
            const modelName = (_a = def === null || def === void 0 ? void 0 : def.name) === null || _a === void 0 ? void 0 : _a.value;
            const modelFieldMap = context.resourceHelper.getModelFieldMap(modelName);
            if (!modelFieldMap.getMappedFields().length) {
                return;
            }
            const queryFields = this.getQueryFieldNames(def);
            const mutationFields = this.getMutationFieldNames(def);
            queryFields.forEach((query) => {
                modelFieldMap.addResolverReference({
                    typeName: query.typeName,
                    fieldName: query.fieldName,
                    isList: [graphql_transformer_interfaces_1.QueryFieldType.LIST, graphql_transformer_interfaces_1.QueryFieldType.SYNC].includes(query.type),
                });
            });
            mutationFields.forEach((mutation) => {
                modelFieldMap.addResolverReference({ typeName: mutation.typeName, fieldName: mutation.fieldName, isList: false });
            });
        });
    }
}
exports.RdsModelResourceGenerator = RdsModelResourceGenerator;
const resolveLayerVersion = (scope, context, resourceNames) => {
    let layerVersionArn;
    if (context.rdsLayerMapping) {
        (0, rds_1.setRDSLayerMappings)(scope, context.rdsLayerMapping, resourceNames);
        layerVersionArn = aws_cdk_lib_1.Fn.findInMap(resourceNames.sqlLayerVersionMapping, aws_cdk_lib_1.Fn.ref('AWS::Region'), 'layerRegion');
    }
    else {
        const layerVersionCustomResource = (0, rds_1.createLayerVersionCustomResource)(scope, resourceNames);
        layerVersionArn = layerVersionCustomResource.getResponseField('Body');
    }
    return layerVersionArn;
};
//# sourceMappingURL=rds-model-resource-generator.js.map