# frozen_string_literal: true

require 'litany/resource'
require 'litany/mixins'

module Litany
  class NetworkLoadBalancerTargetGroup < Resource
    include Taggable

    cfn_type 'AWS::ElasticLoadBalancingV2::TargetGroup'
    parent_resource :load_balancer

    flag :disable_healthy_alarm, false

    property :deregistration_delay, 10, [5..3600], inherited: true
    property :health_check_interval, 10, [10, 30], inherited: true
    property :health_check_path, '/', [String], inherited: true
    property :health_check_port, nil, [nil, Integer, String], inherited: true, &:to_s
    property :health_check_protocol, nil, [nil, :http, :https, :tcp], inherited: true
    property :health_check_timeout, 2, [2..60], inherited: true
    property :healthy_threshold, 3, [2..10], inherited: true
    property :healthy_statuses, '200', [String, Integer, Range, Array], inherited: true do |value|
      case value
        when Array
          raise 'Invalid value for `healthy_statuses` array. Only Integers and Ranges allowed.' unless value.all? { |v| v.is_a?(Range) || v.is_a?(Integer) }
          value.collect { |status| status.is_a?(Range) ? "#{status.first}-#{status.last}" : status.to_s }.join(',').to_s
        when Integer
          value.to_s
        when Range
          "#{value.first}-#{value.last}"
        else
          raise 'Invalid value for `healthy_statuses` string. Only comma separated Integers and Ranges allowed.' unless value.split(',').all? { |v| /(^\d+$)|(^\d+-\d+$)/.match(v) }
          value
      end
    end
    property :port, 80, [1..65_535]
    property :protocol, :tcp, :tcp
    property :target_type, nil, [nil, :instance, :ip]

    resource_references Instance, :target, required: false

    resource_collection CloudWatchAlarm, :alarm, required: false

    validator :health_check do
      raise 'Health check timeout, must be smaller than health check interval.' unless health_check_interval > health_check_timeout
    end

    def healthy_alarm(&block)
      alarm("#{name}_healthy", &block)
    end

    def finalize_resource
      return if disable_healthy_alarm?

      healthy_alarm do
        metric 'HealthyHostCount'
        threshold 1 unless set_threshold?
        unit :count
      end
    end

    def properties
      # TODO: Implement TargetGroupAttributes
      # Not Implementing: Name

      hc_protocol = health_check_protocol || protocol

      props = {
        HealthCheckIntervalSeconds: health_check_interval,
        HealthCheckProtocol: hc_protocol.upcase,
        HealthyThresholdCount: healthy_threshold,
        Port: port,
        Protocol: protocol.upcase,
        TargetGroupAttributes: [
          {
            Key: 'deregistration_delay.timeout_seconds',
            Value: deregistration_delay.to_s
          }
        ],
        UnhealthyThresholdCount: healthy_threshold,
        VpcId: ref(load_balancer.service.vpc)
      }

      unless hc_protocol == :tcp
        props[:HealthCheckPath] = health_check_path
        props[:HealthCheckTimeoutSeconds] = health_check_timeout
        props[:Matcher] = {
          HttpCode: healthy_statuses
        }
      end

      props[:TargetType] = target_type if set_target_type?
      props[:HealthCheckPort] = health_check_port if set_health_check_port?
      props[:Targets] = targets.collect { |target| {Id: ref(target), Port: port} } unless targets.empty?

      props
    end

    def default_tags
      {
          LitanyTargetGroupName: self.name,
      }
    end
  end
end
