class SendPeriodicEmailsJob < Struct.new(:frequency)
  DEFAULT_PRIORITY=3

  def before(job)
    #make sure the SMTP configuration is in sync with current SEEK settings
    Seek::Config.smtp_propagate
  end

  def perform
    next_run_at = Time.new
    logs = []
    begin
      if frequency == 'daily'
        next_run_at += 1.day
        logs = activity_logs_since Time.now.yesterday.utc
      elsif frequency == 'weekly'
        next_run_at += 1.week
        logs = activity_logs_since 7.days.ago
      elsif frequency == 'monthly'
        next_run_at += 1.month
        logs = activity_logs_since 1.month.ago
      end
      send_subscription_mails logs, frequency
      #add job for next period
      SendPeriodicEmailsJob.create_job(frequency, next_run_at, 1, true)
    rescue Exception=>e
      #add job for next period
      SendPeriodicEmailsJob.create_job(frequency, next_run_at, 1,true)
    end
  end

  Subscription::FREQUENCIES.drop(1).each do |frequency|
    eval <<-END_EVAL
    def self.#{frequency}_exists?
      exists? '#{frequency}'
    end
    END_EVAL
  end

  def self.exists? frequency, ignore_locked=false
    if ignore_locked
      Delayed::Job.where(['handler = ? AND locked_at IS ? AND failed_at IS ?',SendPeriodicEmailsJob.new("#{frequency}").to_yaml,nil,nil]).first != nil
    else
      Delayed::Job.where(['handler = ? AND failed_at IS ?',SendPeriodicEmailsJob.new("#{frequency}").to_yaml,nil]).first != nil
    end

  end


  def self.create_job frequency,t, priority=DEFAULT_PRIORITY, ignore_locked=false
      Delayed::Job.enqueue(SendPeriodicEmailsJob.new(frequency),:priority=>priority,:run_at=>t) unless exists?(frequency,ignore_locked)
  end

  def send_subscription_mails logs, frequency
    if Seek::Config.email_enabled
      #strip the logs down to those that are relevant
      logs.reject! do |log|
        log.activity_loggable.nil? || !log.activity_loggable.subscribable?
      end

      #limit to only the people subscribed to the items logged, and those that are set to receive notifications
      people = people_subscribed_to_logged_items logs
      people.reject!{|person| !person.receive_notifications?}

      people.each do |person|
        begin
          #get only the logs for items that are visible to this person
          logs_for_visible_items = logs.select{|log| log.activity_loggable.try(:can_view?,person.user)}

          #get the logs for this persons subscribable items, where the subscription has the correct frequency
          activity_logs = logs_for_visible_items.select do |log|
            !person.subscriptions.for_subscribable(log.activity_loggable).select{ |s| s.frequency == frequency }.empty?
          end
          SubMailer.send_digest_subscription(person, activity_logs, frequency).deliver unless activity_logs.blank?
        rescue Exception => e
          Delayed::Job.logger.error("Error sending subscription emails to person #{person.id} - #{e.message}")
        end
      end
    end
  end

  #returns an enumaration of the people subscribed to the items in the logs
  def people_subscribed_to_logged_items logs
    items = logs.collect{|log| log.activity_loggable}.uniq
    items.collect do |item|
      subscriptions = Subscription.find_all_by_subscribable_type_and_subscribable_id(item.class.name,item.id)
      subscriptions.collect{|sub| sub.person}
    end.flatten.compact.uniq
  end

  def activity_logs_since time_point
    ActivityLog.where(['created_at>=? and action in (?) and controller_name!=?', time_point, ['create', 'update'], 'sessions'])
  end

  # puts the initial jobs on the queue for each period - daily, weekly, monthly - if they do not exist already
  # starting at midday
  def self.create_initial_jobs
    t=Time.now
    # start tomorrow if time now is later than midday
    t = t + 1.day if t > Time.local_time(t.year, t.month,t.day,12,00,00)
    SendPeriodicEmailsJob.create_job('daily', Time.local_time(t.year, t.month,t.day,12,00,00))   #at 12:00:00
    SendPeriodicEmailsJob.create_job('weekly', Time.local_time(t.year, t.month,t.day,12,05,00))  #at 12:05:00
    SendPeriodicEmailsJob.create_job('monthly', Time.local_time(t.year, t.month,t.day,12,10,00)) #at 12:10:00
  end
end
