class EdFi::Indiana::Sandbox::GraduateService < EdFi::Indiana::Sandbox::ApplicationService
  def call
    students.map do |student|
      next unless valid_ed_fi_graduation_date?(student.graduation_date)

      props(student)
    end
  end

  def send_summer_graduate
    student = school.students
      .preload(:indiana_question_values, :state_number, :school_year_students)
      .joins(:school_year_students)
      .find_by(id: @params[:student_id])
      .decorate

    props(student, true)
  end

  def endpoint
    'ed-fi/studentacademicrecords'
  end

  def destroy_logs
    nil
  end

  private
    def students
      school_year.students
        .preload(:indiana_question_values, :state_number, :school_year_students)
        .joins(:school_year_students)
        .where('SchoolYearStudents.SYGrade >= 11')
        .where.not(SchoolYearStudents: { SYGrade: grades_mapped_ungraded }, graduated: false)
        .by_valid_graduation_date
        .distinct
        .decorate
    end

    def choices
      @choices ||= StudentAdditionalChoice
        .where(field_id: [3_527, 13_060, 13_061])
        .group_by(&:field_id)
    end

    def begin_and_end_days_by_semester
      @begin_and_end_days_by_semester ||= school_year.begin_and_end_days_by_semester
    end

    def terms
      @terms ||= if school.school_config.semesters?
        { 1 => 'Fall Semester', 2 => 'Spring Semester' }
      else
        { 1 => 'First Trimester', 2 => 'Second Trimester', 3 => 'Third Trimester' }
      end
    end

    def graduated_term(record)
      terms.keys.find_all do |term|
        start_date = begin_and_end_days_by_semester[term][:begin].date
        end_date = begin_and_end_days_by_semester[term][:end].date

        (start_date..end_date).cover?(record.entry_date) ||
        (start_date..end_date).cover?(record.exit_date) ||
        record.entry_date < start_date &&
          (record.exit_date.nil? || record.exit_date > end_date)
      end
    end

    def valid_ed_fi_graduation_date?(grad_date)
      (
        Date.new(school_year.academic_year - 1, 7, 1)..Date.new(school_year.academic_year, 6, 30)
      ).cover?(grad_date)
    end

    def props(student, summer_grad=false)
      values = student.indiana_question_values.index_by(&:field_id)
      term = if summer_grad
        'Fall Semester'
      else
        # This avoids n+1 unlike using it from the student model.

        record = student.school_year_students.select { |school_year_student| 
          school_year_student.school_year_id == school_year.id
        }
        .last
        terms[graduated_term(record).last]
      end
      data = {
        educationOrganizationReference: {
          educationOrganizationId: organization_id.number
        },
        schoolYearTypeReference: {
          schoolYear: school_year.academic_year
        },
        studentReference: {
          studentUniqueId: student.state_number&.number
        },
        termDescriptor: "uri://ed-fi.org/TermDescriptor##{term}",
        diplomas: [diploma_props(student.graduation_date, values[3_527]&.value)],
        recognitions: recognition_props(
          values[13_060]&.value,
          values[13_061]&.value,
          values[13_062]&.value
        )
      }

      rest_client_request(:post, url, student, body: data.to_json)
    end

    def recognition_props(employability, competency, pathway)
      data = []
      type_descriptor = 'uri://doe.in.gov/RecognitionTypeDescriptor#'
      category_descriptor = 'uri://doe.in.gov/AchievementCategoryDescriptor#'
      if employability.present?
        name = choices[13_060].find { |c| c.value == employability }.name.strip
        data << {
          recognitionTypeDescriptor: "#{type_descriptor}Employability Skills",
          achievementCategoryDescriptor: "#{category_descriptor}#{name}"
        }
      end

      if competency.present?
        name = choices[13_061].find { |c| c.value == competency }.name.strip
        obj = {
          recognitionTypeDescriptor: "#{type_descriptor}Post-Secondary Competencies",
          achievementCategoryDescriptor: "#{category_descriptor}#{name}"
        }
        obj[:achievementCategorySystem] = pathway if name.include?('Local')
        data << obj
      end

      data
    end

    def diploma_props(graduation_date, level_type)
      level_type_descriptor = case level_type
      when '07', '06' # certificate of completion or course completion
        'Certificate of completion'
      else
        'Regular diploma'
      end
      type_desciptor = "uri://ed-fi.org/DiplomaTypeDescriptor##{level_type_descriptor}"
      level_descriptor = "uri://doe.in.gov/DiplomaLevelDescriptor##{level_type}"
      {}.tap do |data|
        data[:diplomaTypeDescriptor] = type_desciptor
        data[:diplomaAwardDate] = graduation_date
        data[:diplomaLevelDescriptor] = level_descriptor
      end
    end
end
