AWSTemplateFormatVersion: '2010-09-09'
Description: |
  Language Services Platform - Master Stack
  Deploys a complete Language Services application with ECS Fargate, ALB, S3, and Secrets Manager.
  For AWS Marketplace deployment.

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Application Configuration"
        Parameters:
          - AppName
          - Environment
          - LicenseKey
      - Label:
          default: "Network Configuration"
        Parameters:
          - VpcCIDR
          - PublicSubnet1CIDR
          - PublicSubnet2CIDR
          - PrivateSubnet1CIDR
          - PrivateSubnet2CIDR
      - Label:
          default: "ECS Configuration"
        Parameters:
          - ContainerImage
          - TaskCPU
          - TaskMemory
          - DesiredCount
          - MinCapacity
          - MaxCapacity
      - Label:
          default: "Authentication"
        Parameters:
          - AuthUsername
          - AuthPassword
          - AuthSecret
      - Label:
          default: "API Keys"
        Parameters:
          - OpenAIApiKey
      - Label:
          default: "Domain Configuration (Optional)"
        Parameters:
          - DomainName
          - CertificateArn

Parameters:
  # Application Configuration
  AppName:
    Type: String
    Default: language-services
    Description: Name of the application (used for resource naming)
    AllowedPattern: ^[a-z0-9-]+$
    ConstraintDescription: Must be lowercase alphanumeric with hyphens

  Environment:
    Type: String
    Default: production
    AllowedValues:
      - development
      - staging
      - production
    Description: Deployment environment

  LicenseKey:
    Type: String
    NoEcho: true
    Description: License key for the Language Services application
    MinLength: 1

  # Network Configuration
  VpcCIDR:
    Type: String
    Default: 10.0.0.0/16
    Description: CIDR block for the VPC

  PublicSubnet1CIDR:
    Type: String
    Default: 10.0.1.0/24
    Description: CIDR block for Public Subnet 1

  PublicSubnet2CIDR:
    Type: String
    Default: 10.0.2.0/24
    Description: CIDR block for Public Subnet 2

  PrivateSubnet1CIDR:
    Type: String
    Default: 10.0.3.0/24
    Description: CIDR block for Private Subnet 1

  PrivateSubnet2CIDR:
    Type: String
    Default: 10.0.4.0/24
    Description: CIDR block for Private Subnet 2

  # ECS Configuration
  ContainerImage:
    Type: String
    Description: Docker image URI for the application (ECR or Docker Hub)
    Default: ''

  TaskCPU:
    Type: Number
    Default: 1024
    AllowedValues:
      - 256
      - 512
      - 1024
      - 2048
      - 4096
    Description: CPU units for the ECS task (1024 = 1 vCPU)

  TaskMemory:
    Type: Number
    Default: 2048
    AllowedValues:
      - 512
      - 1024
      - 2048
      - 4096
      - 8192
      - 16384
    Description: Memory (MB) for the ECS task

  DesiredCount:
    Type: Number
    Default: 2
    MinValue: 1
    MaxValue: 10
    Description: Desired number of ECS tasks

  MinCapacity:
    Type: Number
    Default: 1
    MinValue: 1
    Description: Minimum number of tasks for auto-scaling

  MaxCapacity:
    Type: Number
    Default: 4
    MinValue: 1
    MaxValue: 20
    Description: Maximum number of tasks for auto-scaling

  # Authentication
  AuthUsername:
    Type: String
    Default: admin
    Description: Username for application authentication
    MinLength: 3

  AuthPassword:
    Type: String
    NoEcho: true
    Description: Password for application authentication
    MinLength: 8

  AuthSecret:
    Type: String
    NoEcho: true
    Description: JWT secret for authentication tokens (min 32 characters recommended)
    MinLength: 16

  # API Keys
  OpenAIApiKey:
    Type: String
    NoEcho: true
    Description: OpenAI API key (optional - for AI-powered features)
    Default: ''

  # Domain Configuration
  DomainName:
    Type: String
    Default: ''
    Description: Custom domain name (optional)

  CertificateArn:
    Type: String
    Default: ''
    Description: ACM Certificate ARN for HTTPS (required if DomainName is provided)

Conditions:
  HasCustomDomain: !Not [!Equals [!Ref DomainName, '']]
  HasCertificate: !Not [!Equals [!Ref CertificateArn, '']]
  UseHTTPS: !And [!Condition HasCustomDomain, !Condition HasCertificate]
  HasOpenAIKey: !Not [!Equals [!Ref OpenAIApiKey, '']]

