using Amazon.CDK;
using Amazon.CDK.AWS.CertificateManager;
using Amazon.CDK.AWS.EC2;
using Amazon.CDK.AWS.Ecr.Assets;
using Amazon.CDK.AWS.ECS;
using Amazon.CDK.AWS.ECS.Patterns;
using Amazon.CDK.AWS.Route53;
using Amazon.CDK.AWS.Route53.Targets;
using Constructs;
using Microsoft.Extensions.Options;
using System.Collections.Generic;

namespace Route53AlbFargateCdkDotnet
{
    public class Route53AlbFargateCdkDotnetStack : Stack
    {
        internal Route53AlbFargateCdkDotnetStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            // Replace the value with your domain name
            string apiDomainName = "api.YOUR-DOMAIN.com";

            // 1. Hosted zone
            var hostedZone = new HostedZone(this, "hosted-zone", new HostedZoneProps
            {
                ZoneName = apiDomainName
            });
            hostedZone.ApplyRemovalPolicy(RemovalPolicy.RETAIN);


            // 2. SSL certificate via ACM
            var certificate = new Certificate(this, "certificate", new CertificateProps
            {
                DomainName = apiDomainName,
                Validation = CertificateValidation.FromDns(hostedZone),
            });


            // 3. VPC with public and private subnets
            var vpc = new Vpc(this, "vpc", new VpcProps
            {
                Cidr = "10.0.0.0/16",
                MaxAzs = 3,
                SubnetConfiguration = new[]
                {
                    new SubnetConfiguration
                    {
                        Name="private",
                        SubnetType= SubnetType.PRIVATE_ISOLATED,
                        CidrMask= 24
                    },
                    new SubnetConfiguration
                    {
                        Name="public",
                        SubnetType= SubnetType.PUBLIC,
                        CidrMask= 24
                    }
                }
            });

            // Create required VPC endpoints to privately retrieve docker images from the ECR repository
            // Reference link - https://docs.aws.amazon.com/AmazonECR/latest/userguide/vpc-endpoints.html

            // 4.1. VPC endpoint 1
            var ecrDockerVpcEndpoint = new InterfaceVpcEndpoint(this, "ecr-dkr-vpc-endpoint", new InterfaceVpcEndpointProps
            {
                Vpc = vpc,
                Service = InterfaceVpcEndpointAwsService.ECR_DOCKER,
                PrivateDnsEnabled = true
            });

            // 4.2. VPC endpoint 2
            var ecrVpcEndpoint = new InterfaceVpcEndpoint(this, "ecr-vpc-endpoint", new InterfaceVpcEndpointProps
            {
                Vpc = vpc,
                Service = InterfaceVpcEndpointAwsService.ECR,
                PrivateDnsEnabled = true
            });

            // 4.3. VPC endpoint 3
            var cwVpcEndpoint = new InterfaceVpcEndpoint(this, "cloudwatch-vpc-endpoint", new InterfaceVpcEndpointProps
            {
                Vpc = vpc,
                Service = InterfaceVpcEndpointAwsService.CLOUDWATCH,
                PrivateDnsEnabled = true
            });

            // 4.4. VPC endpoint 4
            var cwLogsVpcEndpoint = new InterfaceVpcEndpoint(this, "cloudwatch-logs-vpc-endpoint", new InterfaceVpcEndpointProps
            {
                Vpc = vpc,
                Service = InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS,
                PrivateDnsEnabled = true
            });

            // 4.5. VPC endpoint 5
            var s3VpcEndpoint = new GatewayVpcEndpoint(this, "s3-vpc-endpoint", new GatewayVpcEndpointProps
            {
                Vpc = vpc,
                Service = GatewayVpcEndpointAwsService.S3
            });


            // 5. ECS cluster
            var ecsCluster = new Cluster(this, "ecs-cluster", new ClusterProps
            {
                Vpc = vpc
            });


            // 6. ECS fargate service frontend by ALB
            var albFargateService = new ApplicationLoadBalancedFargateService(this, "sample-api-service", new ApplicationLoadBalancedFargateServiceProps
            {
                // ----: Networking (Task Subnets) :-----
                // By default, public subnets are used if assignPublicIp is set, otherwise the first available one of Private, Isolated, Public, in that order.

                Cluster = ecsCluster,
                DesiredCount = 1,
                Cpu = 1024,  // 1024 unit represents 1 vCPU (per task)
                MemoryLimitMiB = 2048,
                TaskImageOptions = new ApplicationLoadBalancedTaskImageOptions
                {
                    ContainerPort = 80, // container port, automatically assigned to host port via dynamic port mapping
                    Image = ContainerImage.FromAsset("./src/SampleApplication.API")
                },
                Certificate = certificate,
                DomainName = apiDomainName,
                DomainZone = hostedZone,
                AssignPublicIp = false
            });

            albFargateService.TargetGroup.ConfigureHealthCheck(new Amazon.CDK.AWS.ElasticLoadBalancingV2.HealthCheck
            {
                Path = "/WeatherForecast"
            });
        }
    }
}