# frozen_string_literal: true

require 'litany/resource'

module Litany
  class DNSAlias < Resource
    cfn_type 'AWS::Route53::RecordSet'

    child_resource DNSHealthCheck, :health_check, automatic: :on_access

    flag :latency_routing, false

    property :alias_name, nil, [nil, Symbol, String]
    property :comment, nil, [nil, String]
    property :target, nil, [ApplicationLoadBalancer, BeanstalkEnvironment, CloudFrontDistribution, NetworkLoadBalancer, S3Bucket, VPCEndpoint, /^.*\.cloudfront\.net$/]
    property :type, :a, [:a, :aaaa, :cname, :mx, :naptr, :ptr, :spf, :srv, :txt]

    resource_reference CloudWatchAlarm, :healthy_alarm, required: false
    resource_reference Route53Zone, :zone

    def beanstalk_environment_hosted_zone_id(region)
      # Pulled from: http://docs.aws.amazon.com/general/latest/gr/rande.html#elasticbeanstalk_region

      @eb_zone_ids ||= {
        'us-east-2': 'Z14LCN19Q5QHIC',
        'us-east-1': 'Z117KPS5GTRQ2G',
        'us-west-1': 'Z1LQECGX5PH1X',
        'us-west-2': 'Z38NKT9BP95V3O',
        'ca-central-1': 'ZJFCZL7SSZB5I',
        'ap-south-1': 'Z18NTBI3Y7N9TZ',
        'ap-northeast-2': 'Z3JE5OI70TWKCP',
        'ap-southeast-1': 'Z16FZ9L249IFLT',
        'ap-southeast-2': 'Z2PCDNR3VC2G1N',
        'ap-northeast-1': 'Z1R25G3KIG2GBW',
        'eu-central-1': 'Z1FRNW7UH4DEZJ',
        'eu-west-1': 'Z2NYPWQ7DFZAZH',
        'eu-west-2': 'Z1GKAAAUGATPF1',
        'sa-east-1': 'Z10X7K2B4QSOFV'
      }

      raise "Unknown HostedZoneId for Beanstalk region #{region}" unless @eb_zone_ids.include?(region)

      @eb_zone_ids[region]
    end

    def evaluate_health?
      set_healthy_alarm? && multi_region? && latency_routing?
    end

    def finalize_resource
      health_check.alarm healthy_alarm if set_healthy_alarm?
    end

    def properties
      dns_alias_name = alias_name || name
      props = {
        HostedZoneId: ref(zone),
        Name: dns_alias_name.to_s.end_with?('.') ? dns_alias_name : "#{dns_alias_name}.",
        Type: type.upcase,
      }

      props[:AliasTarget] = case target
        when ApplicationLoadBalancer, NetworkLoadBalancer
          {
            DNSName: ref(target, :DNSName),
            HostedZoneId: ref(target, :CanonicalHostedZoneID)
          }
        when CloudFrontDistribution
          {
            DNSName: ref(target, :DomainName),
            HostedZoneId: 'Z2FDTNDATAQYW2'
          }
        when BeanstalkEnvironment
          {
            DNSName: target.dns_name,
            HostedZoneId: active_environment.nil? ? '' : beanstalk_environment_hosted_zone_id(active_environment.region)
          }
        when S3Bucket
          {
            DNSName: ref(target, :WebsiteURL),
            HostedZoneId: target.hosted_zone_id
          }
        when VPCEndpoint
          {
            DNSName: ref(target, :DNSName),
            HostedZoneId: ref(target, :HostedZoneID)
          }
        when /^.*\.cloudfront\.net$/
          {
            DNSName: target,
            HostedZoneId: 'Z2FDTNDATAQYW2'
          }
        else
          raise "Uncertain how to create an alias target for #{target.to_s}"
      end

      props[:AliasTarget][:EvaluateTargetHealth] = evaluate_health?
      props[:Comment] = comment if set_comment?
      props[:HealthCheckId] = ref(health_check) if set_healthy_alarm?

      if latency_routing?
        props[:Region] = {Ref: 'AWS::Region'}
        props[:SetIdentifier] = {Ref: 'AWS::Region'}
      end

      props
    end

    def sanitized_name
      name.gsub('*', 'wildcard')
    end
  end
end
