import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';
import { config } from '../../config';
import * as rds from 'aws-cdk-lib/aws-rds';
import { GoogleTagManagerService } from './google-tag-manager/google-tag-manager-service';
import { GoogleTagManagerMainService } from './google-tag-manager/google-tag-manager-main-service';
import { setupGTMLoadBalancer } from './google-tag-manager/google-tag-manager-load-balancer';
import { setupGTMMainLoadBalancer } from './google-tag-manager/google-tag-manager-main-load-balancer';
import { certificate } from '../backend-infra-stack/certificate/studio-api-certificate';
import * as ecs from 'aws-cdk-lib/aws-ecs';
export interface SunoContentStackProps extends cdk.StackProps {
  accountStage: string;
  region: string;
}

interface CidrMap {
  [key: string]: {
    [region: string]: string;
  };
}

export class SunoContentStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: SunoContentStackProps) {
    super(scope, id, props);

    const cidrMap: CidrMap = {
      staging: {
        'us-east-2': '10.7.0.0/16',
      },
      prod: {
        'us-east-2': '10.8.0.0/16',
      },
    };
    new cdk.CfnOutput(this, 'VpcCidr', {
      value: cidrMap[props.accountStage][props.region],
    });

    // VPC Configuration
    const sunoContentVpc = new ec2.Vpc(this, 'SunoContent', {
      vpcName: 'suno-content-vpc',
      cidr: cidrMap[props.accountStage][props.region],
      maxAzs: 3, // 3 Availability Zones
      subnetConfiguration: [
        {
          cidrMask: 24, // /24 subnets for public
          name: 'suno-content-vpc-public-',
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          cidrMask: 24, // /24 subnets for private
          name: 'suno-content-vpc-app-',
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        },
        {
          cidrMask: 24, // /24 subnets for private
          name: 'suno-content-vpc-app-lambda-',
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        },
        {
          cidrMask: 24, // /24 subnets for private
          name: 'suno-content-vpc-database-',
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        },
      ],
      natGateways: 3,
    });

    const securityGroup = new ec2.SecurityGroup(this, 'SunoContentSecurityGroup', {
      vpc: ec2.Vpc.fromVpcAttributes(this, 'Vpc', {
        vpcId: sunoContentVpc.vpcId,
        availabilityZones: ['us-east-2a', 'us-east-2b', 'us-east-2c'], // Replace with your availability zones
        publicSubnetIds: sunoContentVpc.publicSubnets.map((subnet) => subnet.subnetId),
      }),
      description: 'Allow suno content outbound access',
      allowAllOutbound: true,
      securityGroupName: 'SunoContentSecurityGroup',
    });

    securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(5432), 'Allow PostgreSQL traffic');

    // Aurora PostgreSQL engine (use 16.x for now; upgrade to 17 when region/CDK support it)
    const sunoContentPublicPgEngine = rds.DatabaseClusterEngine.auroraPostgres({
      version: rds.AuroraPostgresEngineVersion.VER_17_5,
    });

    // Custom cluster parameter group (add params as needed)
    const sunoContentPublicPgParamGroup = new rds.ParameterGroup(this, 'SunoContentPublicPgParamGroup', {
      engine: sunoContentPublicPgEngine,
      name: 'suno-content-postgresql-17-5',
      description: 'Suno Content PostgreSQL parameter group',
      parameters: {
        // e.g. 'max_connections': '500'
      },
    });

    const sunoContentPublicDbSubnetConstructs = sunoContentVpc.publicSubnets.map((subnet) =>
      ec2.Subnet.fromSubnetId(this, `SunoContentPublicDbSubnet-${subnet.subnetId}`, subnet.subnetId)
    );

    // Aurora cluster with r8g.4xlarge writer
    const sunoContentPublicCluster = new rds.DatabaseCluster(this, 'SunoContentPublicCluster', {
      clusterIdentifier: 'suno-content-public-cluster',
      engine: sunoContentPublicPgEngine,
      
      writer: rds.ClusterInstance.provisioned('SunoContentPublicWriterInstance', {
        instanceIdentifier: 'suno-content-public-writer',
        instanceType: ec2.InstanceType.of(ec2.InstanceClass.R8G, props.accountStage === 'prod' ? ec2.InstanceSize.XLARGE2 : ec2.InstanceSize.XLARGE),
        publiclyAccessible: true,
      }),
      vpc: sunoContentVpc,
      vpcSubnets:  { subnets: sunoContentPublicDbSubnetConstructs },
      securityGroups: [securityGroup],
      parameterGroup: sunoContentPublicPgParamGroup,
      storageType: rds.DBClusterStorageType.AURORA_IOPT1,
      defaultDatabaseName: 'suno_content_public',
      removalPolicy: cdk.RemovalPolicy.RETAIN,
      backup: { retention: cdk.Duration.days(7) },
      cloudwatchLogsExports: ['postgresql'],
    });

    // RDS Proxy in front of the cluster
    const sunoContentPublicProxy = new rds.DatabaseProxy(this, 'SunoContentPublicProxy', {
      dbProxyName: 'suno-content-public-proxy',
      proxyTarget: rds.ProxyTarget.fromCluster(sunoContentPublicCluster),
      vpc: sunoContentVpc,
      securityGroups: [securityGroup],
      secrets: [sunoContentPublicCluster.secret!],
      requireTLS: false,
      iamAuth: false,
    });

    // Outputs for convenience
    new cdk.CfnOutput(this, 'SunoContentPublicClusterEndpoint', {
      value: sunoContentPublicCluster.clusterEndpoint.hostname,
      exportName: 'SunoContentPublicClusterEndpoint',
    });
    new cdk.CfnOutput(this, 'SunoContentPublicReaderEndpoint', {
      value: sunoContentPublicCluster.clusterReadEndpoint.hostname,
      exportName: 'SunoContentPublicReaderEndpoint',
    });
    new cdk.CfnOutput(this, 'SunoContentPublicProxyEndpoint', {
      value: sunoContentPublicProxy.endpoint,
      exportName: 'SunoContentPublicProxyEndpoint',
    });

    const sunoContentEcsCluster = new ecs.Cluster(this, 'SunoContentEcsCluster', {
      clusterName: 'suno-content-ecs-cluster',
      vpc: sunoContentVpc,
    });

    // Get the Cloudflare wildcard certificate (*.suno.com)
    const gtmCertificate = certificate(this, props.accountStage, true);

    // Select public subnets for the internet-facing ALBs
    const publicSubnets = sunoContentVpc.selectSubnets({
      subnetType: ec2.SubnetType.PUBLIC,
    });

    // Select app subnets for GTM services (private subnets)
    const appSubnets = sunoContentVpc.selectSubnets({
      subnetGroupName: 'suno-content-vpc-app-',
    });

    // ========== GTM Preview Server Setup ==========
    // Set up the ALB for GTM Preview service
    const gtmPreviewLoadBalancer = setupGTMLoadBalancer(
      this,
      sunoContentVpc,
      publicSubnets.subnets,
      gtmCertificate
    );

    const googleTagManagerPreviewService = new GoogleTagManagerService(this, 'GoogleTagManagerService', {
      accountStage: props.accountStage,
      cluster: sunoContentEcsCluster,
      vpc: sunoContentVpc,
      subnets: appSubnets.subnets,
      targetGroup: gtmPreviewLoadBalancer.targetGroup,
      loadBalancerSecurityGroup: gtmPreviewLoadBalancer.loadBalancerSecurityGroup,
    });

    // Output the Preview ALB DNS name
    new cdk.CfnOutput(this, 'GTMLoadBalancerDNS', {
      value: gtmPreviewLoadBalancer.loadBalancer.loadBalancerDnsName,
      description: 'DNS name of the GTM Preview Load Balancer (point suno-content.suno.com to this)',
    });

    // ========== GTM Main Cluster Server Setup ==========
    // Set up the ALB for GTM Main service
    const gtmMainLoadBalancer = setupGTMMainLoadBalancer(
      this,
      sunoContentVpc,
      publicSubnets.subnets,
      gtmCertificate
    );

    const googleTagManagerMainService = new GoogleTagManagerMainService(this, 'GoogleTagManagerMainService', {
      accountStage: props.accountStage,
      cluster: sunoContentEcsCluster,
      vpc: sunoContentVpc,
      subnets: appSubnets.subnets,
      targetGroup: gtmMainLoadBalancer.targetGroup,
      loadBalancerSecurityGroup: gtmMainLoadBalancer.loadBalancerSecurityGroup,
    });

    // Determine the endpoint based on accountStage
    const mainEndpoint = props.accountStage === 'prod'
      ? 'suno-content-prod.suno.com'
      : 'suno-content-staging.suno.com';

    // Output the Main ALB DNS name
    new cdk.CfnOutput(this, 'GTMMainLoadBalancerDNS', {
      value: gtmMainLoadBalancer.loadBalancer.loadBalancerDnsName,
      description: `DNS name of the GTM Main Load Balancer (point ${mainEndpoint} to this)`,
    });
  }
}
