class Classroom < ApplicationRecord
  include Base::Classroom

  enum type: { preschool: -1, day_long: 1, period_long: 2, general: 3, sports_team: 4 }
  enum grade_model: { numeric: 1, standards: 2 }

  associations_for legacy: true do |a|
    a.belongs_to :school
    a.belongs_to :primary_teacher, foreign_key: 'PrimaryStaffID', inverse_of: :classrooms,
      primary_key: :UserID, class_name: 'Employee', optional: true
    a.belongs_to :room, keys: 'FacilityID', class_name: 'Facility::Room',
      inverse_of: :classrooms, optional: true
    a.belongs_to :location, keys: 'LocationID', class_name: 'Facility::Location',
      inverse_of: :classrooms, optional: true
    a.belongs_to :department, keys: :DepartmentID, class_name: '::Department',
      inverse_of: :classrooms, optional: true

    a.has_many :attendances, keys: 'ClassID'
    a.has_many :class_assignments, keys: :ClassID
    a.has_many :class_assignment_groups, keys: :ClassID
    a.has_many :class_grades, keys: :ClassID
    a.has_many :class_grade_postings, keys: :ClassID
    a.has_many :class_grade_summaries, keys: :ClassID
    a.has_many :class_grade_categories, keys: :ClassID
    a.has_many :class_lesson_plans, keys: :ClassID
    a.has_many :class_seatings, keys: :ClassID
    a.has_many :class_subjects, keys: :ClassID
    a.has_many :class_student_enrollments, keys: :ClassID
    a.has_many :class_students, keys: :ClassID
    a.has_many :class_teachers, keys: :ClassID
    a.has_many :class_periods, keys: :ClassID
    a.has_many :documents, keys: :ClassID
    a.has_many :document_folders, keys: :ClassID
    a.has_many :news_articles, keys: :ClassID
    a.has_many :student_lunch_orders, keys: :ClassID
    a.has_many :student_milk_orders, keys: :ClassID
    a.has_many :events, keys: :ClassID
    a.has_many :student_transcripts, keys: :ClassID

    a.has_one :class_enrollment, keys: :ClassID
    a.has_one :period, keys: :PeriodID, inverse_of: :classrooms
    a.has_one :school_state_classroom, keys: :ClassID
  end

  has_many :employees, through: :class_teachers
  has_many :students, through: :class_students
  has_many :periods, through: :class_periods

  has_and_belongs_to_many :course, join_table: :course_classrooms

  associations_for namespace: 'EdFi' do |a|
    a.has_many :ids, as: :associated, inverse_of: :associated, dependent: :destroy
    a.has_many :logs, as: :associated, inverse_of: :associated
  end

  associations_for namespace: 'TimeCard' do |a|
    a.has_many :entries, class_name: '::TimeCard::Entry', dependent: :nullify
  end

  delegate :school_config, to: :school
  delegate :school_year_type, to: :school_config

  scope :ordered, -> { order(:name) }
  scope :with_viewable_grades, -> { where(viewable_grades: true) }
  scope :by_parent_viewable, ->(flag) { where(parent_viewable: flag) unless flag.nil? }
  scope :by_session_term, ->(term) { where(s1: term).or(where(s1: -1)).or(day_long) if term }
  scope :by_homeroom, ->(homeroom) { where(homeroom: homeroom) if homeroom }
  scope :by_type, ->(type) { where(type: type) if type }
  scope :by_department, ->(department) { where(department_id: department) if department }
  scope :by_id, ->(ids) { where(id: ids) if ids }

  scope :by_student, ->(student) do
    return unless student

    joins(:students).where(ClassStudents: { StudentID: student })
  end

  scope :by_user, ->(user) do
    return unless user

    joins(:employees).where(ClassTeachers: { UserID: user })
  end

  scope :not_attached_to_a_course, ->(flag) do
    return unless flag

    left_joins(:course).where(courses: { id: nil })
  end

  scope :with_active_courses, -> { joins(:course).where(courses: { archived: false }) }

  scope :by_quarter, ->(school, quarter) do
    return unless quarter
    return by_session_term(quarter) if school.school_config.sessions?

    query = where("Classes.Q#{quarter} = 1")
    return query unless school.school_config.semesters?

    semester = quarter.to_i > 2 ? 2 : 1
    if semester == 1
      query.or(where("Classes.Q1 = 0 AND Classes.Q2 = 0 AND Classes.S#{semester} = 1"))
    else
      query.or(where("Classes.Q3 = 0 AND Classes.Q4 = 0 AND Classes.S#{semester} = 1"))
    end
  end

  scope :by_semester, ->(school, semester) do
    return unless semester

    if semester.to_s == 'full_year'
      by_full_year(school)
    elsif school.school_config.sessions?
      by_session_term(semester)
    else
      where("s#{semester}": true)
    end
  end

  scope :by_semesters, ->(school, semesters) do
    return unless semesters

    query = self
    semesters.each_with_index do |semester, index|
      query = if index.zero?
        query.by_semester(school, semester)
      else
        query.or(by_semester(school, semester))
      end
    end

    query
  end

  scope :by_full_year, ->(school) do
    query = self
    school.school_config.semesters.each_key { |s| query = query.where("s#{s}": true) }
    query
  end

  scope :by_parent_viewable_or_viewable_grades, -> do
    query = left_joins(:class_grade_postings)
    query.where(parent_viewable: true)
      .or(query.where.not({ ClassGradePostings: { GradeID: nil } })
        .where(viewable_grades: true))
  end

  def ceds_grade
    case grade
    when -9, -8
      'IT'
    when -7, -6, -5, -1
      'PR'
    when -4, -3, -2
      'PK'
    when 0
      'KG'
    when 14, 15, 16
      'PS'
    when 99
      nil
    else
      sprintf('%02d', grade)
    end
  end

  def semester
    case school_year_type.to_sym
    when :semesters
      return :full_year if s1? && s2?

      s1? ? 1 : 2
    when :trimesters
      return :full_year if s1? && s2? && s3?
      return 1 if s1?
      return 2 if s2?

      3
    when :semester
      1
    when :sessions
      s1 == -1 ? :full_year : s1

    end
  end
end
