# frozen_string_literal: true

module Spree
  module Preferences
    module PreferableClassMethods
      def preference(name, type, *args)
        options = args.extract_options!
        options.assert_valid_keys(:default, :description)
        default = options[:default]
        description = options[:description] || name

        # cache_key will be nil for new objects, then if we check if there
        # is a pending preference before going to default
        define_method preference_getter_method(name) do
          # perference_cache_key will only be nil/false for new records
          #
          if preference_cache_key(name)
            preference_store.get(preference_cache_key(name), default)
          else
            get_pending_preference(name) || default
          end
        end
        alias_method prefers_getter_method(name), preference_getter_method(name)

        define_method preference_setter_method(name) do |value|
          value = convert_preference_value(value, type)
          if preference_cache_key(name)
            preference_store.set preference_cache_key(name), value, type
          else
            add_pending_preference(name, value)
          end
        end
        alias_method prefers_setter_method(name), preference_setter_method(name)

        define_method preference_default_getter_method(name) do
          default
        end

        define_method preference_type_getter_method(name) do
          type
        end

        define_method preference_description_getter_method(name) do
          description
        end
      end

      def remove_preference(name)
        if method_defined? preference_getter_method(name)
          remove_method preference_getter_method(name)
        end
        if method_defined? preference_setter_method(name)
          remove_method preference_setter_method(name)
        end
        if method_defined? prefers_getter_method(name)
          remove_method prefers_getter_method(name)
        end
        if method_defined? prefers_setter_method(name)
          remove_method prefers_setter_method(name)
        end
        if method_defined? preference_default_getter_method(name)
          remove_method preference_default_getter_method(name)
        end
        if method_defined? preference_type_getter_method(name)
          remove_method preference_type_getter_method(name)
        end
        return unless method_defined? preference_description_getter_method(name)

        remove_method preference_description_getter_method(name)
      end

      def preference_getter_method(name)
        :"preferred_#{name}"
      end

      def preference_setter_method(name)
        :"preferred_#{name}="
      end

      def prefers_getter_method(name)
        :"prefers_#{name}?"
      end

      def prefers_setter_method(name)
        :"prefers_#{name}="
      end

      def preference_default_getter_method(name)
        :"preferred_#{name}_default"
      end

      def preference_type_getter_method(name)
        :"preferred_#{name}_type"
      end

      def preference_description_getter_method(name)
        :"preferred_#{name}_description"
      end
    end
  end
end
