import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecr from 'aws-cdk-lib/aws-ecr';
import * as codedeploy from 'aws-cdk-lib/aws-codedeploy';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';
import { ApplicationTargetGroup, ApplicationListener } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { studioSecrets } from '../secrets/studio-secrets';
import { studioApiServiceOnlySecrets } from '../secrets/studio-api-service-only-secret';
import { config } from '../../../config'; // Import the configuration
import { fluteSecrets } from '../secrets/flute-secrets';
import { rdsSecrets } from '../secrets/rds-secrets';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
import * as sqs from 'aws-cdk-lib/aws-sqs';
import * as lambdaEventSources from 'aws-cdk-lib/aws-lambda-event-sources';
import * as logs from 'aws-cdk-lib/aws-logs';

export interface FargateServiceProps {
  accountStage: string;
  cluster: ecs.Cluster;
  vpc: ec2.IVpc;
  subnets: ec2.ISubnet[];
  blueTargetGroup: ApplicationTargetGroup;
  greenTargetGroup: ApplicationTargetGroup;
  httpListener: ApplicationListener;
  loadBalancerSecurityGroup: ec2.SecurityGroup;
}

export class FargateService extends Construct {
  public service: ecs.FargateService;
  public containerLogGroup?: logs.ILogGroup;

  constructor(scope: Construct, id: string, props: FargateServiceProps) {
    super(scope, id);

    const taskRole = new iam.Role(this, 'TaskRole', {
      assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonECSTaskExecutionRolePolicy'),
        iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'),
      ],
    });

    // Create a dedicated execution role with custom policy
    const executionRole = new iam.Role(this, 'ExecutionRole', {
      assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
    });

