module StaticRecord
  # The main gate for the model class methods.
  module GatewayModel
    def all
      records
    end

    def find(*ids)
      context = records.select { |c| ids.include? c.id }

      raise RecordNotFound.new(
        "Couldn't find #{to_s.tableize} with an out of range value for id.",
        to_s.tableize,
        'id'
      ) if context.empty?

      return context.first if context.length == 1
      context
    end

    def find_by(hash)
      unless hash.is_a? Hash
        raise InvalidParameterError,
              'Couldn\'t find record, because search closure is not a Hash.'
      end

      key, value = hash.first

      context = records.select { |c| c.attributes[key] == value }

      return context.first if context.length == 1
      context
    end

    def find_by!(hash)
      context = find_by hash
      key, value = hash.first

      raise RecordNotFound.new(
        "Couldn't find #{to_s.tableize} like #{key} as #{value}",
        to_s.tableize,
        'id'
      ) if context.empty?
      context
    end

    private

    def records
      load
      @records
    end

    def array_proxy(attribute, params)
      return records.send attribute, params unless params.empty?
      records.send attribute
    end

    def method_missing(meth, *params, &block)
      attribute = meth.to_s.gsub(/=$/, '')

      if meth.to_s =~ /^find_by_(.+)/
        attribute = meth.to_s.gsub(/^find_by_/, '')

        return find_by(attribute.to_sym => params.first)
      elsif records.respond_to? attribute.to_sym
        # The method missing is part of Array object, try pass it
        return array_proxy attribute.to_sym, params unless meth.to_s =~ /=$/
      end

      super
    end

    def respond_to_missing?(meth, *args)
      attribute = meth.to_s.gsub(/=$/, '')

      if meth.to_s =~ /^find_by_(.+)/
        attribute = meth.to_s.gsub(/^find_by_/, '')

        return attribute? attribute
      end

      records.respond_to?(attribute.to_sym) || super
    end
  end
end