class StateReporting::Config < ApplicationRecord
  enum syncing: { all_students: 2 }

  attr_accessor :skip_calendar_validation

  belongs_to :school_year
  belongs_to :calendar_descriptor, class_name: 'EdFi::Descriptor', optional: true

  associations_for namespace: 'EdFi' do |a|
    a.has_many :logs, as: :associated, inverse_of: :associated

    a.has_one :id, as: :associated, inverse_of: :associated, dependent: :destroy
  end

  delegate :school, to: :school_year
  delegate :current?, to: :school_year

  validates :calendar_descriptor, presence: true,
    on: :update, unless: :skip_calendar_validation

  def job_statuses
    calendar_time = job_status(:calendar_job)['update_time']
    master_schedule_time = job_status(:master_schedule_job)['update_time']
    students_time = job_status(:students_job)['update_time']
    attendance_time = job_status(:attendance_job)['update_time']
    staff_time = job_status(:staff_job)['update_time']
    student_membership_time = job_status(:student_membership_job)['update_time']
    parents_time = job_status(:parents_job)['update_time']
    student_programs_time = job_status(:student_programs_job)['update_time']
    course_offering_time = job_status(:course_offering_job)['update_time']
    preschool_transcripts_time = job_status(:preschool_transcripts_job)['update_time']
    primary_transcripts_time = job_status(:primary_transcripts_job)['update_time']
    middle_transcripts_time = job_status(:middle_transcripts_job)['update_time']
    secondary_transcripts_time = job_status(:secondary_transcripts_job)['update_time']
    course_section_rosters_time = job_status(:course_section_rosters_job)['update_time']
    student_accommodations_time = job_status(:student_accommodations_job)['update_time']
    student_graduation_plans_time = job_status(:student_graduation_plans_job)['update_time']

    {}.tap do |props|
      props[:calendar_job] = job_status(:calendar_job)['status']
      props[:calendar_retrying] = job_retrying(:calendar_job).present?
      if calendar_time
        props[:calendar_job_time] = Time.zone.at(calendar_time.to_i)&.to_datetime
      end
      props[:master_schedule_job] = job_status(:master_schedule_job)['status']
      props[:master_schedule_retrying] = job_retrying(:master_schedule_job).present?
      if master_schedule_time
        props[:master_schedule_job_time] = Time.zone.at(master_schedule_time.to_i)&.to_datetime
      end
      props[:students_job] = job_status(:students_job)['status']
      props[:students_retrying] = job_retrying(:students_job).present?
      props[:students_job_time] = Time.zone.at(students_time.to_i)&.to_datetime if students_time
      props[:attendance_job] = job_status(:attendance_job)['status']
      props[:attendance_retrying] = job_retrying(:students_job).present?
      if attendance_time
        props[:attendance_job_time] = Time.zone.at(attendance_time.to_i)&.to_datetime
      end
      props[:staff_job] = job_status(:staff_job)['status']
      props[:staff_retrying] = job_retrying(:staff_job).present?
      props[:staff_job_time] = Time.zone.at(staff_time.to_i)&.to_datetime if staff_time
      props[:parents_job] = job_status(:parents_job)['status']
      props[:parents_retrying] = job_retrying(:parents_job).present?
      props[:parents_job_time] = Time.zone.at(parents_time.to_i)&.to_datetime if parents_time
      props[:student_membership_job] = job_status(:student_membership_job)['status']
      props[:student_membership_retrying] = job_retrying(:student_membership_job).present?
      if student_membership_time
        props[:student_membership_job_time] =
          Time.zone.at(student_membership_time.to_i)&.to_datetime
      end
      props[:student_programs_job] = job_status(:student_programs_job)['status']
      props[:student_programs_retrying] = job_retrying(:student_programs_job).present?
      if student_programs_time
        props[:student_programs_job_time] = Time.zone.at(student_programs_time.to_i)&.to_datetime
      end
      props[:course_offering_job] = job_status(:course_offering_job)['status']
      props[:course_offering_retrying] = job_retrying(:course_offering_job).present?
      if course_offering_time
        props[:course_offering_job_time] = Time.zone.at(course_offering_time.to_i)&.to_datetime
      end
      props[:preschool_transcripts_job] = job_status(:preschool_transcripts_job)['status']
      props[:preschool_transcripts_retrying] = job_retrying(:preschool_transcripts_job).present?
      if preschool_transcripts_time
        props[:preschool_transcripts_job_time] =
          Time.zone.at(preschool_transcripts_time.to_i)&.to_datetime
      end
      props[:primary_transcripts_job] = job_status(:primary_transcripts_job)['status']
      props[:primary_transcripts_retrying] = job_retrying(:primary_transcripts_job).present?
      if primary_transcripts_time
        props[:primary_transcripts_job_time] =
          Time.zone.at(primary_transcripts_time.to_i)&.to_datetime
      end
      props[:middle_transcripts_job] = job_status(:middle_transcripts_job)['status']
      props[:middle_transcripts_retrying] = job_retrying(:middle_transcripts_job).present?
      if middle_transcripts_time
        props[:middle_transcripts_job_time] =
          Time.zone.at(middle_transcripts_time.to_i)&.to_datetime
      end
      props[:secondary_transcripts_job] = job_status(:secondary_transcripts_job)['status']
      props[:secondary_transcripts_retrying] = job_retrying(:secondary_transcripts_job).present?
      if secondary_transcripts_time
        props[:secondary_transcripts_job_time] =
          Time.zone.at(secondary_transcripts_time.to_i)&.to_datetime
      end
      props[:course_section_rosters_job] = job_status(:course_section_rosters_job)['status']
      props[:course_section_rosters_retrying] = job_retrying(:course_section_rosters_job).present?
      if course_section_rosters_time
        props[:course_section_rosters_job_time] =
          Time.zone.at(course_section_rosters_time.to_i)&.to_datetime
      end
      props[:student_accommodations_job] = job_status(:student_accommodations_job)['status']
      props[:student_accommodations_retrying] = job_retrying(:student_accommodations_job).present?
      if student_accommodations_time
        props[:student_accommodations_job_time] =
          Time.zone.at(student_accommodations_time.to_i)&.to_datetime
      end
      props[:student_graduation_plans_job] = job_status(:student_graduation_plans_job)['status']
      props[:student_graduation_plans_retrying] = job_retrying(:student_graduation_plans_job).present?
      if student_graduation_plans_time
        props[:student_graduation_plans_job_time] =
          Time.zone.at(student_graduation_plans_time.to_i)&.to_datetime
      end
    end
  end

  def broadcast_job_statuses
    ActionCable.server.broadcast(
      "components_admin_state_reporting_sync_channel_#{school.id}",
      job_statuses
    )
  end

  def sync_calendars
    status = job_status(:calendar_job)['status']&.to_sym
    retrying = job_retrying(:calendar_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::CalendarJob.perform_async(school_year_id)
    update(calendar_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_students
    status = job_status(:students_job)['status']&.to_sym
    retrying = job_retrying(:students_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::StudentsJob.perform_async(school_year_id)
    update(students_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_master_schedule
    status = job_status(:master_schedule_job)['status']&.to_sym
    retrying = job_retrying(:master_schedule_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::GradingPeriodsJob.perform_async(school_year_id)
    update(master_schedule_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_attendance
    status = job_status(:attendance_job)['status']&.to_sym
    retrying = job_retrying(:attendance_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::AttendanceJob.perform_async(school_year_id)
    update(attendance_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_staff
    status = job_status(:staff_job)['status']&.to_sym
    retrying = job_retrying(:staff_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::StaffJob.perform_async(school_year_id)
    update(staff_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_student_education
    status = job_status(:student_membership_job)['status']&.to_sym
    retrying = job_retrying(:student_membership_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::StudentEducationResponsibilityJob.perform_async(school_year_id)
    update(student_membership_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_parents
    status = job_status(:parents_job)['status']&.to_sym
    retrying = job_retrying(:parents_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::ParentsJob.perform_async(school_year_id)
    update(parents_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_student_programs
    status = job_status(:student_programs_job)['status']&.to_sym
    retrying = job_retrying(:student_programs_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::StudentProgramsJob.perform_async(school_year_id)
    update(student_programs_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_course_offerings
    status = job_status(:course_offering_job)['status']&.to_sym
    retrying = job_retrying(:course_offering_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::CourseOfferingJob.perform_async(school_year_id)
    update(course_offering_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_student_transcripts(grade)
    job = :"#{grade}_transcripts_job"
    status = job_status(job)['status']&.to_sym
    retrying = job_retrying(job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::StudentTranscriptJob.perform_async(school_year_id, grade: grade)
    update(job.to_s => job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_course_section_rosters
    status = job_status(:course_section_rosters_job)['status']&.to_sym
    retrying = job_retrying(:course_section_rosters_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::CourseSectionRosterJob.perform_async(school_year_id)
    update(course_section_rosters_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_student_accommodations
    status = job_status(:student_accommodations_job)['status']&.to_sym
    retrying = job_retrying(:student_accommodations_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::StudentAccommodationJob.perform_async(school_year_id)
    update(student_accommodations_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  def sync_student_graduation_plans
    status = job_status(:student_graduation_plans_job)['status']&.to_sym
    retrying = job_retrying(:student_graduation_plans_job).present?
    return unless status == :complete || status.nil? || status == :retrying && !retrying

    job_id = EdFi::Indiana::StudentGraduationPlanJob.perform_async(school_year_id)
    update(student_graduation_plans_job: job_id, skip_calendar_validation: true)
    broadcast_job_statuses
  end

  private
    def job_status(job)
      Sidekiq::Status.get_all(public_send(job))
    end

    def job_retrying(job)
      Sidekiq::RetrySet.new.find_job(public_send(job))
    end
end
