frameworkVersion: '2'
useDotenv: true

plugins:
  - serverless-finch

service: everest

package:
  individually: false
  exclude:
    - .husky/**
    - .aws-sam/**
    - test-reports/**
    - .idea/**
    - scripts/**
    - conf/**

custom:
  client:
    bucketName: ${self:custom.profiles.${opt:stage, self:provider.stage, 'sandbox'}.deploymentBucketName}
    distributionFolder: ./storybook-static
    indexDocument: index.html
    manageResources: false

  profiles:
    sandbox:
      awsProfile: sandbox
      deploymentBucketName: story-book-sandbox-${sls:instanceId}
    test:
      awsProfile: development
      deploymentBucketName: storybook.dev.noissue.io
      domain:
        storyBookHostedZone: storybook.dev.noissue.io
        hostedZone: ecommerce.dev.noissue.io
        hostedZoneId: Z01126303OM2A2E9RQZYM
        certificateArn: 'arn:aws:acm:us-west-2:689393824053:certificate/92a2805d-9346-4a3e-b219-d203082cc0f6'
        cloudfrontCertificateArn: 'arn:aws:acm:us-east-1:689393824053:certificate/51d252af-6ea0-491b-a7e1-fcc9237d220e'
        nzDomain: ecommerce.nz.dev.noissue.io
        auDomain: ecommerce.au.dev.noissue.io
        ukDomain: ecommerce.uk.dev.noissue.io
        usDomain: ecommerce.us.dev.noissue.io
        caDomain: ecommerce.ca.dev.noissue.io
    production:
      awsProfile: production
      domain:
        hostedZone: ecommerce.noissue.io
        nzDomain: noissue.co.nz
        auDomain: noissue.com.au
        ukDomain: noissue.co.uk
        usDomain: noissue.co
        caDomain: noissue.ca

provider:
  name: aws
  runtime: nodejs14.x
  lambdaHashingVersion: 20201221
  stage: sandbox
  region: us-west-2
  profile: ${self:custom.profiles.${opt:stage, self:provider.stage, 'sandbox'}.awsProfile}
  tracing:
    lambda: true
  memorySize: 128
  timeout: 300
  logs:
    frameworkLambda: true # Optional, whether to write CloudWatch logs for custom resource lambdas as added by the framework

resources:
  Conditions:
    CreateEcommerceSiteDomain:
      Fn::Not:
        - Fn::Equals:
            - ${opt:stage, self:provider.stage}
            - sandbox
    CreateStoryBookSiteDomain:
      Fn::Equals:
        - ${opt:stage, self:provider.stage}
        - test
  Parameters:
    ServiceName:
      Type: String
      Default: BigCommerceStore
      Description: Store front for BigCommerce Next Commerce store front

    ContainerPort:
      Type: Number
      Default: 3000
      Description: What port number the application inside the docker container is binding to

  Resources:
    # Try a very simple VPC for Everest Big Commerce cluster
    VPC:
      Type: AWS::EC2::VPC
      Properties:
        CidrBlock: 10.0.0.0/16
        EnableDnsSupport: true
        EnableDnsHostnames: true
        InstanceTenancy: default # An instance launched into the VPC runs on shared hardware by default

    InternetGateway:
      Type: AWS::EC2::InternetGateway

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

    RouteTable:
      Type: AWS::EC2::RouteTable
      Properties:
        VpcId: !Ref VPC
        Tags:
          - Key: Name
            Value: Public

    InternetRoute:
      Type: AWS::EC2::Route
      DependsOn: VPCGatewayAttachment
      Properties:
        RouteTableId: !Ref RouteTable
        DestinationCidrBlock: 0.0.0.0/0
        GatewayId: !Ref InternetGateway

    PublicSubnetBigCommerceOne:
      Type: AWS::EC2::Subnet
      Properties:
        VpcId: !Ref VPC
        CidrBlock: 10.0.0.0/24
        AvailabilityZone: !Select [0, !GetAZs ''] # Get the first AZ in the list
        MapPublicIpOnLaunch: true

    PublicSubnetBigCommerceOneRouteTableAssociation:
      Type: AWS::EC2::SubnetRouteTableAssociation
      Properties:
        RouteTableId: !Ref RouteTable
        SubnetId: !Ref PublicSubnetBigCommerceOne

    PublicSubnetBigCommerceTwo:
      Type: AWS::EC2::Subnet
      Properties:
        VpcId: !Ref VPC
        CidrBlock: 10.0.1.0/24
        AvailabilityZone: !Select [1, !GetAZs ''] # Get the second AZ in the list
        MapPublicIpOnLaunch: true

    PublicSubnetBigCommerceTwoRouteTableAssociation:
      Type: AWS::EC2::SubnetRouteTableAssociation
      Properties:
        RouteTableId: !Ref RouteTable
        SubnetId: !Ref PublicSubnetBigCommerceTwo

    # ECS Resources
    ECSCluster:
      Type: AWS::ECS::Cluster

    SecurityGroup:
      Type: AWS::EC2::SecurityGroup
      Properties:
        GroupName: 'Internet Group'
        GroupDescription: 'Simple internet group for Big Commerce Fargate cluster'
        VpcId: !Ref VPC
        # FIXME: Temporary for sandbox to access.
        SecurityGroupIngress:
          - IpProtocol: tcp
            FromPort: '3000'
            ToPort: '3000'
            CidrIp: 0.0.0.0/0
        SecurityGroupEgress:
          - IpProtocol: -1
            CidrIp: 0.0.0.0/0

    #adding this to avoid circular dependency
    SelfReferenceRule:
      Type: AWS::EC2::SecurityGroupIngress
      Properties:
        IpProtocol: '-1' #-1 used for all traffic
        SourceSecurityGroupId: !Ref SecurityGroup
        GroupId: !Ref SecurityGroup

    # This is an IAM role which authorizes ECS to manage resources on your
    # account on your behalf, such as updating your load balancer with the
    # details of where your containers are, so that traffic can reach your
    # containers.
    ECSRole:
      Type: AWS::IAM::Role
      Properties:
        AssumeRolePolicyDocument:
          Statement:
            - Effect: Allow
              Principal:
                Service: [ecs.amazonaws.com]
              Action: ['sts:AssumeRole']
        Path: /
        Policies:
          - PolicyName: ecs-service
            PolicyDocument:
              Statement:
                - Effect: Allow
                  Action:
                    # Rules which allow ECS to attach network interfaces to instances
                    # on your behalf in order for awsvpc networking mode to work right
                    - 'ec2:AttachNetworkInterface'
                    - 'ec2:CreateNetworkInterface'
                    - 'ec2:CreateNetworkInterfacePermission'
                    - 'ec2:DeleteNetworkInterface'
                    - 'ec2:DeleteNetworkInterfacePermission'
                    - 'ec2:Describe*'
                    - 'ec2:DetachNetworkInterface'
                  Resource: '*'

    # This is a role which is used by the ECS tasks themselves.
    ECSTaskExecutionRole:
      Type: AWS::IAM::Role
      Properties:
        AssumeRolePolicyDocument:
          Statement:
            - Effect: Allow
              Principal:
                Service: [ecs-tasks.amazonaws.com]
              Action: ['sts:AssumeRole']
        Path: /
        Policies:
          - PolicyName: AmazonECSTaskExecutionRolePolicy
            PolicyDocument:
              Statement:
                - Effect: Allow
                  Action:
                    # Allow the ECS Tasks to download images from ECR
                    - 'ecr:GetAuthorizationToken'
                    - 'ecr:BatchCheckLayerAvailability'
                    - 'ecr:GetDownloadUrlForLayer'
                    - 'ecr:BatchGetImage'

                    # Allow the ECS tasks to upload logs to CloudWatch
                    - 'logs:CreateLogGroup'
                    - 'logs:CreateLogStream'
                    - 'logs:PutLogEvents'
                  Resource: '*'

    # This is a role which is used by the code within tasks.
    ECSTaskRole:
      Type: AWS::IAM::Role
      Properties:
        AssumeRolePolicyDocument:
          Statement:
            - Effect: Allow
              Principal:
                Service: [ecs-tasks.amazonaws.com]
              Action: ['sts:AssumeRole']
        Path: /
        Policies:
          - PolicyName: AmazonECSTaskRolePolicy
            PolicyDocument:
              Statement:
                # Allow the ECS tasks to download and upload files to S3 bucket
                - Effect: Allow
                  Action:
                    # Allow the ECS tasks to upload logs to CloudWatch
                    - 'logs:CreateLogGroup'
                    - 'logs:CreateLogStream'
                    - 'logs:PutLogEvents'
                  Resource: '*'

    # This is a log group to which logs are saved.
    FargateLogGroup:
      Type: AWS::Logs::LogGroup
      Properties:
        LogGroupName: !Join ['', ['/ecs/fargate-', !Ref 'AWS::StackName']]

    # The task definition. This is a simple metadata description of what
    # container to run, and what resource requirements it has.
    FargateTaskDefinitionAU:
      Type: AWS::ECS::TaskDefinition
      Properties:
        Family: !Join ['', [!Ref 'ServiceName', '-AU']]
        Cpu: 1024 # 1 vCPU
        Memory: 4096 # 4G
        NetworkMode: awsvpc # Required by Fargate
        RequiresCompatibilities:
          - FARGATE
        ExecutionRoleArn: !Ref ECSTaskExecutionRole
        TaskRoleArn: !Ref ECSTaskRole
        ContainerDefinitions:
          - Name: !Join ['', [!Ref 'ServiceName', '-AU']]
            Cpu: 1024
            Memory: 4096
            Image: ${env:EVEREST_IMAGE_URL}:${env:TAG,'master'}_au
            Environment:
              - Name: BIGCOMMERCE_STOREFRONT_API_URL
                Value: ${env:BIGCOMMERCE_STOREFRONT_API_URL}
              - Name: BIGCOMMERCE_STOREFRONT_API_TOKEN
                Value: ${env:BIGCOMMERCE_STOREFRONT_API_TOKEN}
              - Name: BIGCOMMERCE_STORE_API_URL
                Value: ${env:BIGCOMMERCE_STORE_API_URL}
              - Name: BIGCOMMERCE_STORE_API_TOKEN
                Value: ${env:BIGCOMMERCE_STORE_API_TOKEN}
              - Name: BIGCOMMERCE_STORE_API_CLIENT_ID
                Value: ${env:BIGCOMMERCE_STORE_API_CLIENT_ID}
              - Name: BIGCOMMERCE_CHANNEL_ID
                Value: 611758
              - Name: BIGCOMMERCE_CHANNEL_CURRENCY
                Value: AUD
              - Name: NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID
                Value: ${env:NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID}
              - Name: NEXT_PUBLIC_BIGCOMMERCE_CHANNEL_CURRENCY
                Value: AUD
              - Name: NEXT_PUBLIC_CONTENTFUL_SPACE_ID
                Value: ${env:NEXT_PUBLIC_CONTENTFUL_SPACE_ID}
              - Name: NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN
                Value: ${env:NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN}
              - Name: NEXT_PUBLIC_CONTENTFUL_ENVIRONMENT
                Value: ${env:NEXT_PUBLIC_CONTENTFUL_ENVIRONMENT}
              - Name: CMS_BLOG_GHOST_API_URL
                Value: ${env:CMS_BLOG_GHOST_API_URL}
              - Name: CMS_BLOG_GHOST_CONTENT_API_KEY
                Value: ${env:CMS_BLOG_GHOST_CONTENT_API_KEY}
              - Name: RECAPTCHA_SECRET_KEY
                Value: ${env:RECAPTCHA_SECRET_KEY}
              - Name: BIGCOMMERCE_CHANNEL_COUNTRY
                Value: AU
              - Name: NEXT_PUBLIC_BIGCOMMERCE_CHANNEL_COUNTRY
                Value: AU
              - Name: S3_DESIGN_FILES_AWS_ACCESS_KEY_ID
                Value: ${env:S3_DESIGN_FILES_AWS_ACCESS_KEY_ID}
              - Name: S3_DESIGN_FILES_AWS_SECRET_ACCESS_KEY
                Value: ${env:S3_DESIGN_FILES_AWS_SECRET_ACCESS_KEY}
              - Name: NOISSUE_BASE_URL
                Value: ${env:NOISSUE_BASE_URL}
              - Name: HOSTED_CHECKOUT_BASE_URL
                Value: ${env:HOSTED_CHECKOUT_BASE_URL}
            PortMappings:
              - ContainerPort: !Ref ContainerPort
            LogConfiguration:
              LogDriver: awslogs
              Options:
                awslogs-group: !Ref FargateLogGroup
                awslogs-region: !Ref 'AWS::Region'
                awslogs-stream-prefix: ecs

    FargateTaskDefinitionNZ:
      Type: AWS::ECS::TaskDefinition
      Properties:
        Family: !Join ['', [!Ref 'ServiceName', '-NZ']]
        Cpu: 1024 # 1 vCPU
        Memory: 4096 # 4G
        NetworkMode: awsvpc # Required by Fargate
        RequiresCompatibilities:
          - FARGATE
        ExecutionRoleArn: !Ref ECSTaskExecutionRole
        TaskRoleArn: !Ref ECSTaskRole
        ContainerDefinitions:
          - Name: !Join ['', [!Ref 'ServiceName', '-NZ']]
            Cpu: 1024
            Memory: 4096
            Image: ${env:EVEREST_IMAGE_URL}:${env:TAG,'master'}_nz
            Environment:
              - Name: BIGCOMMERCE_STOREFRONT_API_URL
                Value: ${env:BIGCOMMERCE_STOREFRONT_API_URL}
              - Name: BIGCOMMERCE_STOREFRONT_API_TOKEN
                Value: ${env:BIGCOMMERCE_STOREFRONT_API_TOKEN}
              - Name: BIGCOMMERCE_STORE_API_URL
                Value: ${env:BIGCOMMERCE_STORE_API_URL}
              - Name: BIGCOMMERCE_STORE_API_TOKEN
                Value: ${env:BIGCOMMERCE_STORE_API_TOKEN}
              - Name: BIGCOMMERCE_STORE_API_CLIENT_ID
                Value: ${env:BIGCOMMERCE_STORE_API_CLIENT_ID}
              - Name: BIGCOMMERCE_CHANNEL_ID
                Value: 612611
              - Name: BIGCOMMERCE_CHANNEL_CURRENCY
                Value: NZD
              - Name: NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID
                Value: ${env:NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID}
              - Name: NEXT_PUBLIC_BIGCOMMERCE_CHANNEL_CURRENCY
                Value: NZD
              - Name: NEXT_PUBLIC_CONTENTFUL_SPACE_ID
                Value: ${env:NEXT_PUBLIC_CONTENTFUL_SPACE_ID}
              - Name: NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN
                Value: ${env:NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN}
              - Name: NEXT_PUBLIC_CONTENTFUL_ENVIRONMENT
                Value: ${env:NEXT_PUBLIC_CONTENTFUL_ENVIRONMENT}
              - Name: CMS_BLOG_GHOST_API_URL
                Value: ${env:CMS_BLOG_GHOST_API_URL}
              - Name: CMS_BLOG_GHOST_CONTENT_API_KEY
                Value: ${env:CMS_BLOG_GHOST_CONTENT_API_KEY}
              - Name: RECAPTCHA_SECRET_KEY
                Value: ${env:RECAPTCHA_SECRET_KEY}
              - Name: BIGCOMMERCE_CHANNEL_COUNTRY
                Value: NZ
              - Name: NEXT_PUBLIC_BIGCOMMERCE_CHANNEL_COUNTRY
                Value: NZ
              - Name: S3_DESIGN_FILES_AWS_ACCESS_KEY_ID
                Value: ${env:S3_DESIGN_FILES_AWS_ACCESS_KEY_ID}
              - Name: S3_DESIGN_FILES_AWS_SECRET_ACCESS_KEY
                Value: ${env:S3_DESIGN_FILES_AWS_SECRET_ACCESS_KEY}
              - Name: NOISSUE_BASE_URL
                Value: ${env:NOISSUE_BASE_URL}
              - Name: HOSTED_CHECKOUT_BASE_URL
                Value: ${env:HOSTED_CHECKOUT_BASE_URL}
            PortMappings:
              - ContainerPort: !Ref ContainerPort
            LogConfiguration:
              LogDriver: awslogs
              Options:
                awslogs-group: !Ref FargateLogGroup
                awslogs-region: !Ref 'AWS::Region'
                awslogs-stream-prefix: ecs

    # The service. The service is a resource which allows you to run multiple
    # copies of a type of task, and gather up their logs and metrics, as well
    # as monitor the number of running tasks and replace any that have crashed
    ServiceAU:
      Type: AWS::ECS::Service
      DependsOn: LoadBalancerRuleAU
      Properties:
        ServiceName: !Join ['', [!Ref 'ServiceName', '-AU']]
        Cluster: !Ref 'ECSCluster'
        # Uncomment this line if you want to use FARGATE instead of FARGATE spot
        # LaunchType: FARGATE
        # Comment next three lines if you want to use FARGATE instead of FARGATE spot
        CapacityProviderStrategy:
          - CapacityProvider: FARGATE_SPOT
            Weight: 1
        DeploymentConfiguration:
          MaximumPercent: 200
          MinimumHealthyPercent: 75
        DesiredCount: 1 # FIXME: Should be different for different countries?
        NetworkConfiguration:
          AwsvpcConfiguration:
            AssignPublicIp: ENABLED
            SecurityGroups:
              - !Ref SecurityGroup
            Subnets:
              - !Ref PublicSubnetBigCommerceOne
              - !Ref PublicSubnetBigCommerceTwo
        TaskDefinition: !Ref 'FargateTaskDefinitionAU'
        HealthCheckGracePeriodSeconds: 60
        LoadBalancers:
          - ContainerName: !Join ['', [!Ref 'ServiceName', '-AU']]
            ContainerPort: !Ref 'ContainerPort'
            TargetGroupArn: !Ref 'TargetGroupAU'

    ServiceNZ:
      Type: AWS::ECS::Service
      DependsOn: LoadBalancerRuleNZ
      Properties:
        ServiceName: !Join ['', [!Ref 'ServiceName', '-NZ']]
        Cluster: !Ref 'ECSCluster'
        # Uncomment this line if you want to use FARGATE instead of FARGATE spot
        # LaunchType: FARGATE
        # Comment next three lines if you want to use FARGATE instead of FARGATE spot
        CapacityProviderStrategy:
          - CapacityProvider: FARGATE_SPOT
            Weight: 1
        DeploymentConfiguration:
          MaximumPercent: 200
          MinimumHealthyPercent: 75
        DesiredCount: 1 # FIXME: Should be different for different countries?
        NetworkConfiguration:
          AwsvpcConfiguration:
            AssignPublicIp: ENABLED
            SecurityGroups:
              - !Ref SecurityGroup
            Subnets:
              - !Ref PublicSubnetBigCommerceOne
              - !Ref PublicSubnetBigCommerceTwo
        TaskDefinition: !Ref 'FargateTaskDefinitionNZ'
        HealthCheckGracePeriodSeconds: 60
        LoadBalancers:
          - ContainerName: !Join ['', [!Ref 'ServiceName', '-NZ']]
            ContainerPort: !Ref 'ContainerPort'
            TargetGroupArn: !Ref 'TargetGroupNZ'

    # A target group. This is used for keeping track of all the tasks, and
    # what IP addresses / port numbers they have. You can query it yourself,
    # to use the addresses yourself, but most often this target group is just
    # connected to an application load balancer, or network load balancer, so
    # it can automatically distribute traffic across all the targets.
    TargetGroupAU:
      Type: AWS::ElasticLoadBalancingV2::TargetGroup
      Properties:
        HealthCheckIntervalSeconds: 5
        HealthCheckPath: /
        HealthCheckProtocol: HTTP
        HealthCheckTimeoutSeconds: 4
        HealthyThresholdCount: 2
        TargetType: ip
        Name: !Join ['', [!Ref 'ServiceName', '-AU']]
        Port: !Ref 'ContainerPort'
        Protocol: HTTP
        UnhealthyThresholdCount: 2
        VpcId: !Ref VPC
        TargetGroupAttributes:
          - Key: deregistration_delay.timeout_seconds
            Value: '10'

    TargetGroupNZ:
      Type: AWS::ElasticLoadBalancingV2::TargetGroup
      Properties:
        HealthCheckIntervalSeconds: 5
        HealthCheckPath: /
        HealthCheckProtocol: HTTP
        HealthCheckTimeoutSeconds: 4
        HealthyThresholdCount: 2
        TargetType: ip
        Name: !Join ['', [!Ref 'ServiceName', '-NZ']]
        Port: !Ref 'ContainerPort'
        Protocol: HTTP
        UnhealthyThresholdCount: 2
        VpcId: !Ref VPC
        TargetGroupAttributes:
          - Key: deregistration_delay.timeout_seconds
            Value: '10'

    # ALB rules to route traffic to correct country container
    LoadBalancerRuleNZ:
      Type: AWS::ElasticLoadBalancingV2::ListenerRule
      Properties:
        Actions:
          - TargetGroupArn: !Ref 'TargetGroupNZ'
            Type: 'forward'
        Conditions:
          - Field: host-header
            Values:
              - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.nzDomain}
        ListenerArn: !Ref PublicLoadBalancerListener
        Priority: 1
    LoadBalancerRuleAU:
      Type: AWS::ElasticLoadBalancingV2::ListenerRule
      Properties:
        Actions:
          - TargetGroupArn: !Ref 'TargetGroupAU'
            Type: 'forward'
        Conditions:
          - Field: host-header
            Values:
              - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.auDomain}
        ListenerArn: !Ref PublicLoadBalancerListener
        Priority: 2
    LoadBalancerRuleUS:
      Type: AWS::ElasticLoadBalancingV2::ListenerRule
      Properties:
        Actions:
          - TargetGroupArn: !Ref 'TargetGroupAU'
            Type: 'forward'
        Conditions:
          - Field: host-header
            Values:
              - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.usDomain}
        ListenerArn: !Ref PublicLoadBalancerListener
        Priority: 3
    LoadBalancerRuleUK:
      Type: AWS::ElasticLoadBalancingV2::ListenerRule
      Properties:
        Actions:
          - TargetGroupArn: !Ref 'TargetGroupNZ'
            Type: 'forward'
        Conditions:
          - Field: host-header
            Values:
              - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.ukDomain}
        ListenerArn: !Ref PublicLoadBalancerListener
        Priority: 4
    LoadBalancerRuleCA:
      Type: AWS::ElasticLoadBalancingV2::ListenerRule
      Properties:
        Actions:
          - TargetGroupArn: !Ref 'TargetGroupAU'
            Type: 'forward'
        Conditions:
          - Field: host-header
            Values:
              - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.caDomain}
        ListenerArn: !Ref PublicLoadBalancerListener
        Priority: 5

    EcsSecurityGroupIngressFromPublicALB:
      Type: AWS::EC2::SecurityGroupIngress
      Properties:
        Description: Ingress from the public ALB
        GroupId: !Ref SecurityGroup
        IpProtocol: -1
        SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG'

    # Public load balancer, hosted in public subnets that is accessible
    # to the public, and is intended to route traffic to one or more public
    # facing services. This is used for accepting traffic from the public
    # internet and directing it to public facing microservices
    PublicLoadBalancerSG:
      Type: AWS::EC2::SecurityGroup
      Properties:
        GroupDescription: Access to the public facing load balancer
        VpcId: !Ref VPC
        SecurityGroupIngress:
          # Allow access to ALB from anywhere on the internet
          - CidrIp: 0.0.0.0/0
            IpProtocol: -1
    PublicLoadBalancer:
      Type: AWS::ElasticLoadBalancingV2::LoadBalancer
      Properties:
        Scheme: internet-facing
        LoadBalancerAttributes:
          - Key: idle_timeout.timeout_seconds
            Value: '30'
        Subnets:
          # The load balancer is placed into the public subnets, so that traffic
          # from the internet can reach the load balancer directly via the internet gateway
          - !Ref PublicSubnetBigCommerceOne
          - !Ref PublicSubnetBigCommerceTwo
        SecurityGroups: [!Ref 'PublicLoadBalancerSG']
    # A dummy target group is used to setup the ALB to just drop traffic
    # initially, before any real service target groups have been added.
    DummyTargetGroupPublic:
      Type: AWS::ElasticLoadBalancingV2::TargetGroup
      Properties:
        HealthCheckIntervalSeconds: 5
        HealthCheckPath: /
        HealthCheckProtocol: HTTP
        HealthCheckTimeoutSeconds: 4
        HealthyThresholdCount: 2
        Port: 80
        Protocol: HTTP
        UnhealthyThresholdCount: 2
        VpcId: !Ref VPC

    PublicLoadBalancerListener:
      Type: AWS::ElasticLoadBalancingV2::Listener
      DependsOn:
        - PublicLoadBalancer
      Properties:
        DefaultActions:
          - TargetGroupArn: !Ref 'TargetGroupAU'
            Type: 'forward'
        LoadBalancerArn: !Ref 'PublicLoadBalancer'
        Port: 80
        Protocol: HTTP

    StorybookBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:custom.profiles.${opt:stage, self:provider.stage, 'sandbox'}.deploymentBucketName}
        AccessControl: PublicRead
        WebsiteConfiguration:
          IndexDocument: index.html
          ErrorDocument: 404.html

    StorybookBucketPolicy:
      Type: "AWS::S3::BucketPolicy"
      Properties:
        Bucket: !Ref StorybookBucket
        PolicyDocument:
          Statement:
            - Action: "s3:GetObject"
              Effect: "Allow"
              Resource: !Join [ "",
                  [
                      "arn:aws:s3:::",
                      !Ref StorybookBucket,
                      "/*"
                  ],
                ]
              Principal: "*"

#    StoryBookDNSAlias:
#      Type: AWS::Route53::RecordSet
#      Condition: CreateStoryBookSiteDomain
#      Properties:
#        ResourceRecords:
#          - !GetAtt StorybookBucket.DomainName
#        Name: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.storyBookHostedZone}
#        HostedZoneId: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.hostedZoneId}
#        Type: A

    # CloudFront behaviour policies
    VHostCachePolicy:
      Type: AWS::CloudFront::CachePolicy
      Properties:
        CachePolicyConfig:
          Name: VHostCachePolicy
          Comment: Include Host header in cache key to correctly cache per-country content
          DefaultTTL: 86400
          MaxTTL: 31536000
          MinTTL: 1
          ParametersInCacheKeyAndForwardedToOrigin:
            EnableAcceptEncodingBrotli: true
            EnableAcceptEncodingGzip: true
            CookiesConfig:
              CookieBehavior: none
            QueryStringsConfig:
              QueryStringBehavior: none
            HeadersConfig:
              HeaderBehavior: whitelist
              Headers:
                - Host

    CloudFrontDistribution:
      Type: AWS::CloudFront::Distribution
      Condition: CreateEcommerceSiteDomain
      Properties:
        DistributionConfig:
          Aliases:
            - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.hostedZone}
            - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.nzDomain}
            - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.auDomain}
            - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.ukDomain}
            - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.usDomain}
            - ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.caDomain}
          Origins:
            - DomainName: !GetAtt PublicLoadBalancer.DNSName
              Id: alb-everest-${opt:stage, self:provider.stage}
              CustomOriginConfig:
                OriginProtocolPolicy: http-only
          CacheBehaviors:
            - PathPattern: /checkout*
              CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad
              OriginRequestPolicyId: 216adef6-5c7f-47e4-b989-5492eafa07d3
              TargetOriginId: alb-everest-${opt:stage, self:provider.stage}
              ViewerProtocolPolicy: redirect-to-https
              AllowedMethods:
                - GET
                - HEAD
            - PathPattern: /api/*
              CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad
              OriginRequestPolicyId: 216adef6-5c7f-47e4-b989-5492eafa07d3
              TargetOriginId: alb-everest-${opt:stage, self:provider.stage}
              ViewerProtocolPolicy: redirect-to-https
              AllowedMethods:
                - DELETE
                - GET
                - HEAD
                - OPTIONS
                - PATCH
                - POST
                - PUT
          DefaultCacheBehavior:
            CachePolicyId: !GetAtt VHostCachePolicy.Id
            OriginRequestPolicyId: 216adef6-5c7f-47e4-b989-5492eafa07d3
            TargetOriginId: alb-everest-${opt:stage, self:provider.stage}
            ViewerProtocolPolicy: redirect-to-https
            AllowedMethods:
              - DELETE
              - GET
              - HEAD
              - OPTIONS
              - PATCH
              - POST
              - PUT
          Enabled: true
          HttpVersion: http2
          IPV6Enabled: true
          PriceClass: PriceClass_100
          ViewerCertificate:
            AcmCertificateArn: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.cloudfrontCertificateArn}
            MinimumProtocolVersion: TLSv1.1_2016
            SslSupportMethod: sni-only

    # DNS alias records for CloudFront distribution
    CloudFrontAliasDefault:
      Type: AWS::Route53::RecordSet
      Condition: CreateEcommerceSiteDomain
      Properties:
        AliasTarget:
          DNSName: !GetAtt CloudFrontDistribution.DomainName
          HostedZoneId: Z2FDTNDATAQYW2
        HostedZoneId: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.hostedZoneId}
        Name: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.hostedZone}
        Type: A
    CloudFrontAliasUS:
      Type: AWS::Route53::RecordSet
      Condition: CreateEcommerceSiteDomain
      Properties:
        AliasTarget:
          DNSName: !GetAtt CloudFrontDistribution.DomainName
          HostedZoneId: Z2FDTNDATAQYW2
        HostedZoneId: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.hostedZoneId}
        Name: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.usDomain}
        Type: A
    CloudFrontAliasUK:
      Type: AWS::Route53::RecordSet
      Condition: CreateEcommerceSiteDomain
      Properties:
        AliasTarget:
          DNSName: !GetAtt CloudFrontDistribution.DomainName
          HostedZoneId: Z2FDTNDATAQYW2
        HostedZoneId: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.hostedZoneId}
        Name: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.ukDomain}
        Type: A
    CloudFrontAliasCA:
      Type: AWS::Route53::RecordSet
      Condition: CreateEcommerceSiteDomain
      Properties:
        AliasTarget:
          DNSName: !GetAtt CloudFrontDistribution.DomainName
          HostedZoneId: Z2FDTNDATAQYW2
        HostedZoneId: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.hostedZoneId}
        Name: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.caDomain}
        Type: A
    CloudFrontAliasNZ:
      Type: AWS::Route53::RecordSet
      Condition: CreateEcommerceSiteDomain
      Properties:
        AliasTarget:
          DNSName: !GetAtt CloudFrontDistribution.DomainName
          HostedZoneId: Z2FDTNDATAQYW2
        HostedZoneId: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.hostedZoneId}
        Name: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.nzDomain}
        Type: A
    CloudFrontAliasAU:
      Type: AWS::Route53::RecordSet
      Condition: CreateEcommerceSiteDomain
      Properties:
        AliasTarget:
          DNSName: !GetAtt CloudFrontDistribution.DomainName
          HostedZoneId: Z2FDTNDATAQYW2
        HostedZoneId: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.hostedZoneId}
        Name: ${self:custom.profiles.${opt:stage, self:provider.stage}.domain.auDomain}
        Type: A
