import * as cdk from 'aws-cdk-lib';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { IVpc } from 'aws-cdk-lib/aws-ec2';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';
import { certificate } from '../certificate/studio-api-certificate'; // Import the certificate
import * as certManager from 'aws-cdk-lib/aws-certificatemanager';
import * as s3 from 'aws-cdk-lib/aws-s3';

export const setupGrpcLoadBalancer = (scope: Construct, vpc: IVpc, subnets: ec2.ISubnet[], certificate: certManager.ICertificate) => {
  // Create a security group for the load balancer
  const loadBalancerSecurityGroup = new ec2.SecurityGroup(scope, 'GrpcLoadBalancerSG', {
    vpc: vpc,
    allowAllOutbound: true,
    description: 'BackendInfraStack/grpcLoadBalancer/GrpcLoadBalancerSG',
  });

  loadBalancerSecurityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(80), 'Allow HTTP traffic');

  // Allow HTTPS traffic on port 443
  loadBalancerSecurityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(443), 'Allow HTTPS traffic');

  // Create an S3 bucket for ALB logs
  const albLogBucket = new s3.Bucket(scope, 'AlbLogBucket', {
    removalPolicy: cdk.RemovalPolicy.DESTROY,
    autoDeleteObjects: true,
  });

  const loadBalancer = new elbv2.ApplicationLoadBalancer(scope, 'GrpcLoadBalancer', {
    vpc,
    vpcSubnets: {
      subnets: subnets,
    },
    internetFacing: true,
    securityGroup: loadBalancerSecurityGroup,
    idleTimeout: cdk.Duration.seconds(600), // Set idle timeout for the load balancer
  });

  // Enable access logging
  loadBalancer.logAccessLogs(albLogBucket);

  const blueTargetGroup = new elbv2.ApplicationTargetGroup(scope, 'GrpcBlueTargetGroup', {
    vpc,
    port: 50051,
    protocol: elbv2.ApplicationProtocol.HTTP,
    protocolVersion: elbv2.ApplicationProtocolVersion.GRPC,
    targetType: elbv2.TargetType.IP,
    healthCheck: {
      path: '/grpc.health.v1.Health/Check',
      port: '50051',
      interval: cdk.Duration.seconds(30),
      timeout: cdk.Duration.seconds(5),
      healthyThresholdCount: 2,
      unhealthyThresholdCount: 2,
      healthyGrpcCodes: '0',
    },
  });

  const greenTargetGroup = new elbv2.ApplicationTargetGroup(scope, 'GrpcGreenTargetGroup', {
    vpc,
    port: 50051,
    protocol: elbv2.ApplicationProtocol.HTTP,
    protocolVersion: elbv2.ApplicationProtocolVersion.GRPC,
    targetType: elbv2.TargetType.IP,
    healthCheck: {
      path: '/grpc.health.v1.Health/Check',
      port: '50051',
      interval: cdk.Duration.seconds(30),
      timeout: cdk.Duration.seconds(5),
      healthyThresholdCount: 2,
      unhealthyThresholdCount: 2,
      healthyGrpcCodes: '0',
    },
  });

  // Add listener for HTTP (port 80) and redirect to HTTPS (port 443)
  const httpListener = loadBalancer.addListener('GrpcHttpListener', {
    port: 80,
    defaultAction: elbv2.ListenerAction.redirect({
      protocol: 'HTTPS',
      port: '443',
      permanent: true,
    }),
  });

  // Add listener for HTTPS (port 443) with HTTP/2 support
  const httpsListener = loadBalancer.addListener('GrpcHttpsListener', {
    port: 443,
    protocol: elbv2.ApplicationProtocol.HTTPS,
    certificates: [certificate],
    sslPolicy: elbv2.SslPolicy.TLS12, // Ensure TLS 1.2 for HTTP/2
    defaultTargetGroups: [blueTargetGroup],
  });

  // return { loadBalancer, blueTargetGroup, greenTargetGroup, httpsListener, loadBalancerSecurityGroup };
  return { loadBalancer, blueTargetGroup, greenTargetGroup, httpsListener, loadBalancerSecurityGroup };
};
