# frozen_string_literal: true

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

module Litany
  class SQSQueue < Resource

    cfn_type 'AWS::SQS::Queue'

    output
    output :Arn

    id_validator /^arn:aws:sqs:[\w-]+-\d:\d+:[\w-]+$/

    flag :fifo, false
    flag :deduplication, false

    property :delay_messages, 0, 0..900
    property :dead_letter_retries, 5, 1..100
    property :message_max_size, 262_144, 1024..262_144
    property :message_retention, 345_600, 60..1_209_600
    property :receive_message_wait, 0, 0..20
    property :visibility_timeout, 30, 0..43_200

    child_resource EventsRule, :event, automatic: :on_access
    child_resource SQSQueuePolicy, :policy, automatic: :on_access

    resource_reference SQSQueue, :dead_letter_queue, required: false

    resource_collection CloudWatchAlarm, :cloudwatch_alarm, required: false

    validator :fifo_dedupe do
      raise 'Only fifo queues may enable deduplication.' if deduplication? && !fifo?
    end

    validator :dead_letter do
      raise 'If you set `dead_letter_retries` you must also set `dead_letter_queue`.' if set_dead_letter_retries? && !set_dead_letter_queue?
    end

    def allow(topic:, in_account: { Ref: 'AWS::AccountId' }, region: '*')
      policy.allow(topic: topic, in_account: in_account, region: region)
    end

    def event_rate(minutes: nil, hours: nil, days: nil)
      value = [minutes, hours, days].compact.first
      raise 'You must provide a value for either `minutes`, `hours`, or `days` but not multiple.' unless !minutes.nil? ^ !hours.nil? ^ !days.nil?
      raise 'You must provide a positive value' unless value.positive?

      unit = 'minute'
      unit = 'hour' unless hours.nil?
      unit = 'day' unless days.nil?

      unit = "#{unit}s" if value > 1
      event.schedule "rate(#{value} #{unit})"
    end

    def finalize_resource
      return unless set_event?

      deduplication if fifo?
      event.target_queue(self)
      policy.allow_service(service: 'events.amazonaws.com', from: ref(event, :Arn))
    end

    def properties
      # Not Implementing: QueueName
      props = {
        DelaySeconds: delay_messages,
        MaximumMessageSize: message_max_size,
        MessageRetentionPeriod: message_retention,
        ReceiveMessageWaitTimeSeconds: receive_message_wait,
        VisibilityTimeout: visibility_timeout
      }

      props[:ContentBasedDeduplication] = deduplication? if fifo?
      props[:FifoQueue] = fifo? if fifo? # TODO: pre 2.0 compatability

      if set_dead_letter_queue?
        props[:RedrivePolicy] = {
          deadLetterTargetArn: ref(dead_letter_queue, :Arn),
          maxReceiveCount: dead_letter_retries
        }
      end

      props
    end

  end
end
