AWSTemplateFormatVersion: "2010-09-09"
Description: Finds and marks zuora accounts that are out of the retention period

Parameters:
    Stage:
        Description: Stage name
        Type: String
        AllowedValues:
            - CODE
            - PROD
        Default: CODE
Mappings:
  StageVariables:
    CODE:
      retentionBucketName : "zuora-retention-code"
    PROD:
      retentionBucketName : "zuora-retention-prod"
Resources:
    RetentionBucket:
        Type: "AWS::S3::Bucket"
        Properties:
          BucketName:
            Fn::FindInMap:
              - StageVariables
              - Ref: Stage
              - "retentionBucketName"
          AccessControl: Private
          BucketEncryption:
            ServerSideEncryptionConfiguration:
              - ServerSideEncryptionByDefault:
                  SSEAlgorithm: AES256
          LifecycleConfiguration:
            Rules:
              - Id: DeleteOldFiles
                Prefix: ""
                Status: Enabled
                ExpirationInDays: 1
    ZuoraQuerierRole:
        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/zuora-retention-querier-${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}/zuoraRest-${Stage}*.json"
    ZuoraResultsRole:
        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/zuora-retention-jobResult-${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}/zuoraRest-${Stage}*.json"
    ZuoraFileFetcherRole:
        Type: AWS::IAM::Role
        DependsOn: RetentionBucket
        Properties:
            AssumeRolePolicyDocument:
                Statement:
                    - Effect: Allow
                      Principal:
                          Service:
                             - lambda.amazonaws.com
                      Action:
                          - sts:AssumeRole
            Path: /
            Policies:
                - PolicyName: writeToRetentionBucket
                  PolicyDocument:
                      Statement:
                        - Effect: Allow
                          Action:
                          - s3:PutObject
                          Resource: !Sub arn:aws:s3:::${RetentionBucket}/*
                - 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/zuora-retention-fileFetcher-${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}/zuoraRest-${Stage}*.json"
    FilterRole:
        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/zuora-retention-filter-${Stage}:log-stream:*"

                - PolicyName: RetentionBucket
                  PolicyDocument:
                      Statement:
                        - Effect: Allow
                          Action:
                          - s3:PutObject
                          - s3:GetObject
                          Resource: !Sub arn:aws:s3:::${RetentionBucket}/*
    UpdaterRole:
          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/zuora-retention-account-updater-${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}/zuoraRest-${Stage}*.json"

                  - PolicyName: ReadRetentionBucket
                    PolicyDocument:
                        Statement:
                          - Effect: Allow
                            Action:
                            - s3:GetObject
                            Resource: !Sub arn:aws:s3:::${RetentionBucket}/*
    StateMachineTriggerRole:
      Type: AWS::IAM::Role
      Properties:
          AssumeRolePolicyDocument:
              Statement:
                  - Effect: Allow
                    Principal:
                        Service:
                           - events.amazonaws.com
                    Action:
                        - sts:AssumeRole
          Policies:
              - PolicyName: TriggerStateMchine
                PolicyDocument:
                    Version : "2012-10-17"
                    Statement:
                       - Effect: Allow
                         Action:
                         - states:StartExecution
                         Resource: !Ref stateMachine
    ZuoraRetentionQuerier:
        Type: AWS::Lambda::Function
        Properties:
            Description: submit query jobs to Zuora AQuA API
            FunctionName:
                !Sub zuora-retention-querier-${Stage}
            Code:
                S3Bucket: support-service-lambdas-dist
                S3Key: !Sub membership/${Stage}/zuora-retention/zuora-retention.jar
            Handler: com.gu.zuora.retention.ZuoraRetentionQueryHandler::apply
            Environment:
                Variables:
                  Stage: !Ref Stage
            Role:
                !GetAtt ZuoraQuerierRole.Arn
            MemorySize: 1536
            Runtime: java21
            Timeout: 300
            Architectures:
              - arm64
        DependsOn:
        - ZuoraQuerierRole
    ZuoraRetentionJobResult:
        Type: AWS::Lambda::Function
        Properties:
            Description: fetch job results from zuora
            FunctionName:
                !Sub zuora-retention-jobResult-${Stage}
            Code:
                S3Bucket: support-service-lambdas-dist
                S3Key: !Sub membership/${Stage}/zuora-retention/zuora-retention.jar
            Handler: com.gu.zuora.reports.handlers.FetchResultsHandler::apply
            Environment:
                Variables:
                  Stage: !Ref Stage
            Role:
                !GetAtt ZuoraResultsRole.Arn
            MemorySize: 1536
            Runtime: java21
            Timeout: 300
            Architectures:
              - arm64
        DependsOn:
        - ZuoraResultsRole
    ZuoraRetentionFileFetcher:
        Type: AWS::Lambda::Function
        Properties:
            Description: fetches report files and saves them to s3
            FunctionName:
                !Sub zuora-retention-fileFetcher-${Stage}
            Code:
                S3Bucket: support-service-lambdas-dist
                S3Key: !Sub membership/${Stage}/zuora-retention/zuora-retention.jar
            Handler: com.gu.zuora.retention.ZuoraRetentionFetchFileHandler::apply
            Environment:
                Variables:
                  Stage: !Ref Stage
            Role:
                !GetAtt ZuoraFileFetcherRole.Arn
            MemorySize: 1536
            Runtime: java21
            Timeout: 300
            Architectures:
              - arm64
        DependsOn:
        - ZuoraFileFetcherRole
    ZuoraRetentionFilter:
            Type: AWS::Lambda::Function
            Properties:
                Description: filters candidates using the exclusion list to get the final list of accounts to process
                FunctionName:
                    !Sub zuora-retention-filter-${Stage}
                Code:
                    S3Bucket: support-service-lambdas-dist
                    S3Key: !Sub membership/${Stage}/zuora-retention/zuora-retention.jar
                Handler: com.gu.zuora.retention.filterCandidates.FilterCandidates::apply
                Environment:
                    Variables:
                      Stage: !Ref Stage
                Role:
                    !GetAtt FilterRole.Arn
                MemorySize: 1536
                Runtime: java21
                Timeout: 300
                Architectures:
                  - arm64
            DependsOn:
            - FilterRole
    ZuoraRetentionAccountUpdater:
            Type: AWS::Lambda::Function
            Properties:
                Description: sets the field 'ProcessingAdvice__c' to 'DoNotProcess' for a list of accounts coming from a csv file
                FunctionName:
                    !Sub zuora-retention-account-updater-${Stage}
                Code:
                    S3Bucket: support-service-lambdas-dist
                    S3Key: !Sub membership/${Stage}/zuora-retention/zuora-retention.jar
                Handler: com.gu.zuora.retention.updateAccounts.Handler::apply
                Environment:
                    Variables:
                      Stage: !Ref Stage
                Role:
                    !GetAtt UpdaterRole.Arn
                MemorySize: 1536
                Runtime: java21
                Timeout: 300
                Architectures:
                  - arm64
            DependsOn:
            - UpdaterRole
    StatesExecutionRole:
      Type: 'AWS::IAM::Role'
      Properties:
        AssumeRolePolicyDocument:
          Version: 2012-10-17
          Statement:
            Effect: Allow
            Principal:
              Service: !Sub 'states.${AWS::Region}.amazonaws.com'
            Action: 'sts:AssumeRole'
        Path: /
        Policies:
          - PolicyName: StatesExecutionPolicy
            PolicyDocument:
              Version: 2012-10-17
              Statement:
                - Effect: Allow
                  Action:
                    - 'lambda:InvokeFunction'
                  Resource: '*'
    stateMachine:
      Type: 'AWS::StepFunctions::StateMachine'
      Properties:
        StateMachineName: !Sub 'zuoraRetention-${Stage}'
        RoleArn: !GetAtt
          - StatesExecutionRole
          - Arn
        DefinitionString: !Sub
          - |-
            {
               "StartAt":"QueryZuora",
               "States":{
                  "QueryZuora":{
                     "Type":"Task",
                     "Resource":"${querierArn}",
                     "Next":"WaitSomeTime",
                     "Retry":[
                        {
                           "ErrorEquals":["States.ALL"],
                           "IntervalSeconds":30,
                           "MaxAttempts":3
                        }
                     ]
                  },
                  "WaitSomeTime":{
                     "Type":"Wait",
                     "Seconds":60,
                     "Next":"FetchResults"
                  },
                  "FetchResults":{
                     "Type":"Task",
                     "Resource":"${fetcherArn}",
                     "Next":"checkResultsAvailable",
                     "Retry":[
                        {
                           "ErrorEquals":["States.ALL"],
                            "IntervalSeconds":30,
                            "MaxAttempts":3
                        }
                     ]
                  },
                  "checkResultsAvailable":{
                     "Type":"Choice",
                     "Choices":[
                        {
                           "Variable":"$.status",
                           "StringEquals":"pending",
                           "Next":"WaitSomeTime"
                        }
                     ],
                     "Default":"FetchFiles"
                  },
                  "FetchFiles":{
                     "Type":"Task",
                     "Resource":"${fetchFilesArn}",
                     "Next":"CheckRemainingFiles",

                     "Retry":[
                        {
                           "ErrorEquals":["States.ALL"],
                            "IntervalSeconds":30,
                            "MaxAttempts":3
                        }
                     ]
                  },
                  "CheckRemainingFiles":{
                     "Type":"Choice",
                     "Choices":[
                        {
                           "Variable":"$.done",
                           "BooleanEquals":false,
                           "Next":"FetchFiles"
                        }
                     ],
                     "Default":"Filter"
                  },
               "Filter":{
                          "Type":"Task",
                          "Resource":"${filterArn}",
                          "Next":"isDryRun",
                          "Retry":[
                             {
                              "ErrorEquals":["States.ALL"],
                              "IntervalSeconds":30,
                              "MaxAttempts":3
                             }
                          ]
                       }
               ,
               "isDryRun":{
                  "Type":"Choice",
                  "Choices":[
                     {
                        "Variable":"$.dryRun",
                        "BooleanEquals":false,
                        "Next":"UpdateAccounts"
                     }
                  ],
                  "Default":"done"
               },
               "UpdateAccounts":{
                           "Type":"Task",
                           "Resource":"${accountUpdaterArn}",
                           "Next":"checkRemainingAccounts",
                           "Retry":[
                              {
                               "ErrorEquals":["States.ALL"],
                               "IntervalSeconds":30,
                               "MaxAttempts":3
                              }
                           ]
                },
                "checkRemainingAccounts": {
                "Type":"Choice",
                "Choices":[
                           {
                              "Variable":"$.done",
                              "BooleanEquals":false,
                              "Next":"UpdateAccounts"
                           }
                        ],
                        "Default":"done"
                },
                "done": {
                  "Type": "Pass",
                  "End": true
                }
              }
            }

          - {
            querierArn: !GetAtt [ ZuoraRetentionQuerier, Arn ],
            fetcherArn: !GetAtt [ ZuoraRetentionJobResult, Arn ],
            fetchFilesArn: !GetAtt [ ZuoraRetentionFileFetcher, Arn ],
            filterArn: !GetAtt [ ZuoraRetentionFilter, Arn ],
            accountUpdaterArn: !GetAtt [ ZuoraRetentionAccountUpdater, Arn ]
          }
    ScheduleRule:
        Type: "AWS::Events::Rule"
        Properties:
          Description: "Trigger the Zuora Retention state machine every day at 03:00 GMT"
          ScheduleExpression: "cron(0 3 ? * * *)"
          State: "ENABLED"
          Targets:
            -
              Arn: !Ref stateMachine
              Id: !Sub 'trigger_zuoraRetention-${Stage}'
              Input: |
                {
                  "dryRun": false
                }
              RoleArn: !GetAtt [ StateMachineTriggerRole, Arn ]
