#https://sim.amazon.com/issues/V877961959
#blog: https://quip-amazon.com/eZlqAXRsXdIi/Use-Amazon-Connect-APIs-to-automatically-evaluate-agent-customer-interactions
# Main CFT
AWSTemplateFormatVersion: 2010-09-09
Description: "Create DITL CCP and associated friends"

Parameters:
    AmazonConnectInstanceARN:
        Type: String
        Description: What is the ARN for your Amazon Connect Instance?
        Default: <insert arn here>
    BasicQueueARN:
        Type: String
        Description: Amazon Connect Basic Queue ARN - this is needed to route a call to an agent
        Default: <insert arn here>
    S3BucketName:
        Type: String
        Description: Name of the existing Amazon Connect Speech Analytics S3 bucket
        Default: <insert bucket name here>




Mappings:
  CFTParameters:
    S3Bucket:
      Name: aws-contact-center-blog
    S3Prefix:
      Value: evaluation-forms-api-launch
    ContactFlowInstaller:
      Name: install_contact_flows.yml
    EVALFormInstaller:
      Name: install_eval_form.yml
    TriggerInstaller:
      Name: install_s3_trigger.yml


Resources:
##################~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  BlogArtifacts:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Delete
    UpdateReplacePolicy: Retain
    Properties:
      OwnershipControls:
        Rules:
          - ObjectOwnership: ObjectWriter
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      LoggingConfiguration:
        DestinationBucketName: !Ref BlogBucketLogs
        LogFilePrefix: blog-logs

  BlogBucketLogs:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Delete
    UpdateReplacePolicy: Retain
    Properties:
      OwnershipControls:
        Rules:
          - ObjectOwnership: ObjectWriter
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256

  BlogBucketLogsPolicy:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
      Bucket: !Ref BlogBucketLogs
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Action:
              - 's3:PutObject'
            Effect: Allow
            Principal:
              Service: logging.s3.amazonaws.com
            Resource: !Join 
              - ''
              - - 'arn:aws:s3:::'
                - !Ref BlogBucketLogs
                - /*
            Condition:
              ArnLike:
                'aws:SourceArn': !GetAtt 
                  - BlogArtifacts
                  - Arn
              StringEquals:
                'aws:SourceAccount': !Sub '${AWS::AccountId}'
                
  CopyArtifactsLambdaIamRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 's3:PutObject'
                Resource: !Sub 'arn:aws:s3:::${BlogArtifacts}/*'
              - Effect: Allow
                Action:
                  - 's3:GetObject'
                  - 's3:GetObjectVersion'
                Resource:
                  - !Sub 
                    - 'arn:aws:s3:::${S3BucketName}/*'
                    - S3BucketName: !FindInMap 
                        - CFTParameters
                        - S3Bucket
                        - Name
              - Effect: Allow
                Action:
                  - 's3:ListBucket'
                  - 's3:ListBucketVersions'
                Resource:
                  - !Sub 
                    - 'arn:aws:s3:::${S3BucketName}/*'
                    - S3BucketName: !FindInMap 
                        - CFTParameters
                        - S3Bucket
                        - Name
                  - !Sub 'arn:aws:s3:::${BlogArtifacts}/*'
              - Effect: Allow
                Action:
                  - 's3:DeleteObject'
                Resource:
                  - !Sub 'arn:aws:s3:::${BlogArtifacts}/*'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'

  CustomResourceCopySourceFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      ReservedConcurrentExecutions: 10
      Role: !GetAtt CopyArtifactsLambdaIamRole.Arn
      Handler: index.handler
      Runtime: nodejs18.x
      Code:
        ZipFile: >
          /**
          * Stuff that needs to be copied go into this array
          * This includes CFT files, zip files, images etc.
          */

          const sourceObjectArray = [
            'install_contact_flows.yml',
            'install_eval_form.yml',
            'evaluation-form-blog-create-form.zip',
            'install_s3_trigger.yml',
            'evaluation-forms-api-demo.zip'
          ];

          //~ Don't edit below this line ~//

          // Copyright 2022 Amazon.com and its affiliates; all rights reserved.
          // This file is Amazon Web Services Content and may not be duplicated or
          // distributed without permission.

          const {S3Client, CopyObjectCommand, DeleteObjectsCommand } = require("@aws-sdk/client-s3");
          const s3 = new S3Client();
          const response = require('cfn-response');


          exports.handler = async (event, context) => {
              const sourceBucket = event.ResourceProperties.SourceBucket;
              const sourcePrefix = event.ResourceProperties.SourcePrefix;
              console.log(JSON.stringify(event));
              var result = {responseStatus: 'FAILED', responseData: {Data: 'Never updated'}};
              try {
                  console.log(`Received event with type ${event.RequestType}`); 
                  if(event.RequestType === 'Create' || event.RequestType === 'Update') {
                      var copyResult = await Promise.all(
                          sourceObjectArray.map( async (object) => {
                            console.log('Copying with', object, `${sourceBucket}/${sourcePrefix}/${object}`)
                            const input = {
                              "Bucket": event.ResourceProperties.BlogArtifacts,
                              "CopySource": `${sourceBucket}/${sourcePrefix}/${object}`,
                              "Key": object
                            };
                            const command = new CopyObjectCommand(input);
                            const s3Result = await s3.send(command);
                            console.log(`Finished uploading File with result ${JSON.stringify(s3Result, 0, 4)}`);
                          }),
                      );
                      result.responseStatus = 'SUCCESS';
                      result.responseData['Data'] = 'Successfully uploaded files';
                  } else if (event.RequestType === 'Delete') {
                      console.log('Deleting objects from S3 : ' + event.ResourceProperties.BlogArtifacts);
                      var deleteobjects = [];
                      var cleanupResult = await Promise.all(
                          sourceObjectArray.map( async (object) => {
                            deleteobjects.push({Key : object});
                          }),
                      );                        
                      var input = {
                            Bucket: event.ResourceProperties.BlogArtifacts,
                            Delete: { Objects: deleteobjects}
                        };
                      const command = new DeleteObjectsCommand(input);
                      console.log(JSON.stringify(command));
                      try{
                        const s3Result = await s3.send(command);                  
                        console.log(`Finished deleting files with result ${JSON.stringify(s3Result, 0, 4)}`);
                      }catch(e){
                        console.log(e);
                      }
                      
                      result.responseStatus = 'SUCCESS',
                      result.responseData['Data'] = 'Successfully deleted files';
                  }
              } catch (error) {
                  console.log(JSON.stringify(error, 0, 4));
                  result.responseStatus = 'FAILED';
                  result.responseData['Data'] = 'Failed to process event';
              } finally {
                console.log('Sending the response back to CloudFormation');    
                var resp;
                try{
                  resp = await responsePromise(event, context, result.responseStatus, result.responseData, `mainstack`);
                  console.log(JSON.stringify(resp));
                  return resp;
                }catch(e){
                  console.log(e);        
                }
                  
              }
          };
          function responsePromise(event, context, responseStatus, responseData, physicalResourceId) {
              return new Promise(() => response.send(event, context, responseStatus, responseData, physicalResourceId));
          }
      Timeout: 50

  CopyCfnStacksLambdaTrigger:
    Type: 'Custom::CopyCfnResources'
    Properties:
      ServiceToken: !GetAtt CustomResourceCopySourceFunction.Arn
      BlogArtifacts: !Ref BlogArtifacts
      SourceBucket: !FindInMap 
        - CFTParameters
        - S3Bucket
        - Name
      SourcePrefix: !FindInMap 
        - CFTParameters
        - S3Prefix
        - Value
    DependsOn: CustomResourceCopySourceFunction


