import { iamPolicy } from "../iam/PolicyDocument";
import { normalize } from "../cloudformation";
import { join, joinWith } from "../Value";
export class Lambda {
    aws;
    role;
    lambda;
    permissions;
    subscriptions;
    rules;
    name;
    constructor(aws, name, role, lambda) {
        this.aws = aws;
        this.aws = aws;
        this.name = name;
        this.role = role;
        this.lambda = lambda;
        this.permissions = [];
        this.subscriptions = [];
        this.rules = [];
    }
    schedule(scheduleExpression) {
        const rule = this.aws.events.rule({
            scheduleExpression: scheduleExpression,
            targets: [{ arn: this.lambda.attributes.Arn, id: '1' }]
        });
        this.rules.push(rule);
        this.permissions.push(this.aws.lambda.permission({
            action: 'lambda:InvokeFunction',
            functionName: this.lambda.attributes.Arn,
            principal: 'events.amazonaws.com',
            sourceArn: rule.attributes.Arn
        }));
        return this;
    }
    grantInvoke(toArn, principal, sourceAccount) {
        this.permissions.push(Lambda.grantInvoke(this.aws, this.lambda.attributes.Arn, toArn, principal, sourceAccount));
        return this;
    }
    enableTracing() {
        const managedPolicy = 'arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess';
        const current = (this.role.properties.managedPolicyArns ?? []);
        if (!current.includes(managedPolicy)) {
            this.role.properties.managedPolicyArns = [...current, managedPolicy];
        }
        this.lambda.properties.tracingConfig = {
            mode: 'Active'
        };
        return this;
    }
    static grantInvoke(aws, lambdaName, toArn, principal, sourceAccount) {
        return aws.lambda.permission({
            action: 'lambda:InvokeFunction',
            functionName: lambdaName,
            principal,
            sourceArn: toArn,
            sourceAccount
        });
    }
    snsTrigger(topicArn, sourceAccount) {
        const [permission, subscription] = Lambda.snsTrigger(this.aws, this.lambda.attributes.Arn, topicArn, sourceAccount);
        permission.logicalName = `${this.aws.logicalName(this.lambda.logicalName + 'Permission')}`;
        subscription.logicalName = `${this.aws.logicalName(this.lambda.logicalName + 'Subscription')}`;
        this.permissions.push(permission);
        this.subscriptions.push(subscription);
        return this;
    }
    static snsTrigger(aws, lambdaArn, topicArn, sourceAccount) {
        const permission = Lambda.grantInvoke(aws, lambdaArn, topicArn, 'sns.amazonaws.com', sourceAccount);
        const subscription = aws.sns.subscription({
            protocol: 'lambda',
            topicArn: topicArn,
            endpoint: lambdaArn
        });
        return [permission, subscription];
    }
    static create(aws, name, code, handler, runtime, extra) {
        const normalName = normalize(name);
        const functionName = extra?.properties?.functionName ?? name;
        const role = aws.iam.role({
            path: '/',
            assumeRolePolicyDocument: iamPolicy({
                statement: [{ action: 'sts:AssumeRole', effect: 'Allow', principal: { Service: ['lambda.amazonaws.com'] } }],
                version: '2012-10-17',
            }),
            policies: [{
                    policyName: 'LogAccess',
                    policyDocument: iamPolicy({
                        version: '2012-10-17',
                        statement: [
                            { action: 'logs:CreateLogGroup', effect: 'Allow', resource: [joinWith(':', 'arn', { Ref: 'AWS::Partition' }, 'logs', { Ref: 'AWS::Region' }, { Ref: 'AWS::AccountId' }, '*')] },
                            { action: ['logs:CreateLogStream', 'logs:PutLogEvents'], effect: 'Allow', resource: [joinWith(':', 'arn', { Ref: 'AWS::Partition' }, 'logs', { Ref: 'AWS::Region' }, { Ref: 'AWS::AccountId' }, 'log-group', join('/aws/lambda/', functionName, ':*'))] }
                        ],
                    })
                }],
            tags: extra?.properties?.tags,
        }).withLogicalName(`${normalName}Role`);
        const lambda = aws.lambda
            .createFunction({ functionName: name, code, handler, role: role.attributes.Arn, runtime, ...extra })
            .withLogicalName(`${normalName}Function`);
        return new Lambda(aws, normalName, role, lambda);
    }
}
