---
AWSTemplateFormatVersion: '2010-09-09'
Description: Static Web Site

Parameters:
  BucketName:
    Type: String
    Description: Unique name for S3 bucket 
    Default: enterbucketnamehere

  DomainName:
    Type: String
    Description: The hostname for the certificate 
    Default: enteryourdomainhere.com

  HostedZoneId:
    Type: String
    Description: The ID of the existing Route 53 Hosted Zone

  Certificate:
    Type: String
    Description: The ARN of the ACM certificate

Resources:
        
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
      AccessControl: Private

  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3Bucket
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: "cloudfront.amazonaws.com"
            Action: 's3:GetObject'
            Resource: !Sub arn:aws:s3:::${S3Bucket}/*
            Condition:
              StringEquals:
                AWS:SourceArn: !Sub
                  - arn:aws:cloudfront::${AWS::AccountId}:distribution/${DistId}
                  - DistId: !GetAtt CloudFrontDistribution.Id

  RecordSetMain:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneId: !Ref HostedZoneId
      Name: !Ref DomainName
      Type: A
      AliasTarget:
        HostedZoneId: Z2FDTNDATAQYW2
        DNSName: !GetAtt CloudFrontDistribution.DomainName

  RecordSetWww:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneId: !Ref HostedZoneId
      Name: !Sub www.${DomainName}
      Type: A
      AliasTarget:
        HostedZoneId: Z2FDTNDATAQYW2  # CloudFront hosted zone ID
        DNSName: !GetAtt CloudFrontDistribution.DomainName


  CloudFrontOriginAccessControl:
    Type: AWS::CloudFront::OriginAccessControl
    Properties:
      OriginAccessControlConfig:
        Description: "origin access control(OAC) for allowing cloudfront to access S3 bucket"
        Name: website-OAC
        OriginAccessControlOriginType: s3
        SigningBehavior: always
        SigningProtocol: sigv4

  CloudFrontOriginIdentity:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: "origin identity"

  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    DependsOn:
      - S3Bucket
    Properties:
      DistributionConfig:
        Origins:
          - DomainName: !Sub ${S3Bucket}.s3.us-west-2.amazonaws.com
            Id: static-hosting
            S3OriginConfig:
              OriginAccessIdentity: ""
            OriginAccessControlId: !GetAtt CloudFrontOriginAccessControl.Id
        Enabled: "true"
        DefaultRootObject: index.html
        CustomErrorResponses:
          - ErrorCode: 404
            ResponseCode: 200
            ResponsePagePath: /index.html
          - ErrorCode: 403
            ResponseCode: 200
            ResponsePagePath: /index.html
        HttpVersion: http2
        Aliases:
          - !Ref DomainName
          - !Sub www.${DomainName}
        ViewerCertificate:
          AcmCertificateArn: !Ref Certificate
          MinimumProtocolVersion: TLSv1.2_2021
          SslSupportMethod: sni-only
        DefaultCacheBehavior:
          CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
          AllowedMethods:
            - DELETE
            - GET
            - HEAD
            - OPTIONS
            - PATCH
            - POST
            - PUT
          Compress: true
          TargetOriginId: static-hosting
          ForwardedValues:
            QueryString: "false"
            Cookies:
              Forward: none
          ViewerProtocolPolicy: redirect-to-https
          FunctionAssociations:
            - EventType: viewer-request
              FunctionARN: !GetAtt DistributionFunction.FunctionMetadata.FunctionARN

  DistributionFunction:
    Type: AWS::CloudFront::Function
    Properties:
      AutoPublish: true
      FunctionCode: |
        function handler(event) {
          var request = event.request;
          var uri = request.uri;
          
          // Check whether the URI is missing a file name.
          if (uri.endsWith('/')) {
              request.uri += 'index.html';
          } 
          // Check whether the URI is missing a file extension.
          else if (!uri.includes('.')) {
              request.uri += '/index.html';
          }

          return request;
        }
      FunctionConfig:
        Comment: Redirect-Default-Index-Request
        Runtime: cloudfront-js-1.0
      Name: redirect-index-request

Outputs:
  S3Bucket:
    Value: !Ref S3Bucket
    Description: S3 Bucket that contains a static web site

  CloudFrontURLMain:
    Value: !GetAtt [CloudFrontDistribution, DomainName]
    Description: URL of the CloudFront distribution for the main environment

  
