AWSTemplateFormatVersion: "2010-09-09"
Description: CRUD API for Holiday Stop Requests (stored in SalesForce)

Parameters:
    Stage:
        Description: Stage name
        Type: String
        AllowedValues:
            - PROD
            - CODE
        Default: CODE

Conditions:
  CreateProdMonitoring: !Equals [ !Ref Stage, PROD ]

Mappings:
    StageMap:
        CODE:
            ApiName: holiday-stop-api-CODE
            FulfilmentDatesBucketUrn: "arn:aws:s3:::fulfilment-date-calculator-code/*"
            DomainName: holiday-stop-api-code.support.guardianapis.com
        PROD:
            ApiName: holiday-stop-api-PROD
            FulfilmentDatesBucketUrn: "arn:aws:s3:::fulfilment-date-calculator-prod/*"
            DomainName: holiday-stop-api.support.guardianapis.com

Resources:
    HolidayStopApiRole:
        Type: AWS::IAM::Role
        Properties:
            AssumeRolePolicyDocument:
                Statement:
                    - Effect: Allow
                      Principal:
                          Service:
                             - lambda.amazonaws.com
                      Action:
                          - sts:AssumeRole
            Path: /
            Policies:
                - PolicyName: LambdaPolicy
                  PolicyDocument:
                      Statement:
                          - Effect: Allow
                            Action:
                            - logs:CreateLogGroup
                            - logs:CreateLogStream
                            - logs:PutLogEvents
                            - lambda:InvokeFunction
                            Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/holiday-stop-api-${Stage}:log-stream:*"
                - PolicyName: ReadPrivateCredentials
                  PolicyDocument:
                      Statement:
                          - Effect: Allow
                            Action: s3:GetObject
                            Resource: !Sub arn:aws:s3:::gu-reader-revenue-private/membership/support-service-lambdas/${Stage}/*
                - PolicyName: FulfilmentDatesCalculatorBucket
                  PolicyDocument:
                    Statement:
                      - Effect: Allow
                        Action: s3:GetObject
                        Resource:
                          - !FindInMap [StageMap, !Ref Stage, FulfilmentDatesBucketUrn]

    HolidayStopApi:
        Type: "AWS::ApiGateway::RestApi"
        Properties:
            Description: manage-frontend (self-service MMA) uses to create/update/delete Holiday Stop Requests (stored in SalesForce)
            Name: !FindInMap [StageMap, !Ref Stage, ApiName]

    HolidayStopApiPermission:
        Type: AWS::Lambda::Permission
        Properties:
            Action: lambda:invokeFunction
            FunctionName: !Sub holiday-stop-api-${Stage}
            Principal: apigateway.amazonaws.com
        DependsOn: HolidayStopApiLambda

    HolidayStopApiLambda:
        Type: AWS::Lambda::Function
        Properties:
            Description: manage-frontend (self-service MMA) uses to create/update/delete Holiday Stop Requests (stored in SalesForce)
            FunctionName:
                !Sub holiday-stop-api-${Stage}
            Code:
                S3Bucket: support-service-lambdas-dist
                S3Key: !Sub membership/${Stage}/holiday-stop-api/holiday-stop-api.jar
            Handler: com.gu.holiday_stops.Handler::apply
            Environment:
              Variables:
                Stage: !Ref Stage
            Role:
                Fn::GetAtt:
                - HolidayStopApiRole
                - Arn
            MemorySize: 1536
            Runtime: java21
            Timeout: 300
            Architectures:
              - arm64
        DependsOn:
        - HolidayStopApiRole

    HolidayStopApiUsagePlan:
      Type: AWS::ApiGateway::UsagePlan
      Properties:
        UsagePlanName: holiday-stop-api
        ApiStages:
          - ApiId: !Ref HolidayStopApi
            Stage: !Ref Stage
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiStage

    HolidayStopApiKey:
      Type: AWS::ApiGateway::ApiKey
      Properties:
        Description: Used by manage-frontend
        Enabled: true
        Name: !Sub holiday-stop-api-key-${Stage}
        StageKeys:
          - RestApiId: !Ref HolidayStopApi
            StageName: !Ref Stage
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiStage

    HolidayStopApiUsagePlanKey:
      Type: AWS::ApiGateway::UsagePlanKey
      Properties:
        KeyId: !Ref HolidayStopApiKey
        KeyType: API_KEY
        UsagePlanId: !Ref HolidayStopApiUsagePlan
      DependsOn:
        - HolidayStopApiKey
        - HolidayStopApiUsagePlan

    HolidayStopApiPotentialProxyResource:
        Type: AWS::ApiGateway::Resource
        Properties:
            RestApiId: !Ref HolidayStopApi
            ParentId: !GetAtt [HolidayStopApi, RootResourceId]
            PathPart: "potential"
        DependsOn: HolidayStopApi

    HolidayStopApiPotentialBySubscriptionNameProxyResource:
      Type: AWS::ApiGateway::Resource
      Properties:
        RestApiId: !Ref HolidayStopApi
        ParentId: !Ref HolidayStopApiPotentialProxyResource
        PathPart: "{subscriptionName}"
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiPotentialProxyResource

    HolidayStopApiPotentialBySubscriptionNameGetMethod:
      Type: AWS::ApiGateway::Method
      Properties:
        AuthorizationType: NONE
        ApiKeyRequired: true
        RestApiId: !Ref HolidayStopApi
        ResourceId: !Ref HolidayStopApiPotentialBySubscriptionNameProxyResource
        HttpMethod: GET
        RequestParameters:
          method.request.path.subscriptionName: true
        Integration:
          Type: AWS_PROXY
          IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST
          Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HolidayStopApiLambda.Arn}/invocations
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiLambda
        - HolidayStopApiPotentialBySubscriptionNameProxyResource

    HolidayStopApiGetAllAndCreateProxyResource:
        Type: AWS::ApiGateway::Resource
        Properties:
            RestApiId: !Ref HolidayStopApi
            ParentId: !GetAtt [HolidayStopApi, RootResourceId]
            PathPart: "hsr"
        DependsOn: HolidayStopApi

    BulkHolidayStopApiCreateProxyResource:
      Type: AWS::ApiGateway::Resource
      Properties:
        RestApiId: !Ref HolidayStopApi
        ParentId: !GetAtt [HolidayStopApi, RootResourceId]
        PathPart: "bulk-hsr"
      DependsOn: HolidayStopApi

    HolidayStopApiCreateMethod:
      Type: AWS::ApiGateway::Method
      Properties:
        AuthorizationType: NONE
        ApiKeyRequired: true
        RestApiId: !Ref HolidayStopApi
        ResourceId: !Ref HolidayStopApiGetAllAndCreateProxyResource
        HttpMethod: POST
        Integration:
          Type: AWS_PROXY
          IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST
          Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HolidayStopApiLambda.Arn}/invocations
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiLambda
        - HolidayStopApiGetAllAndCreateProxyResource
          
    BulkHolidayStopApiCreateMethod:
      Type: AWS::ApiGateway::Method
      Properties:
        AuthorizationType: NONE
        ApiKeyRequired: true
        RestApiId: !Ref HolidayStopApi
        ResourceId: !Ref BulkHolidayStopApiCreateProxyResource
        HttpMethod: POST
        Integration:
          Type: AWS_PROXY
          IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST
          Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HolidayStopApiLambda.Arn}/invocations
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiLambda
        - BulkHolidayStopApiCreateProxyResource

    HolidayStopApiBySubscriptionNameProxyResource:
      Type: AWS::ApiGateway::Resource
      Properties:
        RestApiId: !Ref HolidayStopApi
        ParentId: !Ref HolidayStopApiGetAllAndCreateProxyResource
        PathPart: "{subscriptionName}"
      DependsOn:
      - HolidayStopApi
      - HolidayStopApiGetAllAndCreateProxyResource

    HolidayStopApiGetBySubscriptionNameMethod:
      Type: AWS::ApiGateway::Method
      Properties:
        AuthorizationType: NONE
        ApiKeyRequired: true
        RestApiId: !Ref HolidayStopApi
        ResourceId: !Ref HolidayStopApiBySubscriptionNameProxyResource
        HttpMethod: GET
        RequestParameters:
          method.request.path.subscriptionName: true
        Integration:
          Type: AWS_PROXY
          IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST
          Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HolidayStopApiLambda.Arn}/invocations
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiLambda
        - HolidayStopApiBySubscriptionNameProxyResource
    
    HolidayStopApiDeleteAndEditResource:
      Type: AWS::ApiGateway::Resource
      Properties:
        RestApiId: !Ref HolidayStopApi
        ParentId: !Ref HolidayStopApiBySubscriptionNameProxyResource
        PathPart: "{holidayStopRequestId}"
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiBySubscriptionNameProxyResource

    HolidayStopApiDeleteMethod:
      Type: AWS::ApiGateway::Method
      Properties:
        AuthorizationType: NONE
        ApiKeyRequired: true
        RestApiId: !Ref HolidayStopApi
        ResourceId: !Ref HolidayStopApiDeleteAndEditResource
        HttpMethod: DELETE
        RequestParameters:
          method.request.path.subscriptionName: true
          method.request.path.holidayStopRequestId: true
        Integration:
          Type: AWS_PROXY
          IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST
          Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HolidayStopApiLambda.Arn}/invocations
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiLambda
        - HolidayStopApiDeleteAndEditResource

    HolidayStopApiCancelResource:
      Type: AWS::ApiGateway::Resource
      Properties:
        RestApiId: !Ref HolidayStopApi
        ParentId: !Ref HolidayStopApiBySubscriptionNameProxyResource
        PathPart: "cancel"
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiBySubscriptionNameProxyResource

    HolidayStopApiCancelPostMethod:
      Type: AWS::ApiGateway::Method
      Properties:
        AuthorizationType: NONE
        ApiKeyRequired: true
        RestApiId: !Ref HolidayStopApi
        ResourceId: !Ref HolidayStopApiCancelResource
        HttpMethod: POST
        RequestParameters:
          method.request.path.subscriptionName: true
        Integration:
          Type: AWS_PROXY
          IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST
          Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HolidayStopApiLambda.Arn}/invocations
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiLambda
        - HolidayStopApiCancelResource

    HolidayStopApiCancelGetMethod:
      Type: AWS::ApiGateway::Method
      Properties:
        AuthorizationType: NONE
        ApiKeyRequired: true
        RestApiId: !Ref HolidayStopApi
        ResourceId: !Ref HolidayStopApiCancelResource
        HttpMethod: GET
        RequestParameters:
          method.request.path.subscriptionName: true
        Integration:
          Type: AWS_PROXY
          IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST
          Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HolidayStopApiLambda.Arn}/invocations
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiLambda
        - HolidayStopApiCancelResource

    HolidayStopApiEditMethod:
      Type: AWS::ApiGateway::Method
      Properties:
        AuthorizationType: NONE
        ApiKeyRequired: true
        RestApiId: !Ref HolidayStopApi
        ResourceId: !Ref HolidayStopApiDeleteAndEditResource
        HttpMethod: PATCH
        RequestParameters:
          method.request.path.subscriptionName: true
          method.request.path.holidayStopRequestId: true
        Integration:
          Type: AWS_PROXY
          IntegrationHttpMethod: POST # this for the interaction between API Gateway and Lambda and MUST be POST
          Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HolidayStopApiLambda.Arn}/invocations
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiLambda
        - HolidayStopApiDeleteAndEditResource

    HolidayStopApiStage:
        Type: AWS::ApiGateway::Stage
        Properties:
            Description: Stage for holiday-stop-api
            RestApiId: !Ref HolidayStopApi
            DeploymentId: !Ref HolidayStopApiDeployment2
            StageName: !Sub ${Stage}
        DependsOn:
        - HolidayStopApiPotentialBySubscriptionNameGetMethod
        - HolidayStopApiGetBySubscriptionNameMethod
        - HolidayStopApiCreateMethod
        - BulkHolidayStopApiCreateMethod
        - HolidayStopApiDeleteMethod
        - HolidayStopApiEditMethod
        - HolidayStopApiCancelPostMethod
        - HolidayStopApiCancelGetMethod

    # Bizarrely you have to update the deployment to include new endpoints in each stage
    HolidayStopApiDeployment2:
        Type: AWS::ApiGateway::Deployment
        Properties:
            Description: Deploys holiday-stop-api into an environment/stage
            RestApiId: !Ref HolidayStopApi
        DependsOn:
        - HolidayStopApiPotentialBySubscriptionNameGetMethod
        - HolidayStopApiGetBySubscriptionNameMethod
        - HolidayStopApiCreateMethod
        - BulkHolidayStopApiCreateMethod
        - HolidayStopApiDeleteMethod
        - HolidayStopApiEditMethod
        - HolidayStopApiCancelPostMethod

    5xxApiAlarm:
      Type: AWS::CloudWatch::Alarm
      Condition: CreateProdMonitoring
      Properties:
        AlarmActions:
        - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-PROD
        AlarmName:
          !Sub
            - 5XX rate from ${ApiName}
            - { ApiName: !FindInMap [StageMap, !Ref Stage, ApiName] }
        AlarmDescription: Holiday stop API exceeded the allowed 5XX error rate
        ComparisonOperator: GreaterThanThreshold
        Dimensions:
          - Name: ApiName
            Value: !FindInMap [StageMap, !Ref Stage, ApiName]
          - Name: Stage
            Value: !Sub ${Stage}
        EvaluationPeriods: 1
        MetricName: 5XXError
        Namespace: AWS/ApiGateway
        Period: 3600
        Statistic: Sum
        Threshold: 5
        TreatMissingData: notBreaching

    HolidayStopApiDomainName:
      Type: "AWS::ApiGateway::DomainName"
      Properties:
        RegionalCertificateArn: # only for *.support.guardianapis.com
          !Sub arn:aws:acm:${AWS::Region}:${AWS::AccountId}:certificate/b384a6a0-2f54-4874-b99b-96eeff96c009
        DomainName: !FindInMap [ StageMap, !Ref Stage, DomainName ]
        EndpointConfiguration:
          Types:
            - REGIONAL

    HolidayStopApiBasePathMapping:
      Type: "AWS::ApiGateway::BasePathMapping"
      Properties:
        RestApiId: !Ref HolidayStopApi
        DomainName: !Ref HolidayStopApiDomainName
        Stage: !Sub ${Stage}
      DependsOn:
        - HolidayStopApi
        - HolidayStopApiDomainName
        - HolidayStopApiStage

    HolidayStopApiDNSRecord:
      Type: AWS::Route53::RecordSet
      Properties:
        HostedZoneName: support.guardianapis.com.
        Name: !FindInMap [ StageMap, !Ref Stage, DomainName ]
        Type: CNAME
        TTL: '120'
        ResourceRecords:
          - !GetAtt HolidayStopApiDomainName.RegionalDomainName