class RecipientSchedule < ApplicationRecord

  belongs_to :recipient
  belongs_to :schedule
  has_many :attempts

  validates_associated :recipient
  validates_associated :schedule
  validates :next_attempt_at, presence: true

  scope :ready, -> { where('next_attempt_at <= ?', Time.new) }
  scope :for_recipient, -> (recipient_or_recipient_id) {
    id = recipient_or_recipient_id.is_a?(Recipient) ?
      recipient_or_recipient_id.id :
      recipient_or_recipient_id
    where(recipient_id: id)
  }
  scope :for_schedule, -> (schedule_or_schedule_id) {
    id = schedule_or_schedule_id.is_a?(Schedule) ?
      schedule_or_schedule_id.id :
      schedule_or_schedule_id
    where(schedule_id: id)
  }

  def next_question
    if queued_question_ids.present?
      next_question_id = queued_question_ids.split(/,/).first
    else
      next_question_id = upcoming_question_ids.split(/,/).first
    end
    Question.where(id: next_question_id).first
  end

  def upcoming_question_id_array
    upcoming_question_ids.try(:split, /,/) || []
  end

  def attempted_question_id_array
    attempted_question_ids.try(:split, /,/) || []
  end

  def queued_question_id_array
    queued_question_ids.try(:split, /,/) || []
  end

  def attempt_question_for_recipient_students(send_message: true, question: next_question)
    return if recipient.opted_out?
    return if question.nil?

    if !question.for_recipient_students?
      return attempt_question(question: question)
    end

    missing_students = []
    recipient_attempts = attempts.for_recipient(recipient).for_question(question)
    recipient.students.each do |student|
      if recipient_attempts.for_student(student).empty?
        missing_students << student
      end
    end

    attempt = recipient.attempts.create(
      schedule: schedule,
      recipient_schedule: self,
      question: question,
      student: missing_students.first
    )

    if send_message && attempt.send_message
      upcoming = upcoming_question_id_array
      queued = queued_question_id_array
      attempted = attempted_question_id_array

      if question.present?
        question_id = [question.id.to_s]
        upcoming = upcoming - question_id
        if missing_students.length > 1
          queued += question_id
        else
          attempted += question_id
          queued -= question_id
        end
      end

      update(
        upcoming_question_ids: upcoming.empty? ? nil : upcoming.join(','),
        attempted_question_ids: attempted.empty? ? nil : attempted.join(','),
        queued_question_ids: queued.empty? ? nil : queued.join(','),
        last_attempt_at: attempt.sent_at,
        next_attempt_at: next_valid_attempt_time
      )
    end
    return attempt
  end

  def attempt_question(send_message: true, question: next_question)
    return if recipient.opted_out?
    unanswered_attempt = recipient.attempts.not_yet_responded.last

    return if question.nil? && unanswered_attempt.nil?

    if unanswered_attempt.nil?
      if question.for_recipient_students?
        return attempt_question_for_recipient_students(question: question)
      end

      attempt = recipient.attempts.create(
        schedule: schedule,
        recipient_schedule: self,
        question: question
      )
    end

    if send_message && (unanswered_attempt || attempt).send_message
      upcoming = upcoming_question_id_array
      queued = queued_question_id_array
      attempted = attempted_question_id_array

      if question.present?
        question_id = [question.id.to_s]
        upcoming = upcoming - question_id
        if unanswered_attempt.nil?
          attempted += question_id
          queued -= question_id
        else
          queued += question_id
        end
      end

      update(
        upcoming_question_ids: upcoming.empty? ? nil : upcoming.join(','),
        attempted_question_ids: attempted.empty? ? nil : attempted.join(','),
        queued_question_ids: queued.empty? ? nil : queued.join(','),
        last_attempt_at: (unanswered_attempt || attempt).sent_at,
        next_attempt_at: next_valid_attempt_time
      )
    end
    return (unanswered_attempt || attempt)
  end

  def next_valid_attempt_time
    local_time = (next_attempt_at + (60 * 60 * schedule.frequency_hours)).in_time_zone('Eastern Time (US & Canada)')
    local_time += 1.day while local_time.on_weekend?
    return local_time
  end

  def self.create_for_recipient(recipient_or_recipient_id, schedule, next_attempt_at=nil)
    if next_attempt_at.nil?
      next_attempt_at = Time.at(schedule.start_date.to_time.to_i + (60 * schedule.time))
      next_attempt_at += 1.day while next_attempt_at.on_weekend?
    end

    question_ids = schedule.question_list.question_ids.split(/,/)
    question_ids = question_ids.shuffle if schedule.random?

    recipient_id = recipient_or_recipient_id.is_a?(Recipient) ?
      recipient_or_recipient_id.id :
      recipient_or_recipient_id

    schedule.recipient_schedules.create(
      recipient_id: recipient_id,
      upcoming_question_ids: question_ids.join(','),
      next_attempt_at: next_attempt_at
    )
  end


end
