module Promotions
  class Base < Service::Base
    self.service_endpoint = Settings.hypeman.endpoint
    self.primary_attribute = :id
    class << self
      CLASS_VARIABLES = [:base_path, :entity, :ignored_audit_updates]
      attr_accessor *CLASS_VARIABLES

      def inherited(base)
        super(base)
        CLASS_VARIABLES.each do |class_variable|
          old_value = base.send class_variable
          new_value = old_value || base.superclass.send(class_variable)
          base.send "#{class_variable}=", new_value if old_value.nil?
        end
      end

      def all(options = {})
        response = get self.base_path

        return [] unless response.success?
        response.body[self.entity.pluralize].map do |entity_attributes|
          from_attributes(entity_attributes)
        end
      end

      def find(id, options = {})
        response = get path_for_channel(id)

        return from_errors(response.body) unless response.success?
        from_attributes(response.body[self.entity])
      end

      def path_for_channel(id)
        self.base_path + "/#{id}"
      end
    end
    attr_reader :is_editing

    validates :priority, :title, :description_raw, :image_url, presence: true
    validates :login, presence: true, unless: :is_editing
    validates :priority, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 10 }

    def update(changes)
      @is_editing = true
      @old_values = self.attributes.dup
      self.attributes = changes.dup.except(*self.class.ignored_audit_updates)
      return false unless valid?
      response = put url, { body: update_body.to_json, headers: {'Content-Type' => 'application/json'} }
      errors.add(:base, error_message('Update', 'Hypeman')) unless response.success?

      response.success?
    end

    def save
      return false unless valid?
      response = post self.class.base_path, { body: save_body.to_json, headers: {'Content-Type' => 'application/json'} }

      if response.success?
        @id = response.body[self.class.entity]['id']
        @user_id = response.body[self.class.entity]['user_id']
      else
        errors.add(:base, error_message('Create', 'Hypeman')) unless response.success?
      end
      response.success?
    end

    def destroy
      response = delete url

      errors.add(:base, error_message('Delete', 'Hypeman')) unless response.success?

      response.success?
    end

    def save_body
      raise NotImplementedError
    end

    def update_body
      raise NotImplementedError
    end

    def error_message(action, service)
      "#{action} failed in #{service}"
    end

    def url
      self.class.path_for_channel(@id)
    end

    def user_id
      @user_id.to_i unless @user_id.nil?
    end

    def updated_at
      @updated_at ||= DateTime.parse(@updated_at) rescue nil
    end

    def inserted_at
      @inserted_at ||= DateTime.parse(@inserted_at) rescue nil
    end

    def changes
      attributes.reduce({}) do |hash, (key, new_value)|
        old_value = @old_values[key]
        if old_value != new_value
          hash[key] = { old_value: old_value, new_value: new_value}
        end

        hash
      end
    end
  end
end
