<reponame>ColoradoCowboy/aws_cdk_examples<gh_stars>0using Amazon.CDK;
using Amazon.CDK.AWS.Route53;
using Amazon.CDK.AWS.Route53.Targets;
using Amazon.CDK.AWS.S3;
using Amazon.CDK.AWS.S3.Deployment;
using Amazon.CDK.AWS.CertificateManager;
using Amazon.CDK.AWS.CloudFront;
using Constructs;
using System.Linq;

namespace StaticSite
{
    public class StaticSiteConstructProps
    {
        public string DomainName;

        public string SiteSubDomain;
    }

    public class StaticSiteConstruct : Construct
    {

        // A simple construct that contains a collection of AWS S3 buckets.
        public StaticSiteConstruct(Construct scope, string id, StaticSiteConstructProps props) : base(scope, id)
        {
            var zone = HostedZone.FromLookup(this, "Zone", new HostedZoneProviderProps
            {
                DomainName = props.DomainName
            });

            var siteDomain = (string) ($"{props.SiteSubDomain}.{props.DomainName}");
            new CfnOutput(this, "Site", new CfnOutputProps
            {
                Value = $"https://{siteDomain}"
            });

            var siteBucket = new Bucket(this, "SiteBucket", new BucketProps
            {
                BucketName = siteDomain,
                WebsiteIndexDocument = "index.html",
                WebsiteErrorDocument = "error.html",
                PublicReadAccess = true,

                // The default removal policy is RETAIN, which means that cdk destroy will not attempt to delete
                // the new bucket, and it will remain in your account until manually deleted. By setting the policy to
                // DESTROY, cdk destroy will attempt to delete the bucket, but will error if the bucket is not empty.
                RemovalPolicy = RemovalPolicy.DESTROY // NOT recommended for production code
            });

            new CfnOutput(this, "Bucket", new CfnOutputProps
            {
                Value = siteBucket.BucketName
            });

            var certificateArn = new DnsValidatedCertificate(this, "SiteCertificate", new DnsValidatedCertificateProps
            {
                DomainName = siteDomain,
                HostedZone = zone
            }).CertificateArn;

            new CfnOutput(this, "Certificate", new CfnOutputProps{Value = certificateArn});

            var behavior = new Behavior();
            behavior.IsDefaultBehavior = true;

            var distribution = new CloudFrontWebDistribution(this, "SiteDistribution", new CloudFrontWebDistributionProps
            {
                AliasConfiguration = new AliasConfiguration
                {
                    AcmCertRef = certificateArn,
                    Names = new string[] {siteDomain},
                    SslMethod = SSLMethod.SNI,
                    SecurityPolicy = SecurityPolicyProtocol.TLS_V1_2016
                },
                OriginConfigs = new ISourceConfiguration[]
                {
                    new SourceConfiguration
                    {
                        S3OriginSource = new S3OriginConfig
                        {
                            S3BucketSource = siteBucket
                        },
                        Behaviors = new Behavior[] {behavior}
                    }
                }
            });

            new CfnOutput(this, "DistributionId", new CfnOutputProps
            {
                Value = distribution.DistributionId
            });

            new ARecord(this, "SiteAliasRecord", new ARecordProps
            {
                RecordName = siteDomain,
                Target = RecordTarget.FromAlias(new CloudFrontTarget(distribution)),
                Zone = zone
            });

            new BucketDeployment(this, "DeployWithInvalidation", new BucketDeploymentProps
            {
                Sources = new ISource[] {Source.Asset("./site-contents")},
                DestinationBucket = siteBucket,
                Distribution = distribution,
                DistributionPaths = new string[] {"/*"}
            });
        }
    }
}
