# frozen_string_literal: true

require_relative 'finder_methods'
require_relative 'persistence'
require_relative 'query_methods'

module ErpIntegration
  module Fulfil
    class ApiResource
      include Enumerable
      include FinderMethods
      include Persistence
      include QueryMethods

      attr_accessor :resource_klass
      delegate :client, :model_name, to: 'self.class'

      def initialize(resource_klass)
        @resource_klass = resource_klass
      end

      # The `where` and `includes` methods lazyly build a search/read query
      # for Fulfil. By calling `all`, the prepared search/read query will actually
      # be executed and the results will be fetched.
      # @return [Array] An enumerable collection object with all API results.
      def all
        return @results if defined?(@results)

        @results =
          client.put(
            "model/#{model_name}/search_read",
            Query.new(selected_fields, where_clauses)
          ).map { |item| resource_klass.new(item) }
      end

      # The `each` method turns the `ApiResource` instance into an enumerable object.
      # For more information, see https://ruby-doc.org/core-3.0.2/Enumerable.html
      def each(&block)
        all.each(&block)
      end

      # The `client` exposes the `ErpIntegration::Fulfil::Client` to the class.
      # @return [ErpIntegration::Fulfil::Client] The HTTP client for Fulfil.
      def self.client
        Client.new(
          api_key: config.fulfil_api_key,
          merchant_id: config.fulfil_merchant_id
        )
      end

      # The `config` exposes the gem's configuration to the `ApiResource`.
      # @return [ErpIntegration::Configuration] The gem's configuration object.
      def self.config
        ErpIntegration.config
      end

      # Fulfil doesn't use logical naming conventions. However, we do need
      # the name of a model to build the resource URI.
      #
      # By manually setting the model name, we allow the `Fulfil::Connection`
      # module to connect to the correct API endpoint.
      #
      # @param name [String] The logical path name in Fulfil.
      # @return [String] The model name
      def self.model_name=(name)
        instance_variable_set(:@model_name, name)
      end

      def self.model_name
        instance_variable_get(:@model_name)
      end
    end
  end
end