"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createFunction = void 0;
const client_cloudwatch_logs_1 = require("@aws-sdk/client-cloudwatch-logs");
const client_lambda_1 = require("@aws-sdk/client-lambda");
const lambda_client_1 = require("@remotion/lambda-client");
const constants_1 = require("@remotion/lambda-client/constants");
const renderer_1 = require("@remotion/renderer");
const node_fs_1 = require("node:fs");
const version_1 = require("remotion/version");
const get_layers_1 = require("../shared/get-layers");
const lambda_insights_extensions_1 = require("../shared/lambda-insights-extensions");
const suggested_policy_1 = require("./iam-validation/suggested-policy");
const createFunction = async ({ createCloudWatchLogGroup, region, zipFile, functionName, accountId, memorySizeInMb, timeoutInSeconds, alreadyCreated, retentionInDays, ephemerealStorageInMb, customRoleArn, enableLambdaInsights, logLevel, vpcSubnetIds, vpcSecurityGroupIds, runtimePreference, requestHandler, }) => {
    var _a;
    if (createCloudWatchLogGroup) {
        renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Creating CloudWatch group');
        try {
            await lambda_client_1.LambdaClientInternals.getCloudWatchLogsClient(region, requestHandler).send(new client_cloudwatch_logs_1.CreateLogGroupCommand({
                logGroupName: `${constants_1.LOG_GROUP_PREFIX}${functionName}`,
            }));
            renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'CloudWatch group successfully created');
        }
        catch (_err) {
            const err = _err;
            if (err.message.includes('log group already exists')) {
                renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'CloudWatch group already existed.');
            }
            else {
                throw err;
            }
        }
        renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Adding retention policy to the CloudWatch group');
        await lambda_client_1.LambdaClientInternals.getCloudWatchLogsClient(region, requestHandler).send(new client_cloudwatch_logs_1.PutRetentionPolicyCommand({
            logGroupName: `${constants_1.LOG_GROUP_PREFIX}${functionName}`,
            retentionInDays,
        }));
        renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `Set retention to ${retentionInDays} days`);
    }
    if (alreadyCreated) {
        renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `Function ${functionName} already existed`);
        return { FunctionName: functionName };
    }
    const defaultRoleName = `arn:aws:iam::${accountId}:role/${suggested_policy_1.ROLE_NAME}`;
    const layers = (0, get_layers_1.getLayers)({
        option: runtimePreference,
        region,
    });
    let vpcConfig;
    if (vpcSubnetIds && vpcSecurityGroupIds) {
        vpcConfig = {
            SubnetIds: vpcSubnetIds.split(','),
            SecurityGroupIds: vpcSecurityGroupIds.split(','),
        };
    }
    renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Deploying new Lambda function');
    const insightsLayer = enableLambdaInsights
        ? lambda_insights_extensions_1.lambdaInsightsExtensions[region]
        : null;
    if (enableLambdaInsights && !insightsLayer) {
        throw new Error(`Lambda Insights is not supported by AWS in region ${region}. Please disable Lambda Insights. See http://remotion.dev/docs/lambda/insights#unsupported-regions`);
    }
    const { FunctionName, FunctionArn } = await lambda_client_1.LambdaClientInternals.getLambdaClient(region, undefined, requestHandler).send(new client_lambda_1.CreateFunctionCommand({
        Code: {
            ZipFile: new Uint8Array((0, node_fs_1.readFileSync)(zipFile)),
        },
        FunctionName: functionName,
        Handler: 'index.handler',
        Role: customRoleArn !== null && customRoleArn !== void 0 ? customRoleArn : defaultRoleName,
        Runtime: 'nodejs24.x',
        Description: 'Renders a Remotion video.',
        MemorySize: memorySizeInMb,
        Timeout: timeoutInSeconds,
        Layers: layers
            .map(({ layerArn, version }) => `${layerArn}:${version}`)
            .concat(insightsLayer ? [insightsLayer] : []),
        Architectures: ['arm64'],
        EphemeralStorage: {
            Size: ephemerealStorageInMb,
        },
        VpcConfig: vpcConfig,
    }));
    renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Function deployed. Adding tags...');
    try {
        await lambda_client_1.LambdaClientInternals.getLambdaClient(region, undefined, requestHandler).send(new client_lambda_1.TagResourceCommand({
            Resource: FunctionArn,
            Tags: {
                'remotion-lambda': 'true',
                'remotion-version': version_1.VERSION,
                'remotion-memory-in-mb': String(memorySizeInMb),
                'remotion-timeout-in-seconds': String(timeoutInSeconds),
                'remotion-ephemereal-storage-in-mb': String(ephemerealStorageInMb),
            },
        }));
    }
    catch (err) {
        // Previous Lambda versions had no permission to tag the function
        if (err.name.includes('AccessDenied')) {
            renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Did not have permission to tag the function. Skipping.');
        }
        else {
            throw err;
        }
    }
    renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Disabling function retries (Remotion handles retries itself)...');
    await lambda_client_1.LambdaClientInternals.getLambdaClient(region, undefined, requestHandler).send(new client_lambda_1.PutFunctionEventInvokeConfigCommand({
        MaximumRetryAttempts: 0,
        FunctionName,
    }));
    renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Set function retries to 0.');
    renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Waiting for the function to be ready...');
    let state = 'Pending';
    while (state === 'Pending') {
        const getFn = await lambda_client_1.LambdaClientInternals.getLambdaClient(region, undefined, requestHandler).send(new client_lambda_1.GetFunctionCommand({
            FunctionName,
        }));
        await new Promise((resolve) => {
            setTimeout(() => resolve(), 1000);
        });
        state = (_a = getFn.Configuration) === null || _a === void 0 ? void 0 : _a.State;
    }
    renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Function is now ready.');
    renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, 'Locking the runtime version of the function...');
    const RuntimeVersionArn = `arn:aws:lambda:${region}::runtime:58a37e8413ed69058c4ac3b1df642118591f17d40def93d6101f867c72cd03c2`;
    try {
        await lambda_client_1.LambdaClientInternals.getLambdaClient(region, undefined, requestHandler).send(new client_lambda_1.PutRuntimeManagementConfigCommand({
            FunctionName,
            UpdateRuntimeOn: 'Manual',
            RuntimeVersionArn,
        }));
    }
    catch (_b) {
        console.warn('⚠️ Could not lock the runtime version. We recommend to update your policies to prevent your functions from breaking in the future in case the AWS runtime changes. See https://remotion.dev/docs/lambda/feb-2023-incident for an example on how to update your policy.');
    }
    renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel }, `Function runtime is locked to ${RuntimeVersionArn}`);
    return { FunctionName: FunctionName };
};
exports.createFunction = createFunction;