Resources:
  #############################################
  # VPC and Networking
  #############################################
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-vpc

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-igw

  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs '']
      CidrBlock: !Ref PublicSubnet1CIDR
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-public-1

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [1, !GetAZs '']
      CidrBlock: !Ref PublicSubnet2CIDR
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-public-2

  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs '']
      CidrBlock: !Ref PrivateSubnet1CIDR
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-private-1

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [1, !GetAZs '']
      CidrBlock: !Ref PrivateSubnet2CIDR
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-private-2

  # NAT Gateway for private subnets
  NatGatewayEIP:
    Type: AWS::EC2::EIP
    DependsOn: InternetGatewayAttachment
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-nat-eip

  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NatGatewayEIP.AllocationId
      SubnetId: !Ref PublicSubnet1
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-nat

  # Route Tables
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-public-rt

  DefaultPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet1

  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet2

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-private-rt

  DefaultPrivateRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnet1

  PrivateSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnet2

  #############################################
  # Security Groups
  #############################################
  ALBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${AppName}-${Environment}-alb-sg
      GroupDescription: Security group for Application Load Balancer
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
          Description: HTTP access
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
          Description: HTTPS access
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-alb-sg

  ECSSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${AppName}-${Environment}-ecs-sg
      GroupDescription: Security group for ECS tasks
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3000
          ToPort: 3000
          SourceSecurityGroupId: !Ref ALBSecurityGroup
          Description: Frontend from ALB
        - IpProtocol: tcp
          FromPort: 5000
          ToPort: 5000
          SourceSecurityGroupId: !Ref ALBSecurityGroup
          Description: Backend from ALB
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-ecs-sg

  # VPC Endpoints for AWS Services (reduces NAT costs and improves security)
  S3VPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcId: !Ref VPC
      RouteTableIds:
        - !Ref PrivateRouteTable
      VpcEndpointType: Gateway

  #############################################
  # S3 Buckets
  #############################################
  InputBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      BucketName: !Sub ${AppName}-${Environment}-input-${AWS::AccountId}
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      VersioningConfiguration:
        Status: Enabled
      LifecycleConfiguration:
        Rules:
          - Id: DeleteOldFiles
            Status: Enabled
            ExpirationInDays: 30
          - Id: DeleteIncompleteMultipartUploads
            Status: Enabled
            AbortIncompleteMultipartUpload:
              DaysAfterInitiation: 7
      CorsConfiguration:
        CorsRules:
          - AllowedHeaders: ['*']
            AllowedMethods: [GET, PUT, POST, DELETE, HEAD]
            AllowedOrigins: ['*']
            MaxAge: 3000
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-input

  OutputBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      BucketName: !Sub ${AppName}-${Environment}-output-${AWS::AccountId}
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      VersioningConfiguration:
        Status: Enabled
      LifecycleConfiguration:
        Rules:
          - Id: DeleteOldFiles
            Status: Enabled
            ExpirationInDays: 90
          - Id: DeleteIncompleteMultipartUploads
            Status: Enabled
            AbortIncompleteMultipartUpload:
              DaysAfterInitiation: 7
      CorsConfiguration:
        CorsRules:
          - AllowedHeaders: ['*']
            AllowedMethods: [GET, PUT, POST, DELETE, HEAD]
            AllowedOrigins: ['*']
            MaxAge: 3000
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-output

  #############################################
  # Secrets Manager
  #############################################
  ApplicationSecrets:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: !Sub ${AppName}-${Environment}-secrets
      Description: Application secrets for Language Services
      SecretString: !Sub |
        {
          "OPENAI_API_KEY": "${OpenAIApiKey}",
          "USER_NAME": "${AuthUsername}",
          "PASSWORD": "${AuthPassword}",
          "LICENSE_KEY": "${LicenseKey}",
          "AUTH_SECRET": "${AuthSecret}"
        }
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-secrets

  #############################################
  # IAM Roles and Policies
  #############################################
  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${AppName}-${Environment}-ecs-execution-role
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
      Policies:
        - PolicyName: SecretsManagerAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - secretsmanager:GetSecretValue
                Resource: !Ref ApplicationSecrets
        - PolicyName: CloudWatchLogsAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${AppName}-${Environment}*

  ECSTaskRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${AppName}-${Environment}-ecs-task-role
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: S3Access
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:DeleteObject
                  - s3:ListBucket
                  - s3:GetBucketLocation
                Resource:
                  - !GetAtt InputBucket.Arn
                  - !Sub ${InputBucket.Arn}/*
                  - !GetAtt OutputBucket.Arn
                  - !Sub ${OutputBucket.Arn}/*
        - PolicyName: TextractAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - textract:AnalyzeDocument
                  - textract:DetectDocumentText
                  - textract:AnalyzeExpense
                  - textract:StartDocumentAnalysis
                  - textract:StartDocumentTextDetection
                  - textract:GetDocumentAnalysis
                  - textract:GetDocumentTextDetection
                Resource: '*'
        - PolicyName: TranscribeAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - transcribe:StartTranscriptionJob
                  - transcribe:StartMedicalTranscriptionJob
                  - transcribe:GetTranscriptionJob
                  - transcribe:GetMedicalTranscriptionJob
                  - transcribe:DeleteTranscriptionJob
                  - transcribe:DeleteMedicalTranscriptionJob
                  - transcribe:ListTranscriptionJobs
                  - transcribe:ListMedicalTranscriptionJobs
                Resource: '*'
        - PolicyName: TranslateAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - translate:TranslateText
                  - translate:TranslateDocument
                  - translate:ListLanguages
                Resource: '*'
        - PolicyName: PollyAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - polly:SynthesizeSpeech
                  - polly:DescribeVoices
                  - polly:GetLexicon
                  - polly:ListLexicons
                Resource: '*'
        - PolicyName: ComprehendAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - comprehend:DetectDominantLanguage
                  - comprehend:DetectEntities
                  - comprehend:DetectKeyPhrases
                  - comprehend:DetectSentiment
                  - comprehend:DetectSyntax
                  - comprehendmedical:DetectEntitiesV2
                  - comprehendmedical:DetectPHI
                  - comprehendmedical:InferICD10CM
                  - comprehendmedical:InferRxNorm
                Resource: '*'
        - PolicyName: STSAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - sts:GetCallerIdentity
                Resource: '*'
        - PolicyName: SecretsManagerRefresh
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - secretsmanager:GetSecretValue
                Resource: !Ref ApplicationSecrets

  #############################################
  # CloudWatch Logs
  #############################################
  ECSLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /ecs/${AppName}-${Environment}
      RetentionInDays: 30

  #############################################
  # ECS Cluster and Service
  #############################################
  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub ${AppName}-${Environment}-cluster
      ClusterSettings:
        - Name: containerInsights
          Value: enabled
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-cluster

  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Sub ${AppName}-${Environment}
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      Cpu: !Ref TaskCPU
      Memory: !Ref TaskMemory
      ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
      TaskRoleArn: !GetAtt ECSTaskRole.Arn
      ContainerDefinitions:
        - Name: !Sub ${AppName}-app
          Image: !Ref ContainerImage
          Essential: true
          PortMappings:
            - ContainerPort: 3000
              Protocol: tcp
              Name: frontend
            - ContainerPort: 5000
              Protocol: tcp
              Name: backend
          Environment:
            - Name: NODE_ENV
              Value: production
            - Name: AWS_REGION
              Value: !Ref AWS::Region
            - Name: AI_FOR_YOU_INPUT
              Value: !Ref InputBucket
            - Name: AI_FOR_YOU_OUTPUT
              Value: !Ref OutputBucket
            - Name: APPLICATION_SECRETS
              Value: !Ref ApplicationSecrets
            - Name: NEXT_PUBLIC_API_URL
              Value: !If
                - UseHTTPS
                - !Sub https://${DomainName}
                - !Sub http://${ApplicationLoadBalancer.DNSName}
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref ECSLogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: ecs
          HealthCheck:
            Command:
              - CMD-SHELL
              - curl -f http://localhost:5000/health || exit 1
            Interval: 30
            Timeout: 5
            Retries: 3
            StartPeriod: 60

  #############################################
  # Application Load Balancer
  #############################################
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Sub ${AppName}-${Environment}-alb
      Type: application
      Scheme: internet-facing
      SecurityGroups:
        - !Ref ALBSecurityGroup
      Subnets:
        - !Ref PublicSubnet1
        - !Ref PublicSubnet2
      Tags:
        - Key: Name
          Value: !Sub ${AppName}-${Environment}-alb

  # Target Group for Frontend (Next.js)
  FrontendTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${AppName}-${Environment}-frontend-tg
      Port: 3000
      Protocol: HTTP
      VpcId: !Ref VPC
      TargetType: ip
      HealthCheckEnabled: true
      HealthCheckPath: /
      HealthCheckProtocol: HTTP
      HealthCheckIntervalSeconds: 30
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 3
      Matcher:
        HttpCode: 200-399

  # Target Group for Backend API
  BackendTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${AppName}-${Environment}-backend-tg
      Port: 5000
      Protocol: HTTP
      VpcId: !Ref VPC
      TargetType: ip
      HealthCheckEnabled: true
      HealthCheckPath: /health
      HealthCheckProtocol: HTTP
      HealthCheckIntervalSeconds: 30
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 3
      Matcher:
        HttpCode: 200

  # HTTP Listener
  HTTPListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP
      DefaultActions:
        - !If
          - UseHTTPS
          - Type: redirect
            RedirectConfig:
              Protocol: HTTPS
              Port: '443'
              StatusCode: HTTP_301
          - Type: forward
            TargetGroupArn: !Ref FrontendTargetGroup

  # HTTPS Listener (conditional)
  HTTPSListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Condition: UseHTTPS
    Properties:
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 443
      Protocol: HTTPS
      Certificates:
        - CertificateArn: !Ref CertificateArn
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref FrontendTargetGroup

  # Listener Rule for API routes
  APIListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      ListenerArn: !If [UseHTTPS, !Ref HTTPSListener, !Ref HTTPListener]
      Priority: 1
      Conditions:
        - Field: path-pattern
          Values:
            - /api/*
            - /health
      Actions:
        - Type: forward
          TargetGroupArn: !Ref BackendTargetGroup

  #############################################
  # ECS Service
  #############################################
  ECSService:
    Type: AWS::ECS::Service
    DependsOn:
      - HTTPListener
    Properties:
      ServiceName: !Sub ${AppName}-${Environment}-service
      Cluster: !Ref ECSCluster
      TaskDefinition: !Ref TaskDefinition
      DesiredCount: !Ref DesiredCount
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: DISABLED
          SecurityGroups:
            - !Ref ECSSecurityGroup
          Subnets:
            - !Ref PrivateSubnet1
            - !Ref PrivateSubnet2
      LoadBalancers:
        - ContainerName: !Sub ${AppName}-app
          ContainerPort: 3000
          TargetGroupArn: !Ref FrontendTargetGroup
        - ContainerName: !Sub ${AppName}-app
          ContainerPort: 5000
          TargetGroupArn: !Ref BackendTargetGroup
      HealthCheckGracePeriodSeconds: 120
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 50
        DeploymentCircuitBreaker:
          Enable: true
          Rollback: true

  #############################################
  # Auto Scaling
  #############################################
  ServiceAutoScalingTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    Properties:
      MaxCapacity: !Ref MaxCapacity
      MinCapacity: !Ref MinCapacity
      ResourceId: !Sub service/${ECSCluster}/${ECSService.Name}
      RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService
      ScalableDimension: ecs:service:DesiredCount
      ServiceNamespace: ecs

  ServiceAutoScalingPolicyCPU:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: !Sub ${AppName}-${Environment}-cpu-scaling
      PolicyType: TargetTrackingScaling
      ScalingTargetId: !Ref ServiceAutoScalingTarget
      TargetTrackingScalingPolicyConfiguration:
        PredefinedMetricSpecification:
          PredefinedMetricType: ECSServiceAverageCPUUtilization
        TargetValue: 70
        ScaleInCooldown: 300
        ScaleOutCooldown: 60

  ServiceAutoScalingPolicyMemory:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: !Sub ${AppName}-${Environment}-memory-scaling
      PolicyType: TargetTrackingScaling
      ScalingTargetId: !Ref ServiceAutoScalingTarget
      TargetTrackingScalingPolicyConfiguration:
        PredefinedMetricSpecification:
          PredefinedMetricType: ECSServiceAverageMemoryUtilization
        TargetValue: 80
        ScaleInCooldown: 300
        ScaleOutCooldown: 60

Outputs:
  VPCId:
    Description: VPC ID
    Value: !Ref VPC
    Export:
      Name: !Sub ${AppName}-${Environment}-VPCId

  ApplicationURL:
    Description: Application URL
    Value: !If
      - UseHTTPS
      - !Sub https://${DomainName}
      - !Sub http://${ApplicationLoadBalancer.DNSName}

  ALBDNSName:
    Description: Application Load Balancer DNS Name
    Value: !GetAtt ApplicationLoadBalancer.DNSName

  ECSClusterName:
    Description: ECS Cluster Name
    Value: !Ref ECSCluster

  ECSServiceName:
    Description: ECS Service Name
    Value: !GetAtt ECSService.Name

  InputBucketName:
    Description: S3 Input Bucket Name
    Value: !Ref InputBucket

  OutputBucketName:
    Description: S3 Output Bucket Name
    Value: !Ref OutputBucket

  SecretsArn:
    Description: Secrets Manager ARN
    Value: !Ref ApplicationSecrets

  TaskRoleArn:
    Description: ECS Task Role ARN
    Value: !GetAtt ECSTaskRole.Arn

  ExecutionRoleArn:
    Description: ECS Task Execution Role ARN
    Value: !GetAtt ECSTaskExecutionRole.Arn

  LogGroupName:
    Description: CloudWatch Log Group Name
    Value: !Ref ECSLogGroup