##################~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# 1: Install contact flows
  ACCFs:
    Type: AWS::CloudFormation::Stack        
    DependsOn: 
      - CustomResourceCopySourceFunction
      - CopyCfnStacksLambdaTrigger
      - CopyArtifactsLambdaIamRole
    Properties:
        TemplateURL: !Join
                -   ""
                -   - "https://"
                    - !Ref BlogArtifacts
                    - ".s3."
                    - !Ref "AWS::Region"
                    - ".amazonaws.com/"
                    - !FindInMap [CFTParameters, ContactFlowInstaller, Name]
        Parameters:
            AmazonConnectInstanceARN: !Ref AmazonConnectInstanceARN
            BasicQueueARN: !Ref BasicQueueARN

# # 2: Install the evaluation form
  EVLFRM:
    Type: AWS::CloudFormation::Stack
    DependsOn: 
      - ACCFs
    Properties:
        TemplateURL: !Join
            -   ""
            -   - "https://"
                - !Ref BlogArtifacts
                - ".s3."
                - !Ref "AWS::Region"
                - ".amazonaws.com/"
                - !FindInMap [CFTParameters, EVALFormInstaller, Name]
        Parameters:
          DataLocation: !Ref BlogArtifacts 
          AmazonConnectInstanceARN: !Ref AmazonConnectInstanceARN

# 3: Setup an S3 trigger
  S3Trigger:
    Type: AWS::CloudFormation::Stack
    DependsOn:
            - EVLFRM
    Properties:
        TemplateURL: !Join
            -   ""
            -   - "https://"
                - !Ref BlogArtifacts
                - ".s3."
                - !Ref "AWS::Region"
                - ".amazonaws.com/"
                - !FindInMap [CFTParameters, TriggerInstaller, Name]
        Parameters:
          AmazonConnectInstanceARN: !Ref AmazonConnectInstanceARN
          SourceCodeLocation: !Ref BlogArtifacts 
          SpeechAnalysisS3Bucket: !Ref S3BucketName 
          EvaluationFormId: !GetAtt [EVLFRM, Outputs.EvalFormID] 

# Outputs
Outputs:
  BasicContactFlowCfId:
      Description: CCP URL
      Value: !GetAtt [ACCFs, Outputs.BasicContactFlowCfId]
  SurveyContactFlowID:
      Description: Enduser URL - customer facing 
      Value: !GetAtt [ACCFs, Outputs.SurveyContactFlowID]
  EvalFormID: 
      Description: This is the ID of the form you created
      Value: !GetAtt [EVLFRM, Outputs.EvalFormID]

