# frozen_string_literal: true

module Litany
  class ResourceOutput < Base

    attr_reader :attribute, :block, :resource_klass

    # @param resource_klass [Class<Resource>] a subclass of Resource that this output belongs to
    # @param attribute [Symbol, :__ref__] the name of the attribute being outputted, :__ref__ is a special case 'root' attribute
    # @param block [Proc] if provided a block's return is used as the value for the output
    def initialize(resource_klass, attribute, &block)
      @resource_klass = resource_klass
      @attribute = attribute
      @block = block
    end

    # Tests whether this output is a simple attribute output or not
    # @return [Boolean]
    def complex?
      !block.nil?
    end

    # Returns a key value pair for use in a Stack's Outputs section
    # @param resource [Resource] additionally this must be a subclass of `resource_klass` passed to the constructor
    # @return [Tuple<String, Hash>]
    def data_for(resource)
      raise "Type mismatch. #{resource.inspect} is not an instance of #{resource_klass.inspect}" unless resource.is_a?(resource_klass)

      data = {
        Export: { Name: resource.output_name(attribute) },
        Value: value_for(resource)
      }

      [resource.resource_name(attribute), data]
    end

    # Tests if we should skip this output for a specific instance of the resource
    # @param resource [Resource] additionally this must be a subclass of `resource_klass` passed to the constructor
    # @return [Boolean]
    def skip_for?(resource)
      resource.respond_to?(:skip_output?) && resource.skip_output?(attribute)
    end

    # Returns the value of the output
    # @param resource [Resource] a subclass of `resource_klass`
    # @return [Hash, String]
    def value_for(resource)
      if complex?
        resource.instance_eval(&block)
      else
        attribute == :__ref__ ? resource.ref(resource) : resource.ref(resource, attribute)
      end
    end

    def to_s
      raise "This object shouldn't be turned into a string call `data_for` instead.  Raising because this is likely an error."
    end

    def inspect
      "<ResourceOutput: ResourceClass: #{resource_klass.inspect}; Attribute: #{attribute}; Complex: #{complex?.inspect}>"
    end
  end
end

