"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AmplifyDynamoModelResourceGenerator = exports.ITERATIVE_TABLE_STACK_NAME = void 0;
const cdk = __importStar(require("aws-cdk-lib"));
const graphql_transformer_common_1 = require("graphql-transformer-common");
const graphql_transformer_core_1 = require("@aws-amplify/graphql-transformer-core");
const aws_dynamodb_1 = require("aws-cdk-lib/aws-dynamodb");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const dynamo_model_resource_generator_1 = require("../dynamo-model-resource-generator");
const path = __importStar(require("path"));
const amplify_dynamodb_table_construct_1 = require("./amplify-dynamodb-table-construct");
exports.ITERATIVE_TABLE_STACK_NAME = 'AmplifyTableManager';
class AmplifyDynamoModelResourceGenerator extends dynamo_model_resource_generator_1.DynamoModelResourceGenerator {
    constructor() {
        super(...arguments);
        this.customResourceServiceToken = '';
    }
    generateResources(ctx) {
        var _a;
        if (!this.isEnabled()) {
            return;
        }
        if (this.isProvisioned()) {
            const rootStack = cdk.Stack.of(ctx.stackManager.scope);
            this.createDynamoDBParameters(rootStack, false);
            const tableManagerStack = ctx.stackManager.getScopeFor('AmplifyTableCustomProvider', exports.ITERATIVE_TABLE_STACK_NAME);
            this.createCustomProviderResource(tableManagerStack, ctx);
        }
        this.models.forEach((model) => {
            const tableBaseName = ctx.resourceHelper.getModelNameMapping(model.name.value);
            const tableLogicalName = graphql_transformer_common_1.ModelResourceIDs.ModelTableResourceID(tableBaseName);
            const scope = ctx.stackManager.getScopeFor(tableLogicalName, tableBaseName);
            this.createModelTable(scope, model, ctx);
        });
        if (this.ddbManagerPolicy) {
            (_a = this.ddbManagerPolicy) === null || _a === void 0 ? void 0 : _a.addStatements(new aws_cdk_lib_1.aws_iam.PolicyStatement({
                actions: [
                    'dynamodb:CreateTable',
                    'dynamodb:UpdateTable',
                    'dynamodb:DeleteTable',
                    'dynamodb:DescribeTable',
                    'dynamodb:DescribeContinuousBackups',
                    'dynamodb:DescribeTimeToLive',
                    'dynamodb:UpdateContinuousBackups',
                    'dynamodb:UpdateTimeToLive',
                ],
                resources: [
                    cdk.Fn.sub('arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/*-${apiId}-${envName}', {
                        apiId: ctx.api.apiId,
                        envName: ctx.synthParameters.amplifyEnvironmentName,
                    }),
                ],
            }));
        }
        this.generateResolvers(ctx);
    }
    createCustomProviderResource(scope, context) {
        this.ddbManagerPolicy = new aws_cdk_lib_1.aws_iam.Policy(scope, 'CreateUpdateDeleteTablesPolicy');
        const lambdaCode = aws_cdk_lib_1.aws_lambda.Code.fromAsset(path.join(__dirname, '..', '..', '..', 'lib', 'resources', 'amplify-dynamodb-table', 'amplify-table-manager-lambda'));
        const gsiOnEventHandler = new aws_cdk_lib_1.aws_lambda.Function(scope, graphql_transformer_common_1.ResourceConstants.RESOURCES.TableManagerOnEventHandlerLogicalID, {
            runtime: aws_cdk_lib_1.aws_lambda.Runtime.NODEJS_18_X,
            code: lambdaCode,
            handler: 'amplify-table-manager-handler.onEvent',
            timeout: aws_cdk_lib_1.Duration.minutes(14),
        });
        const gsiIsCompleteHandler = new aws_cdk_lib_1.aws_lambda.Function(scope, graphql_transformer_common_1.ResourceConstants.RESOURCES.TableManagerIsCompleteHandlerLogicalID, {
            runtime: aws_cdk_lib_1.aws_lambda.Runtime.NODEJS_18_X,
            code: lambdaCode,
            handler: 'amplify-table-manager-handler.isComplete',
            timeout: aws_cdk_lib_1.Duration.minutes(14),
        });
        this.ddbManagerPolicy.attachToRole(gsiOnEventHandler.role);
        this.ddbManagerPolicy.attachToRole(gsiIsCompleteHandler.role);
        const customResourceProvider = new aws_cdk_lib_1.custom_resources.Provider(scope, graphql_transformer_common_1.ResourceConstants.RESOURCES.TableManagerCustomProviderLogicalID, {
            onEventHandler: gsiOnEventHandler,
            isCompleteHandler: gsiIsCompleteHandler,
            logRetention: aws_cdk_lib_1.aws_logs.RetentionDays.ONE_MONTH,
            queryInterval: aws_cdk_lib_1.Duration.seconds(30),
            totalTimeout: aws_cdk_lib_1.Duration.hours(2),
        });
        this.customResourceServiceToken = customResourceProvider.serviceToken;
    }
    createModelTable(scope, def, context) {
        var _a;
        const modelName = def.name.value;
        const tableLogicalName = graphql_transformer_common_1.ModelResourceIDs.ModelTableResourceID(modelName);
        const tableName = context.resourceHelper.generateTableName(modelName);
        const { readIops, writeIops, billingMode, pointInTimeRecovery, enableSSE } = this.createDynamoDBParameters(scope, true);
        new cdk.CfnCondition(scope, graphql_transformer_common_1.ResourceConstants.CONDITIONS.HasEnvironmentParameter, {
            expression: cdk.Fn.conditionNot(cdk.Fn.conditionEquals(context.synthParameters.amplifyEnvironmentName, graphql_transformer_common_1.ResourceConstants.NONE)),
        });
        const useSSE = new cdk.CfnCondition(scope, graphql_transformer_common_1.ResourceConstants.CONDITIONS.ShouldUseServerSideEncryption, {
            expression: cdk.Fn.conditionEquals(enableSSE, 'true'),
        });
        const usePayPerRequestBilling = new cdk.CfnCondition(scope, graphql_transformer_common_1.ResourceConstants.CONDITIONS.ShouldUsePayPerRequestBilling, {
            expression: cdk.Fn.conditionEquals(billingMode, 'PAY_PER_REQUEST'),
        });
        const usePointInTimeRecovery = new cdk.CfnCondition(scope, graphql_transformer_common_1.ResourceConstants.CONDITIONS.ShouldUsePointInTimeRecovery, {
            expression: cdk.Fn.conditionEquals(pointInTimeRecovery, 'true'),
        });
        const removalPolicy = this.options.EnableDeletionProtection ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY;
        const table = new amplify_dynamodb_table_construct_1.AmplifyDynamoDBTable(scope, `${tableLogicalName}`, {
            customResourceServiceToken: this.customResourceServiceToken,
            allowDestructiveGraphqlSchemaUpdates: context.transformParameters.allowDestructiveGraphqlSchemaUpdates,
            replaceTableUponGsiUpdate: context.transformParameters.replaceTableUponGsiUpdate,
            tableName,
            partitionKey: {
                name: 'id',
                type: aws_dynamodb_1.AttributeType.STRING,
            },
            stream: aws_dynamodb_1.StreamViewType.NEW_AND_OLD_IMAGES,
            encryption: aws_dynamodb_1.TableEncryption.DEFAULT,
            removalPolicy,
            ...(context.isProjectUsingDataStore() ? { timeToLiveAttribute: '_ttl' } : undefined),
        });
        (0, graphql_transformer_core_1.setResourceName)(table, { name: modelName, setOnDefaultChild: false });
        const tableRepresentative = table.tableFromAttr;
        (0, graphql_transformer_core_1.setResourceName)(tableRepresentative, { name: modelName, setOnDefaultChild: false });
        const cfnTable = (_a = table.node.defaultChild) === null || _a === void 0 ? void 0 : _a.node.defaultChild;
        (0, graphql_transformer_core_1.setResourceName)(cfnTable, { name: modelName, setOnDefaultChild: false });
        cfnTable.addPropertyOverride('provisionedThroughput', cdk.Fn.conditionIf(usePayPerRequestBilling.logicalId, cdk.Fn.ref('AWS::NoValue'), {
            ReadCapacityUnits: readIops,
            WriteCapacityUnits: writeIops,
        }));
        cfnTable.addPropertyOverride('pointInTimeRecoverySpecification', cdk.Fn.conditionIf(usePointInTimeRecovery.logicalId, { PointInTimeRecoveryEnabled: true }, cdk.Fn.ref('AWS::NoValue')));
        cfnTable.addPropertyOverride('billingMode', cdk.Fn.conditionIf(usePayPerRequestBilling.logicalId, 'PAY_PER_REQUEST', cdk.Fn.ref('AWS::NoValue')).toString());
        cfnTable.addPropertyOverride('sseSpecification', {
            sseEnabled: cdk.Fn.conditionIf(useSSE.logicalId, true, false),
        });
        const streamArnOutputId = `GetAtt${graphql_transformer_common_1.ModelResourceIDs.ModelTableStreamArn(def.name.value)}`;
        if (table.tableStreamArn) {
            new cdk.CfnOutput(cdk.Stack.of(scope), streamArnOutputId, {
                value: table.tableStreamArn,
                description: 'Your DynamoDB table StreamArn.',
                exportName: cdk.Fn.join(':', [context.api.apiId, 'GetAtt', tableLogicalName, 'StreamArn']),
            });
        }
        const tableNameOutputId = `GetAtt${tableLogicalName}Name`;
        new cdk.CfnOutput(cdk.Stack.of(scope), tableNameOutputId, {
            value: table.tableName,
            description: 'Your DynamoDB table name.',
            exportName: cdk.Fn.join(':', [context.api.apiId, 'GetAtt', tableLogicalName, 'Name']),
        });
        const role = this.createIAMRole(context, def, scope, tableName);
        const tableDataSourceLogicalName = `${def.name.value}Table`;
        this.createModelTableDataSource(def, context, tableRepresentative, scope, role, tableDataSourceLogicalName);
    }
}
exports.AmplifyDynamoModelResourceGenerator = AmplifyDynamoModelResourceGenerator;
//# sourceMappingURL=amplify-dynamo-model-resource-generator.js.map