class Checkout < ActiveRecord::Base
  scope :not_returned, -> { where(checkin_id: nil) }
  scope :returned, -> { where('checkin_id IS NOT NULL') }
  scope :overdue, lambda {|date| where('checkin_id IS NULL AND due_date < ?', date)}
  scope :due_date_on, lambda {|date| where(checkin_id: nil, due_date: date.beginning_of_day .. date.end_of_day)}
  scope :completed, lambda {|start_date, end_date| where('checkouts.created_at >= ? AND checkouts.created_at < ?', start_date, end_date)}
  scope :on, lambda {|date| where('created_at >= ? AND created_at < ?', date.beginning_of_day, date.tomorrow.beginning_of_day)}

  belongs_to :user
  delegate :username, :user_number, to: :user, prefix: true
  belongs_to :item, touch: true
  belongs_to :checkin
  belongs_to :librarian, class_name: 'User'
  belongs_to :basket
  belongs_to :shelf
  belongs_to :library

  validates_associated :user, :item, :librarian, :checkin #, :basket
  # TODO: 貸出履歴を保存しない場合は、ユーザ名を削除する
  #validates_presence_of :user, :item, :basket
  validates_presence_of :item_id, :basket_id, :due_date
  validates_uniqueness_of :item_id, scope: [:basket_id, :user_id]
  validate :is_not_checked?, on: :create
  validate :renewable?, on: :update
  validates_date :due_date
  before_update :set_new_due_date

  searchable do
    string :username do
      user.try(:username)
    end
    string :user_number do
      user.try(:profile).try(:user_number)
    end
    string :item_identifier do
      item.try(:item_identifier)
    end
    time :due_date
    time :created_at
    time :checked_in_at do
      checkin.try(:created_at)
    end
    boolean :reserved do
      reserved?
    end
  end

  attr_accessor :operator

  paginates_per 10

  def is_not_checked?
    checkout = Checkout.not_returned.where(item_id: item_id)
    unless checkout.empty?
      errors[:base] << I18n.t('activerecord.errors.messages.checkin.already_checked_out')
    end
  end

  def renewable?
    return nil if checkin
    messages = []
    if !operator and overdue?
      messages << I18n.t('checkout.you_have_overdue_item')
    end
    if !operator and reserved?
      messages << I18n.t('checkout.this_item_is_reserved')
    end
    if !operator and over_checkout_renewal_limit?
      messages << I18n.t('checkout.excessed_renewal_limit')
    end
    if messages.empty?
      true
    else
      messages.each do |message|
        errors[:base] << message
      end
      false
    end
  end

  def reserved?
    return true if item.try(:reserved?)
    false
  end

  def over_checkout_renewal_limit?
    return nil unless item.checkout_status(user)
    return true if item.checkout_status(user).checkout_renewal_limit < checkout_renewal_count
  end

  def overdue?
    return false unless due_date
    if Time.zone.now > due_date.tomorrow.beginning_of_day
      return true
    else
      return false
    end
  end

  def is_today_due_date?
    if Time.zone.now.beginning_of_day == due_date.beginning_of_day
      return true
    else
      return false
    end
  end

  def set_new_due_date
    self.due_date = due_date.try(:end_of_day)
  end

  def get_new_due_date
    return nil unless user
    if item
      if checkout_renewal_count <= item.checkout_status(user).checkout_renewal_limit
        new_due_date = Time.zone.now.advance(days: item.checkout_status(user).checkout_period).beginning_of_day
      else
        new_due_date = due_date
      end
    end
  end

  def self.manifestations_count(start_date, end_date, manifestation)
    self.where(
      self.arel_table[:created_at].gteq start_date
    ).where(
      self.arel_table[:created_at].lt end_date
    )
    .where(
      item_id: manifestation.items.pluck('items.id')
    ).count
  end

  def self.send_due_date_notification
    template = 'recall_item'
    queues = []
    User.find_each do |user|
      # 未来の日時を指定する
      checkouts = user.checkouts.due_date_on(user.profile.user_group.number_of_day_to_notify_due_date.days.from_now.beginning_of_day)
      unless checkouts.empty?
        queues << user.send_message(template, manifestations: checkouts.collect(&:item).collect(&:manifestation))
      end
    end
    queues.size
  end

  def self.send_overdue_notification
    template = 'recall_overdue_item'
    queues = []
    User.find_each do |user|
      user.profile.user_group.number_of_time_to_notify_overdue.times do |i|
        checkouts = user.checkouts.due_date_on((user.profile.user_group.number_of_day_to_notify_overdue * (i + 1)).days.ago.beginning_of_day)
        unless checkouts.empty?
          queues << user.profile.user.send_message(template, manifestations: checkouts.collect(&:item).collect(&:manifestation))
        end
      end
    end
    queues.size
  end

  def self.remove_all_history(user)
    user.checkouts.returned.update_all(user_id: nil)
  end
end

# == Schema Information
#
# Table name: checkouts
#
#  id                     :integer          not null, primary key
#  user_id                :integer
#  item_id                :integer          not null
#  checkin_id             :integer
#  librarian_id           :integer
#  basket_id              :integer
#  due_date               :datetime
#  checkout_renewal_count :integer          default(0), not null
#  lock_version           :integer          default(0), not null
#  created_at             :datetime
#  updated_at             :datetime
#  shelf_id               :integer
#  library_id             :integer
#