class StudentTranscript < ApplicationRecord
  include Base::StudentTranscript

  belongs_to :school, foreign_key: :SchoolID, inverse_of: :student_transcripts
  belongs_to :classroom, foreign_key: :ClassID, inverse_of: :student_transcripts
  belongs_to :class_subject, foreign_key: :SubjectID, inverse_of: :student_transcripts
  belongs_to :college, foreign_key: :CollegeCredit, inverse_of: :student_transcripts
  belongs_to :school_year, inverse_of: :student_transcripts
  belongs_to :student, foreign_key: :StudentID, inverse_of: :student_transcripts

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

  scope :by_classes, ->(ids) { where(class_id: ids) if ids }
  scope :by_subjects, ->(ids) { where(subject_id: ids) if ids }
  scope :by_school_year, ->(id) { where(school_year_id: id) }

  scope :most_recent, ->(field, school_id, school_year_id) do
    return unless [:semester, :quarter].include?(field)

    from(
      <<~SQL
        (
          SELECT StudentTranscripts.*
          FROM StudentTranscripts JOIN (
             SELECT SchoolYearID, StudentID, SubjectID, MAX(#{field.capitalize}) recent_term
             FROM StudentTranscripts
             WHERE SchoolID = #{school_id}
             AND SchoolYearID = #{school_year_id}
             GROUP BY SchoolYearID, StudentID, SubjectID
          ) recent_transcript
          ON StudentTranscripts.SchoolYearID = recent_transcript.SchoolYearID
          AND StudentTranscripts.StudentID = recent_transcript.StudentID
          AND StudentTranscripts.SubjectID = recent_transcript.SubjectID
          AND StudentTranscripts.#{field.capitalize} = recent_transcript.recent_term
        ) StudentTranscripts
      SQL
    )
  end

  def calculate_points(gpa_scale=nil, transcript_config=nil)
    weighted = (grade >= 9 && (transcript_config || school.transcript_config)&.weighted?)

    point_value = if imported != 2 && points.zero?
      scale_hash = (gpa_scale || school.school_gpa_scales).select do |scale|
        if !weighted
          scale.honors.zero?
        elsif honor?
          scale.honors == 1
        elsif college_scale?
          scale.honors == 2
        else
          scale.honors == gpa_scale_id
        end
      end.map { |s| [s.grade, s.value] }.to_h
      scale_hash[letter_grade.upcase] || 0
    else
      points
    end

    point_value * weight
  end
end
