require 'forwardable'

module UnitTests
  class ValidationMatcherScenario
    extend Forwardable

    def initialize(arguments)
      @arguments = arguments.dup
      @matcher_proc = @arguments.delete(:matcher_proc)

      @specified_model_creator = @arguments.delete(:model_creator) do
        raise KeyError.new(<<-MESSAGE)
:model_creator is missing. You can either provide it as an option or as
a method.
        MESSAGE
      end

      @model_creator = model_creator_class.new(@arguments)
    end

    def record
      @_record ||= model.new.tap do |record|
        attribute_default_values_by_name.each do |attribute_name, default_value|
          record.public_send("#{attribute_name}=", default_value)
        end
      end
    end

    def model
      @_model ||= model_creator.call
    end

    def matcher
      @_matcher ||= matcher_proc.call(attribute_name)
    end

    protected

    attr_reader(
      :arguments,
      :existing_value,
      :matcher_proc,
      :model_creator,
      :specified_model_creator,
    )

    private

    def_delegators(
      :model_creator,
      :attribute_name,
      :attribute_default_values_by_name,
    )

    def model_creator_class
      UnitTests::ModelCreators.retrieve(specified_model_creator) ||
        specified_model_creator
    end
  end
end
