import { Construct } from 'constructs';
import * as certManager from 'aws-cdk-lib/aws-certificatemanager';
import * as logs from 'aws-cdk-lib/aws-logs';
import { aws_apigatewayv2, aws_apigatewayv2_integrations, Duration } from 'aws-cdk-lib';
import { ApplicationListener } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { VpcLink } from 'aws-cdk-lib/aws-apigatewayv2';
import * as cdk from 'aws-cdk-lib';

export const createApiGateway = (
  scope: Construct,
  certificate: certManager.ICertificate,
  accountStage: string,
  vpcLink: VpcLink,
  httpListener: ApplicationListener,
  cloudFlare: boolean
) => {
  const suffix = cloudFlare ? `CloudFlare` : '';
  const domainName = new aws_apigatewayv2.DomainName(scope, `ecs${accountStage.charAt(0).toUpperCase() + accountStage.slice(1)}Domain` + suffix, {
    // domainName: `studio-api.${accountStage}.suno.com`,
    domainName: cloudFlare ? `studio-api-${accountStage}.suno.com` : `studio-api.${accountStage}.suno.com`,
    certificate,
  });

  const logGroup = new logs.LogGroup(scope, 'StudioApiApiGatewayAccessLogs' + suffix, {
    logGroupName: `/aws/apigateway/studio-api-${accountStage}${suffix.toLowerCase()}`,
    retention: logs.RetentionDays.ONE_WEEK,
    removalPolicy: cdk.RemovalPolicy.DESTROY, // Add removal policy
  });

  const studioApiHttpIntegration = new aws_apigatewayv2_integrations.HttpAlbIntegration('StudioApiHttpAlbIntegration' + suffix, httpListener, {
    vpcLink,
    parameterMapping: new aws_apigatewayv2.ParameterMapping()
      .appendHeader('x-source-ip', aws_apigatewayv2.MappingValue.contextVariable('identity.sourceIp'))
      .appendHeader('x-request-id', aws_apigatewayv2.MappingValue.contextVariable('requestId')),
  });

  var gatewayOptions: aws_apigatewayv2.HttpApiProps = {
    apiName: 'Fargate Service API' + suffix,
    description: 'This service serves the Studio API Fargate service.',
    createDefaultStage: true,
    defaultIntegration: studioApiHttpIntegration,
  };

  // Add CORS headers for prod gateway
  if (accountStage === 'prod') {
    gatewayOptions = {
      apiName: 'Fargate Service API' + suffix,
      description: 'This service serves the Studio API Fargate service.',
      createDefaultStage: true,
      defaultIntegration: studioApiHttpIntegration,
      corsPreflight: {
        allowHeaders: [
          'Content-Type',
          'Authorization',
          'X-Requested-With',
          'X-Forwarded-For',
          'X-Forwarded-Proto',
          'X-Forwarded-Port',
          'Accept',
          'affiliate-id',
          'Device-Id',
          'Browser-Token',
          'Referring-Pathname',
          'Referring-Url-Params',
          'Anonymous-Id',
          'session-id',
          'traceparent',
          'tracestate',
          'x-datadog-origin',
          'x-datadog-parent-id',
          'x-datadog-sampling-priority',
          'x-datadog-trace-id',
          'Date',
        ],
        allowMethods: [aws_apigatewayv2.CorsHttpMethod.ANY],
        allowOrigins: ['*'],
        exposeHeaders: ['session-id'],
        maxAge: Duration.hours(1),
      },
    };
  }

  const api = new aws_apigatewayv2.HttpApi(scope, 'StudioApiApiGateway' + suffix, gatewayOptions);

  // Add routes to the HTTP API
  const addRoute = (path: string) => {
    api.addRoutes({
      path,
      methods: [aws_apigatewayv2.HttpMethod.ANY],
      integration: studioApiHttpIntegration,
    });
  };

  // Add routes to the HTTP API
  api.addRoutes({
    path: '/api/{proxy+}',
    methods: [aws_apigatewayv2.HttpMethod.ANY],
    integration: studioApiHttpIntegration,
  });
  addRoute('/margu');
  addRoute('/margu/{proxy+}');
  addRoute('/static/{proxy+}');
  addRoute('/{proxy+}');

  // Simple stage creation
  const stage = new aws_apigatewayv2.HttpStage(scope, 'StudioApiDefaultStage' + suffix, {
    httpApi: api,
    stageName: 'Prod',
    autoDeploy: true,
  });

  // Configure logging and throttling at the CFN level
  const cfnStage = stage.node.defaultChild as aws_apigatewayv2.CfnStage;

  // Sample only errors and slow requests (instead of all requests)
  cfnStage.accessLogSettings = {
    destinationArn: logGroup.logGroupArn,
    format: JSON.stringify({
      requestId: '$context.requestId',
      timestamp: '$context.requestTime',
      method: '$context.httpMethod',
      path: '$context.path',
      status: '$context.status',
      latency: '$context.responseLatency',
      ip: '$context.identity.sourceIp',
      logLevel: '$context.status >= 400 ? "ERROR" : ($context.responseLatency > 1000 ? "SLOW" : "INFO")',
    }),
  };

  // Create metric filters that only process samples
  // Sample 1% of successful requests
  new logs.MetricFilter(scope, 'ApiSampledSuccessFilter' + suffix, {
    logGroup,
    metricNamespace: 'StudioAPI/Sampled',
    metricName: 'SampledSuccessRequests',
    metricValue: '1',
    defaultValue: 0,
    // Only process ~1% of 2xx requests (based on last digit of requestId)
    filterPattern: logs.FilterPattern.literal('{ $.status < 300 && $.requestId = "*0" }'),
  });

  // Always log errors (100% sampling)
  new logs.MetricFilter(scope, 'ApiAllErrorsFilter' + suffix, {
    logGroup,
    metricNamespace: 'StudioAPI/Errors',
    metricName: 'AllErrors',
    metricValue: '1',
    defaultValue: 0,
    filterPattern: logs.FilterPattern.literal('{ $.status >= 400 }'),
  });

  // Always log slow requests (100% sampling)
  new logs.MetricFilter(scope, 'ApiSlowRequestsFilter' + suffix, {
    logGroup,
    metricNamespace: 'StudioAPI/Performance',
    metricName: 'SlowRequests',
    metricValue: '1',
    defaultValue: 0,
    filterPattern: logs.FilterPattern.literal('{ $.latency > 2000 }'),
  });

  // Default route settings
  cfnStage.defaultRouteSettings = {
    detailedMetricsEnabled: true,
    throttlingRateLimit: 25000,
    throttlingBurstLimit: 50000,
  };

  new aws_apigatewayv2.ApiMapping(scope, 'StudioApiBasePathMapping' + suffix, {
    domainName,
    api,
    stage,
  });

  return api;
};
