"""Oi cunt!

brutalcompassion.org infrastructure
"""

import hashlib
from datetime import date
from pathlib import Path

import aws_cdk as cdk
import aws_cdk.aws_certificatemanager as acm
import aws_cdk.aws_cloudfront as cloudfront
import aws_cdk.aws_cloudfront_origins as origins
import aws_cdk.aws_route53 as route53
import aws_cdk.aws_route53_targets as targets
import aws_cdk.aws_s3 as s3
import aws_cdk.aws_s3_deployment as deployment


class BrutalCompassion(cdk.App):
    def __init__(self) -> None:
        super().__init__()
        stack = BrutalCompassionStack(
            self,
            id="BrutalCompassionStack",
            env=cdk.Environment(region="us-east-1"),
            hosted_zone_id="Z02061931K3BVBREP0OIW",
            zone_name="brutalcompassion.org.",
        )
        cdk.Tags.of(self).add("project", stack.domain_name)


class BrutalCompassionStack(cdk.Stack):
    """Static website stack

    CloudFront -> S3 Bucket -> Files

    - Deployment
    - Certificate
    - DNS records
    - Log bucket
    """

    def __init__(
        self, scope, id: str, env: cdk.Environment, hosted_zone_id: str, zone_name: str
    ):
        super().__init__(
            scope,
            id,
            description="BrutalCompassion",
            env=env,
        )
        self.domain_name = zone_name[:-1]

        # A bucket to hold website files.
        bucket = s3.Bucket(self, "Bucket")

        # Reference an existing hosted zone...
        hosted_zone = route53.PublicHostedZone.from_public_hosted_zone_attributes(
            self,
            "HostedZone",
            hosted_zone_id=hosted_zone_id,
            zone_name=zone_name,
        )

        # ...to create a certificate.
        certificate = acm.Certificate(
            self,
            "Certificate",
            domain_name=self.domain_name,
            validation=acm.CertificateValidation.from_dns(hosted_zone),
        )

        # A CloudFront distribution delivers from the bucket.
        distribution = cloudfront.Distribution(
            scope=self,
            id="Distribution",
            default_behavior=cloudfront.BehaviorOptions(
                origin=origins.S3BucketOrigin.with_origin_access_control(
                    bucket, origin_shield_enabled=False
                ),
                # Configure CORS
                response_headers_policy=cloudfront.ResponseHeadersPolicy(
                    scope=self,
                    id="ResponseHeadersPolicy",
                    cors_behavior=cloudfront.ResponseHeadersCorsBehavior(
                        access_control_allow_credentials=False,
                        access_control_allow_headers=["*"],
                        access_control_allow_methods=["ALL"],
                        access_control_allow_origins=["brutalcompassion.org"],
                        origin_override=False,
                    ),
                ),
                viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
            ),
            certificate=certificate,
            # Serve qrcode.html from root before 3/14.
            default_root_object=(
                f"{hashlib.sha256(b"index").hexdigest()}.html"
                if date.today() >= date(2025, 3, 14)
                else "qrcode.html"
            ),
            domain_names=[self.domain_name],
            enable_logging=True,
            # Use cheapest class of edge locations.
            price_class=cloudfront.PriceClass.PRICE_CLASS_100,
        )

        # The bucket is populated with local files, with automatic cache invalidation.
        deployment.BucketDeployment(
            self,
            id="BucketDeployment",
            destination_bucket=bucket,
            sources=[
                deployment.Source.asset(
                    str(Path(__file__).parent),
                    exclude=[
                        line.rstrip()
                        for line in (Path(__file__).parent / ".gitignore").open()
                    ]
                    + [".git"],
                    ignore_mode=cdk.IgnoreMode.GIT,
                )
            ],
            # Configure cache invalidation.
            distribution=distribution,
        )

        # Create an alias record for the CloudFront distribution.
        route53.ARecord(
            scope=self,
            id="ARecord",
            target=route53.RecordTarget.from_alias(
                targets.CloudFrontTarget(distribution)
            ),
            zone=hosted_zone,
            record_name=self.domain_name,
        )


if __name__ == "__main__":
    BrutalCompassion().synth()
