module EnjuCirculation
  module EnjuItem
    def self.included(base)
      base.extend ClassMethods
    end

    module ClassMethods
      FOR_CHECKOUT_CIRCULATION_STATUS = [
        'Available On Shelf',
        'On Loan',
        'Waiting To Be Reshelved'
      ]
      FOR_CHECKOUT_USE_RESTRICTION = [
        'Available For Supply Without Return',
        'Limited Circulation, Long Loan Period',
        'Limited Circulation, Short Loan Period',
        'No Reproduction',
        'Overnight Only',
        'Renewals Not Permitted',
        'Supervision Required',
        'Term Loan',
        'User Signature Required',
        'Limited Circulation, Normal Loan Period'
      ]

      def enju_circulation_item_model
        include InstanceMethods
        has_many :reserves, :foreign_key => :manifestation_id

        scope :for_checkout, ->(identifier_conditions = 'item_identifier IS NOT NULL') {
          includes(:circulation_status, :use_restriction).where(
            'circulation_statuses.name' => FOR_CHECKOUT_CIRCULATION_STATUS,
            'use_restrictions.name' => FOR_CHECKOUT_USE_RESTRICTION
          ).where(identifier_conditions)
        }
        scope :removed, -> { includes(:circulation_status).where('circulation_statuses.name' => 'Removed') }
        has_many :checkouts
        has_many :reserves
        has_many :checked_items
        has_many :baskets, :through => :checked_items
        belongs_to :circulation_status, :validate => true
        belongs_to :checkout_type
        has_many :lending_policies, :dependent => :destroy
        has_one :item_has_use_restriction, :dependent => :destroy
        has_one :use_restriction, :through => :item_has_use_restriction
        validates_associated :circulation_status, :checkout_type
        validates_presence_of :circulation_status, :checkout_type
        searchable do
          string :circulation_status do
            circulation_status.name
          end
        end
        accepts_nested_attributes_for :item_has_use_restriction

        before_update :delete_lending_policy
      end
    end

    module InstanceMethods
      def set_circulation_status
        self.circulation_status = CirculationStatus.where(:name => 'In Process').first if self.circulation_status.nil?
      end

      def checkout_status(user)
        return nil unless user
         user.profile.user_group.user_group_has_checkout_types.where(:checkout_type_id => self.checkout_type.id).first
      end

      def reserved?
        return true if manifestation.next_reservation
        false
      end

      def rent?
        return true if self.checkouts.not_returned.select(:item_id).detect{|checkout| checkout.item_id == self.id}
        false
      end

      def reserved_by_user?(user)
        if manifestation.next_reservation
          return true if manifestation.next_reservation.user == user
        end
        false
      end

      def available_for_checkout?
        if circulation_status.name == 'On Loan'
          false
        else
          manifestation.items.for_checkout.include?(self)
        end
      end

      def checkout!(user)
        self.circulation_status = CirculationStatus.where(name: 'On Loan').first
        if reserved_by_user?(user)
          manifestation.next_reservation.update_attributes(checked_out_at: Time.zone.now)
          manifestation.next_reservation.transition_to!(:completed)
        end
        save!
      end

      def checkin!
        self.circulation_status = CirculationStatus.where(name: 'Available On Shelf').first
        save(validate: false)
      end

      def retain(librarian)
        self.class.transaction do
          reservation = manifestation.next_reservation
          unless reservation.nil?
            reservation.item = self
            reservation.transition_to!(:retained)
            reservation.send_message(librarian)
          end
        end
      end

      def retained?
        if manifestation.next_reservation.try(:current_state) == 'retained' and  manifestation.next_reservation.item == self
          return true
        else
          false
        end
      end

      def lending_rule(user)
        policy = lending_policies.where(user_group_id: user.profile.user_group.id).first
        if policy
          policy
        else
          create_lending_policy(user)
        end
      end

      def not_for_loan?
        !manifestation.items.for_checkout.include?(self)
      end

      def create_lending_policy(user)
        rule = user.profile.user_group.user_group_has_checkout_types.where(checkout_type_id: checkout_type_id).first
        return nil unless rule
        LendingPolicy.create!(
          item_id: id,
          user_group_id: rule.user_group_id,
          fixed_due_date: rule.fixed_due_date,
          loan_period: rule.checkout_period,
          renewal: rule.checkout_renewal_limit
        )
      end

      def delete_lending_policy
        return nil unless changes[:checkout_type_id]
        lending_policies.delete_all
      end

      def next_reservation
        Reserve.waiting.where(:item_id => id).first
      end

      def latest_checkout
        checkouts.order('checkouts.id').first
      end
    end
  end
end