    // Add the complete execution role policy based on your existing policy
    executionRole.addToPolicy(new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      actions: [
        'ecr:BatchCheckLayerAvailability',
        'ecr:BatchGetImage',
        'ecr:GetDownloadUrlForLayer',
        'ecr:GetAuthorizationToken',
      ],
      resources: ['*'], 
    }));

    // Add CloudWatch Logs permissions
    executionRole.addToPolicy(new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      actions: [
        'logs:CreateLogStream',
        'logs:PutLogEvents',
      ],
      resources: [`arn:aws:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:log-group:*`],
    }));

    // Add Secrets Manager permissions  
    executionRole.addToPolicy(new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      actions: [
        'secretsmanager:DescribeSecret',
        'secretsmanager:GetSecretValue',
      ],
      resources: [
        `arn:aws:secretsmanager:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:secret:*`,
      ],
    }));

    // Define a Fargate task definition
    const taskDefinition = new ecs.FargateTaskDefinition(this, 'StudioApiTaskDefinition', {
      memoryLimitMiB: 61440,
      cpu: 8192,
      taskRole: taskRole,
      executionRole: executionRole,
      runtimePlatform: {
        operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
        cpuArchitecture: ecs.CpuArchitecture.ARM64,
      },
      family: 'BackendInfraStackStudioApiFargateServiceStudioApiTaskDefinition0972B978',
    });

    const repository = ecr.Repository.fromRepositoryAttributes(this, 'studioApiRepository', {
      repositoryArn: `arn:aws:ecr:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:repository/studio-api`,
      repositoryName: 'studio-api',
    });
    const secrets = studioSecrets(this, props.accountStage, false);
    const serviceOnlySecrets = studioApiServiceOnlySecrets(this, props.accountStage);
    const fluteSecret = fluteSecrets(this, props.accountStage, false);
    const rdsSecret = rdsSecrets(this, props.accountStage);

    const linuxParameters = new ecs.LinuxParameters(this, 'LinuxParameters', {});
    linuxParameters.addCapabilities(ecs.Capability.SYS_PTRACE);

    // Use the existing log group when in staging to avoid creating a new one
    let stagingLogGroup: logs.ILogGroup | undefined = undefined;
    if (props.accountStage === 'staging') {
      stagingLogGroup = logs.LogGroup.fromLogGroupName(
        this,
        'StudioApiExistingLogGroupStaging',
        'BackendInfraStack-StudioApiFargateServiceStudioApiTaskDefinitionStudioApiContainer1LogGroup9ED9C304-WyjX9jYiaCWn'
      );
      this.containerLogGroup = stagingLogGroup as logs.LogGroup;
    }

    // Add a container to the task definition
    const container = taskDefinition.addContainer('StudioApiContainer1', {
      image: ecs.ContainerImage.fromEcrRepository(repository, 'latest'),
      logging: new ecs.AwsLogDriver({
        streamPrefix: 'StudioApiContainer',
        ...(stagingLogGroup ? { logGroup: stagingLogGroup as logs.ILogGroup } : {}),
      }),
      environment: {
        AWS_DEFAULT_REGION: 'us-east-1',
        ACCOUNT_ID: cdk.Aws.ACCOUNT_ID,
        DD_PROFILING_STACK_V2_ENABLED: '0',
        CDK_FORCE_DEPLOY: Date.now().toString(),
      },
      secrets: { ...secrets, ...fluteSecret, ...rdsSecret, ...serviceOnlySecrets },
      linuxParameters: linuxParameters,
      healthCheck: {
        command: ['CMD-SHELL', `curl -f http://localhost:8005/health/ || exit 1`],
        interval: cdk.Duration.seconds(30),
        timeout: cdk.Duration.seconds(10),
        retries: 10,
        startPeriod: cdk.Duration.seconds(120),
      },
      cpu: config[props.accountStage].studioApiServiceConfig.studioApiContainerConfig.cpu,
      memoryLimitMiB: config[props.accountStage].studioApiServiceConfig.studioApiContainerConfig.memory,
      essential: true,
    });

    // Retrieve Docker credentials from AWS Secrets Manager
    const dockerCredentials = secretsmanager.Secret.fromSecretNameV2(this, 'DockerCredentials', 'docker-credential');

    // Add port mappings to the container
    container.addPortMappings({
      containerPort: 8005,
      name: 'studio-api',
    });

    // Create a security group for the Fargate service
    const fargateServiceSecurityGroup = new ec2.SecurityGroup(this, 'FargateServiceSG', {
      vpc: props.vpc,
      allowAllOutbound: true,
      description: 'BackendInfraStack/StudioApiFargateService/FargateServiceSG',
    });

    // Allow traffic from the load balancer to the Fargate service on port 8005
    fargateServiceSecurityGroup.addIngressRule(props.loadBalancerSecurityGroup, ec2.Port.tcp(8005), 'Allow traffic from Load Balancer');

    // Allow traffic from the pre-traffic hook Lambda to the Fargate service on port 8005
    fargateServiceSecurityGroup.addIngressRule(fargateServiceSecurityGroup, ec2.Port.tcp(8005), 'Allow traffic from service security group');

    // Define the Fargate service
    this.service = new ecs.FargateService(this, 'StudioApiFargateService', {
      cluster: props.cluster,
      taskDefinition: taskDefinition,
      serviceName: 'StudioApiFargateService',
      deploymentController: {
        type: ecs.DeploymentControllerType.CODE_DEPLOY,
      },
      securityGroups: [fargateServiceSecurityGroup],
      healthCheckGracePeriod: cdk.Duration.seconds(60),
      vpcSubnets: {
        subnets: props.subnets,
      },
      enableExecuteCommand: true,
      desiredCount: config[props.accountStage].studioApiServiceConfig.desiredCount,
    });

    // Attach the Fargate service to the blue target group initially
    this.service.attachToApplicationTargetGroup(props.blueTargetGroup);

    // Enable auto-scaling for the Fargate service
    const scalableTarget = this.service.autoScaleTaskCount({
      minCapacity: config[props.accountStage].studioApiServiceConfig.minCapacity,
      maxCapacity: config[props.accountStage].studioApiServiceConfig.maxCapacity,
    });

    // Define a scaling policy based on CPU utilization
    scalableTarget.scaleOnCpuUtilization('CpuScaling', {
      targetUtilizationPercent: 50,
      scaleInCooldown: cdk.Duration.seconds(60),
      scaleOutCooldown: cdk.Duration.seconds(60),
      policyName: 'BackendInfraStackStudioApiFargateServiceTaskCountTargetCpuScaling868C718B',
    });

    // Define a scaling policy based on memory utilization
    scalableTarget.scaleOnMemoryUtilization('MemoryScaling', {
      targetUtilizationPercent: 60,
      scaleInCooldown: cdk.Duration.seconds(60),
      scaleOutCooldown: cdk.Duration.seconds(60),
      policyName: 'BackendInfraStackStudioApiFargateServiceTaskCountTargetMemoryScaling676CBD50',
    });

    // Create a CodeDeploy application
    const codedeployApp = new codedeploy.EcsApplication(this, 'StudioApiCodeDeployApp');

    // Create a CodeDeploy deployment group with canary deployment configuration
    const codedeployDeploymentGroup = new codedeploy.EcsDeploymentGroup(this, 'MyCodeDeployDeploymentGroup', {
      application: codedeployApp,
      service: this.service,
      deploymentConfig: codedeploy.EcsDeploymentConfig.ALL_AT_ONCE,
      blueGreenDeploymentConfig: {
        blueTargetGroup: props.blueTargetGroup,
        greenTargetGroup: props.greenTargetGroup,
        listener: props.httpListener,
        terminationWaitTime: cdk.Duration.minutes(config[props.accountStage].studioApiServiceConfig.terminationWaitTime),
      },
    });

    // Create a Lambda layer for the notifier function
    const notifierLayer = new lambda.LayerVersion(this, 'CodeDeployNotifierLayer', {
      code: lambda.Code.fromAsset('lambda/code-deploy-notifier', {
        bundling: {
          image: lambda.Runtime.NODEJS_18_X.bundlingImage,
          command: [
            'bash', '-c',
            'mkdir -p /asset-output/nodejs && cp package.json /asset-output/nodejs/ && cd /asset-output/nodejs && npm install --omit=dev --cache=/tmp/.npm'
          ],
        },
      }),
      compatibleRuntimes: [lambda.Runtime.NODEJS_18_X],
      description: 'Contains the js-yaml dependency for the CodeDeploy notifier.',
    });

    // Define the Lambda function
    const deployNotifierLambdaFunction = new lambda.Function(this, 'CodeDeployNotifier', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda/code-deploy-notifier'),
      functionName: 'CodeDeployNotifier',
      layers: [notifierLayer],
    });

    // Grant necessary permissions to the Lambda function
    deployNotifierLambdaFunction.addToRolePolicy(
      new iam.PolicyStatement({
        actions: [
          'iam:PassRole',
          'sts:GetCallerIdentity',
          'ecr:DescribeImages',
          'ecs:ListTaskDefinitions',
          'ecs:describeTaskDefinition',
          'ssm:PutParameter',
          'codedeploy:CreateDeployment',
          'codedeploy:GetDeployment',
          'codedeploy:GetDeploymentConfig',
          'codedeploy:GetApplication',
          'codedeploy:GetApplicationRevision',
          'codedeploy:RegisterApplicationRevision',
          'codedeploy:GetDeploymentConfig',
          'codedeploy:GetDeploymentGroup',
          'codedeploy:GetDeploymentTarget',
          'codedeploy:ListApplications',
          'codedeploy:ListDeployments',
          'codedeploy:ListDeploymentConfigs',
          'codedeploy:ListDeploymentGroups',
          'codedeploy:ListDeploymentTargets',
          'codedeploy:StopDeployment',
        ],
        resources: ['*'],
      })
    );

    // Define the EventBridge rule
    const codeDeployAfterAllowTrafficRule = new events.Rule(this, 'CodeDeployAfterAllowTrafficRule', {
      eventPattern: {
        source: ['aws.codedeploy'],
        detailType: ['CodeDeploy Deployment State-change Notification'],
        detail: {
          state: ['SUCCESS', 'FAILURE', 'STOP'],
          deploymentId: [{ exists: true }],
        },
      },
    });

    // Add the Lambda function as the target of the rule
    codeDeployAfterAllowTrafficRule.addTarget(new targets.LambdaFunction(deployNotifierLambdaFunction));

    // Define the DLQ
    const dlq = new sqs.Queue(this, 'studio-api-deployment-dlq', {
      queueName: 'studio-api-deployment-dlq.fifo',
      retentionPeriod: cdk.Duration.days(7), // Retain messages for 14 days
      fifo: true,
    });

    const EventBridgeDlq = new sqs.Queue(this, 'event-bridge-dlq', {
      queueName: 'event-bridge-dlq',
      retentionPeriod: cdk.Duration.days(7), // Retain messages for 14 days
    });

    // Define the SQS queue
    const deploymentQueue = new sqs.Queue(this, 'studio-api-deployment-queue', {
      queueName: 'studio-api-deployment-queue.fifo',
      visibilityTimeout: cdk.Duration.minutes(15),
      fifo: true,
      deadLetterQueue: {
        queue: dlq,
        maxReceiveCount: 1,
      },
      contentBasedDeduplication: true,
    });

    // Create a Lambda function to handle the CodeDeploy deployment
    const deploymentFunction = new lambda.Function(this, 'CodeDeployFunction', {
      runtime: lambda.Runtime.NODEJS_16_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda/backend-deploy'),
      environment: {
        APPLICATION_NAME: codedeployApp.applicationName,
        DEPLOYMENT_GROUP_NAME: codedeployDeploymentGroup.deploymentGroupName,
        TASK_DEFINITION_FAMILY: taskDefinition.family,
        CONTAINER_NAME: container.containerName,
      },
      timeout: cdk.Duration.minutes(15),
    });

    // Create a Lambda function to handle the CodeDeploy deployment
    const deploymentFunctionQueued = new lambda.Function(this, 'CodeDeployFunctionQueued', {
      functionName: 'CodeDeployFunctionQueued',
      runtime: lambda.Runtime.PYTHON_3_11,
      handler: 'main.lambda_handler',
      code: lambda.Code.fromAsset('lambda/backend-deploy-queued'),
      environment: {
        APPLICATION_NAME: codedeployApp.applicationName,
        DEPLOYMENT_GROUP_NAME: codedeployDeploymentGroup.deploymentGroupName,
        TASK_DEFINITION_FAMILY: taskDefinition.family,
        CONTAINER_NAME: container.containerName,
        QUEUE_URL: deploymentQueue.queueUrl,
      },
      timeout: cdk.Duration.minutes(15),
    });

    // Grant necessary permissions to the Lambda function
    deploymentFunction.addToRolePolicy(
      new iam.PolicyStatement({
        actions: [
          'sts:GetCallerIdentity',
          'ecs:ListTaskDefinitions',
          'ecs:describeTaskDefinition',
          'ecs:registerTaskDefinition',
          'ecs:UpdateService',
          'ecs:RunTask',
          'ecs:DescribeTasks',
          'ecr:DescribeImages',
          'iam:PassRole',
          'ssm:PutParameter',
          'codedeploy:CreateDeployment',
          'codedeploy:GetDeployment',
          'codedeploy:GetDeploymentConfig',
          'codedeploy:GetApplication',
          'codedeploy:GetApplicationRevision',
          'codedeploy:RegisterApplicationRevision',
          'codedeploy:GetDeploymentConfig',
          'codedeploy:GetDeploymentGroup',
          'codedeploy:GetDeploymentTarget',
          'codedeploy:ListApplications',
          'codedeploy:ListDeployments',
          'codedeploy:ListDeploymentConfigs',
          'codedeploy:ListDeploymentGroups',
          'codedeploy:ListDeploymentTargets',
          'codedeploy:StopDeployment',
        ],
        resources: ['*'],
      })
    );

    // Grant necessary permissions to the Lambda function
    deploymentFunctionQueued.addToRolePolicy(
      new iam.PolicyStatement({
        actions: [
          'sts:GetCallerIdentity',
          'ecs:ListTaskDefinitions',
          'ecs:describeTaskDefinition',
          'ecs:registerTaskDefinition',
          'ecs:UpdateService',
          'ecs:RunTask',
          'ecs:DescribeTasks',
          'ecr:DescribeImages',
          'iam:PassRole',
          'ssm:PutParameter',
          'codedeploy:CreateDeployment',
          'codedeploy:GetDeployment',
          'codedeploy:GetDeploymentConfig',
          'codedeploy:GetApplication',
          'codedeploy:GetApplicationRevision',
          'codedeploy:RegisterApplicationRevision',
          'codedeploy:GetDeploymentConfig',
          'codedeploy:GetDeploymentGroup',
          'codedeploy:GetDeploymentTarget',
          'codedeploy:ListApplications',
          'codedeploy:ListDeployments',
          'codedeploy:ListDeploymentConfigs',
          'codedeploy:ListDeploymentGroups',
          'codedeploy:ListDeploymentTargets',
          'codedeploy:StopDeployment',
          'sqs:SendMessage',
          'sqs:GetQueueUrl',
          'sqs:GetQueueAttributes',
          'sqs:ReceiveMessage',
          'sqs:DeleteMessage',
        ],
        resources: ['*'],
      })
    );

    // Create an EventBridge rule to monitor ECR image push events
    const rule = new events.Rule(this, 'EcrImagePushRule', {
      eventPattern: {
        source: ['aws.ecr'],
        detailType: ['ECR Image Action'],
        detail: {
          'repository-name': ['studio-api'],
          'action-type': ['PUSH'],
          'image-tag': ['latest'],
        },
      },
    });

    // Enhanced Pre-Traffic Hook Lambda Function
    const preTrafficHookLambdaFunction = new lambda.Function(this, 'PreTrafficHook', {
      runtime: lambda.Runtime.PYTHON_3_12,
      handler: 'main.lambda_handler',
      code: lambda.Code.fromAsset('lambda/django-pre-traffic-hook'),
      functionName: `studio-api-pre-traffic-hook`,
      description: 'Validates Django service health before allowing traffic during CodeDeploy blue/green deployment',
      vpc: props.vpc,
      vpcSubnets: {
        subnets: props.subnets,
      },
      securityGroups: [fargateServiceSecurityGroup],
      timeout: cdk.Duration.minutes(5),
      memorySize: 512,
      environment: {
        ENDPOINT: 'http://localhost:8005',
        CONTAINER_PORT: '8005',
        CONTAINER_NAME: container.containerName,
        CLUSTER_NAME: props.cluster.clusterName,
        SERVICE_NAME: this.service.serviceName,
        ENVIRONMENT: props.accountStage,
        LOG_LEVEL: 'INFO',
        // Test configuration
        HEALTH_CHECK_TIMEOUT: '30',
        MAX_RETRIES: '5',
        RETRY_DELAY: '10',
        TEST_TIMEOUT: '300',
        // Test endpoints
        HEALTH_ENDPOINT: '/health',
        DB_CHECK_ENDPOINT: '/api/prober/db-check',
        API_STATUS_ENDPOINT: '/api/prober/status',
        CACHE_CHECK_ENDPOINT: '/api/prober/cache-check',
        STATIC_FILES_PATH: '/static/admin/css/base.css',
        MIGRATION_CHECK_ENDPOINT: '/api/prober/migration-check',
        // Performance thresholds
        PERFORMANCE_THRESHOLD: props.accountStage === 'production' ? '2.0' : '3.0',
      },
      logRetention: logs.RetentionDays.ONE_WEEK,
    });

    // Grant necessary permissions to the Pre-Traffic Hook Lambda
    preTrafficHookLambdaFunction.addToRolePolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: [
          // CodeDeploy permissions
          'codedeploy:PutLifecycleEventHookExecutionStatus',
          'codedeploy:GetDeployment',
          'codedeploy:GetDeploymentGroup',
          'codedeploy:GetDeploymentConfig',
        ],
        resources: ['*'],
      })
    );

    // ECS permissions
    preTrafficHookLambdaFunction.addToRolePolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ['ecs:DescribeServices', 'ecs:DescribeTasks', 'ecs:ListTasks', 'ecs:DescribeContainerInstances', 'ecs:DescribeTaskDefinition'],
        resources: ['*'],
      })
    );

    // EC2 permissions for network information
    preTrafficHookLambdaFunction.addToRolePolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ['ec2:DescribeInstances', 'ec2:DescribeSecurityGroups', 'ec2:DescribeSubnets', 'ec2:DescribeNetworkInterfaces'],
        resources: ['*'],
      })
    );

    // ELB permissions for target health
    preTrafficHookLambdaFunction.addToRolePolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: [
          'elasticloadbalancing:DescribeTargetGroups',
          'elasticloadbalancing:DescribeTargetHealth',
          'elasticloadbalancing:DescribeLoadBalancers',
          'elasticloadbalancing:DescribeListeners',
        ],
        resources: ['*'],
      })
    );

    // CloudWatch Logs permissions
    preTrafficHookLambdaFunction.addToRolePolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
        resources: [`arn:aws:logs:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:log-group:/aws/lambda/*`],
      })
    );

    // Grant CodeDeploy permission to invoke the Lambda function
    preTrafficHookLambdaFunction.grantInvoke(new iam.ServicePrincipal('codedeploy.amazonaws.com'));

    // Create Lambda layer with dependencies
    const preTrafficHookLayer = new lambda.LayerVersion(this, 'PreTrafficHookLayer', {
      code: lambda.Code.fromAsset('lambda/django-pre-traffic-hook/layers', {
        bundling: {
          image: lambda.Runtime.PYTHON_3_12.bundlingImage,
          command: ['bash', '-c', 'pip install -r requirements.txt -t /asset-output/python && ' + 'cp requirements.txt /asset-output/'],
        },
      }),
      compatibleRuntimes: [lambda.Runtime.PYTHON_3_12],
      description: 'Lambda layer with Python dependencies',
    });

    // Add the layer to the Lambda function
    preTrafficHookLambdaFunction.addLayers(preTrafficHookLayer);

    // Create CloudWatch alarms for monitoring pre-traffic hook execution
    const preTrafficHookErrorAlarm = new cdk.aws_cloudwatch.Alarm(this, 'PreTrafficHookErrorAlarm', {
      metric: preTrafficHookLambdaFunction.metricErrors({
        period: cdk.Duration.minutes(5),
      }),
      threshold: 1,
      evaluationPeriods: 1,
      alarmName: `${props.accountStage}-pre-traffic-hook-errors`,
      alarmDescription: 'Alert when pre-traffic hook Lambda function has errors',
    });

    const preTrafficHookDurationAlarm = new cdk.aws_cloudwatch.Alarm(this, 'PreTrafficHookDurationAlarm', {
      metric: preTrafficHookLambdaFunction.metricDuration({
        period: cdk.Duration.minutes(5),
        statistic: 'Average',
      }),
      threshold: 240000, // 4 minutes in milliseconds
      evaluationPeriods: 2,
      alarmName: `${props.accountStage}-pre-traffic-hook-duration`,
      alarmDescription: 'Alert when pre-traffic hook takes too long',
    });

    if (props.accountStage === 'staging') {
      // Define the CloudWatch Log Group
      const logGroup = new logs.LogGroup(this, 'EventBridgeLogGroup', {
        logGroupName: '/aws/events/studio-api-deployment',
        retention: logs.RetentionDays.ONE_WEEK,
      });
      // Add CloudWatch Logs as a target for the EventBridge rule
      rule.addTarget(new targets.CloudWatchLogGroup(logGroup));

      // Add the SQS queue as a target for the EventBridge rule
      rule.addTarget(
        new targets.SqsQueue(deploymentQueue, {
          messageGroupId: 'studio-api-deployment-group',
          deadLetterQueue: EventBridgeDlq,
        })
      );
      // Grant necessary permissions to the SQS queue
      deploymentQueue.grantSendMessages(new iam.ServicePrincipal('events.amazonaws.com'));

      // Add the Lambda function as a target for the SQS queue
      deploymentFunctionQueued.addEventSource(
        new lambdaEventSources.SqsEventSource(deploymentQueue, {
          batchSize: 1, // Process one message at a time
        })
      );
      // Override Event Source Mapping Logical ID at creation time to avoid conflicts with future mappings
      if (props.accountStage === 'staging') {
        // Use a more targeted approach - find the specific Event Source Mapping via construct tree
        cdk.Aspects.of(deploymentFunctionQueued).add({
          visit: (node: any) => {
            // Only target Event Source Mappings that are children of CodeDeployFunctionQueued
            if (node.constructor.name === 'CfnEventSourceMapping') {
              node.overrideLogicalId(
                'StudioApiFargateServiceCodeDeployFunctionQueuedSqsEventSourceBackendInfraStackStudioApiFargateServicestudioapideploymentqueue3F6F6D1465322DB0'
              );
            }
          }
        });
      }

    } else {
      rule.addTarget(new targets.LambdaFunction(deploymentFunction));
    }
  }
}
