class Family::Admissions::ApplicantsController < Family::Admissions::Controller
  def index
    data = applicants.where(student_id: nil).decorate.map { |a| entrance_applicant_props(a) }
    students.each { |s| data << student_props(s) }

    render_success :ok, json: data.sort_by { |i| i[:full_name] }
  end

  def show
    render_success :ok, json: applicant_props(applicant.decorate)
  end

  def create
    applicant = applicants.build(applicant_params)
    if applicant.save
      render_success :ok, json: { id: applicant.id }
    else
      render_error :unprocessable_entity, errors: applicant
    end
  end

  def update
    if applicant.update(applicant_params)
      render_success :ok
    else
      render_error :unprocessable_entity, errors: applicant
    end
  end

  def submit
    if applicant.submit
      render_success :ok, message: applicant.application.completion_message || ''
    else
      render_error :unprocessable_entity, errors: applicant
    end
  end

  private
    def school_year
      @school_year ||= current_school.admission_config.school_year
    end

    def applicants
      school_year.admission_applicants.where(family: current_family)
    end

    def applicant
      @applicant ||= applicants.find_by(id: params[:id])
    end

    def students
      current_family.primary_students.where(graduated: false)
    end

    def entrance_applicant_by_student
      @entrance_applicant_by_student ||= applicants.by_enrollment(false).index_by(&:student_id)
    end

    def enrollment_applicant_by_student
      @enrollment_applicant_by_student ||= applicants.by_enrollment(true).index_by(&:student_id)
    end

    def enrollment_applications_by_grades(returning)
      school_year.admission_applications
        .by_enrollment(true)
        .by_returning(returning)
        .map { |a| { application: a, grades: a.application_grades.by_available.pluck(:grade) } }
    end

    def application_by_returning
      @application_by_returning ||= {
        returning: enrollment_applications_by_grades(true),
        new: enrollment_applications_by_grades(false)
      }
    end

    def application_status(flag, grade, in_admissions)
      type = flag ? :returning : :new
      data = application_by_returning[type].find { |a| a[:grades].include?(grade) }
      return if data.nil? && type == :new && in_admissions

      data && data[:application].open? ? :open : :closed
    end

    def associations
      {}.tap do |props|
        props[:student] = students.find_by(id: params[:student_id]) if params.key?(:student_id)
      end
    end

    def applicant_params
      params.permit(
        :first_name,
        :last_name,
        :middle_name,
        :date_of_birth,
        :grade,
        :suffix,
        :nickname,
        :gender,
        :ethnicity,
        :email,
        :cell_phone,
        :work_phone,
        :returning,
        race: []
      ).merge(associations)
    end

    def entrance_applicant_props(applicant)
      {
        id: "applicant_#{applicant.id}",
        full_name: applicant.full_name(:reverse),
        entrance_applicant: applicant_props(applicant),
        enrollment_applicant: {}
      }
    end

    def student_props(student)
      entrance_applicant = entrance_applicant_by_student[student.id]&.decorate
      enrollment_applicant = enrollment_applicant_by_student[student.id]&.decorate
      returning = student.school_year_students.any?
      grade = if enrollment_applicant
        enrollment_applicant.grade
      elsif returning
        student.grade + 1
      else
        student.grade
      end

      enrollment_applicant = applicant_props(enrollment_applicant).merge({
        returning: returning,
        application_status: application_status(returning, grade, entrance_applicant.present?),
        grade_name: enrollment_applicant&.grade_level || grade_levels[grade]
      })

      {
        id: "student_#{student.id}",
        student_id: student.id,
        full_name: student.full_name(:reverse),
        entrance_applicant: applicant_props(entrance_applicant),
        enrollment_applicant: enrollment_applicant
      }
    end

    def applicant_props(applicant)
      {}.tap do |props|
        props[:id] = applicant&.id
        props[:state] = applicant&.state
        props[:grade_name] = applicant&.grade_level
        props[:download_url] = applicant&.submitted_application&.attachment&.blob&.service_url
        props[:completion_message] = applicant&.application&.completion_message
        return props unless action_name.to_sym == :show

        student = applicant.student
        props[:full_name] = applicant.full_name(:reverse)
        props[:first_name] = applicant.reviewed_prop(:first_name)
        props[:last_name] = applicant.reviewed_prop(:last_name)
        props[:middle_name] = applicant.reviewed_prop(:middle_name)
        props[:nickname] = applicant.review ? applicant.nickname : student.nickname&.first_name
        props[:date_of_birth] = applicant.reviewed_prop(:date_of_birth)
        props[:gender] = applicant.reviewed_prop(:gender)
        props[:student_id] = applicant.student_id
        props[:student_code] = student&.code
        props[:status_name] = applicant.status_name
        props[:application_type] = applicant.application_type.downcase
        props[:created_at] = applicant.created_at
        props[:submitted_at] = applicant.submitted_at
        props[:school_year_name] = applicant.school_year.name
        props[:review] = applicant.review
      end
    end
end
