# frozen_string_literal: true

module Floe
  class Workflow
    class PayloadTemplate
      def initialize(payload)
        @payload_template = parse_payload(payload)
      end

      def value(context, inputs = {})
        interpolate_value(payload_template, context, inputs)
      end

      private

      attr_reader :payload_template

      def parse_payload(value)
        case value
        when Array  then parse_payload_array(value)
        when Hash   then parse_payload_hash(value)
        when String then parse_payload_string(value)
        else
          value
        end
      end

      def parse_payload_array(value)
        value.map { |val| parse_payload(val) }
      end

      def parse_payload_hash(value)
        value.to_h do |key, val|
          if key.end_with?(".$")
            check_key_conflicts(key, value)

            [key, parse_payload(val)]
          else
            [key, val]
          end
        end
      end

      def parse_payload_string(value)
        return Path.new(value)              if Path.path?(value)
        return IntrinsicFunction.new(value) if IntrinsicFunction.intrinsic_function?(value)

        value
      end

      def interpolate_value(value, context, inputs)
        case value
        when Array                   then interpolate_value_array(value, context, inputs)
        when Hash                    then interpolate_value_hash(value, context, inputs)
        when Path, IntrinsicFunction then value.value(context, inputs)
        else
          value
        end
      end

      def interpolate_value_array(value, context, inputs)
        value.map { |val| interpolate_value(val, context, inputs) }
      end

      def interpolate_value_hash(value, context, inputs)
        value.to_h do |key, val|
          if key.end_with?(".$")
            [key.chomp(".$"), interpolate_value(val, context, inputs)]
          else
            [key, val]
          end
        end
      end

      def check_key_conflicts(key, value)
        if value.key?(key.chomp(".$"))
          raise Floe::InvalidWorkflowError, "both #{key} and #{key.chomp(".$")} present"
        end
      end
    end
  end
end