class Admin::Admissions::ApplicantsController < Admin::Admissions::Controller
  def index
    objects = school_year.admission_applicants
      .preload(:family, :status, :tags, :application)
      .by_enrollment(params[:enrollment]&.to_bool)
      .with_application(params[:application_id])
      .with_grade(params[:grades])
      .with_system_status(params[:status])
      .with_returning(params[:student_type])
      .by_review(params[:review]&.to_bool)
      .with_tags(params[:tag_ids])
      .decorate
    render_success :ok, json: objects.map { |o| applicant_props(o) }
  end

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

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

  def destroy
    if applicant.destroy
      render_success :ok
    else
      render_error :unprocessable_entity, errors: applicant
    end
  end

  def batch_update
    data = applicants.where(id: params[:ids]).each { |a| a.assign_attributes(applicant_params) }
    if transactional_save(data)
      render_success :ok, message: 'Applicant updated.'
    else
      render_error :unprocessable_entity
    end
  end

  def submit
    if applicant.submit
      render_success :ok, event: :submitted, json: applicant_props(applicant.reload.decorate)
    else
      render_error :unprocessable_entity, errors: applicant
    end
  end

  def approve
    if Admission::Applicants::ProcessingService.new(applicant.id)
      render_success(
        :ok,
        message: 'Applicant has been approved.',
        json: applicant_props(applicant.reload.decorate)
      )
    else
      render_error :unprocessable_entity
    end
  end

  def state
    data = applicants.where(id: params[:ids]).each { |a| a.state = params[:state] }
    if transactional_save(data)
      render_success :ok, message: 'Applicants updated.'
    else
      render_error :unprocessable_entity
    end
  end

  def batch_enroll
    params[:ids].each { |i| Admissions::EnrollJob.perform_async(current_school.id, i) }
    render_success :ok
  end

  def export
    Reporting::Admissions::ApplicantJob.perform_async(
      current_school.id,
      current_user.id,
      csv_type: params[:csv_type],
      school_year_id: params[:school_year_id],
      application_id: params[:application_id],
      grades: params[:grades],
      status: params[:status],
      student_type: params[:student_type],
      review: params[:review]&.to_bool,
      enrollment: params[:enrollment].to_bool,
      tags: params[:tag_ids]
    )
  end

  def agreements_pdf
    applicant_ids = applicants
      .joins(:application_agreements)
      .where(id: params[:ids])
      .distinct
      .pluck(:id)

    if applicant_ids.present?
      Reporting::Admissions::ApplicantAgreementJob.perform_async(
        current_school.id,
        current_user.id,
        ids: applicant_ids
      )
      render_success :ok
    else
      render_error :unprocessable_entity
    end
  end

  def download_application
    Reporting::Admissions::ApplicantApplicationJob.perform_async(
      current_school.id,
      current_user.id,
      ids: params[:ids],
      preapplicant: params[:preapplicant]&.to_bool
    )
    render_success :ok
  end

  def batch_approve
    Admissions::BatchApproveApplicantJob.perform_async(params[:ids])
    render_success :ok
  end

  def essays_pdf
    applicant_ids = applicants
      .joins(:application_essays)
      .where(id: params[:ids])
      .distinct
      .pluck(:id)

    if applicant_ids.present?
      Reporting::Admissions::ApplicantEssayJob.perform_async(
        current_school.id,
        current_user.id,
        ids: applicant_ids
      )
      render_success :ok
    else
      render_error :unprocessable_entity
    end
  end

  def applicant_list
    Reporting::Admissions::ApplicantListJob.perform_async(
      current_school.id,
      current_user.id,
      school_year_id: params[:school_year_id],
      state: params[:state],
      enrollment: params[:enrollment]&.to_bool,
      tag_ids: params[:tag_ids],
      review: params[:review]&.to_bool,
      grades: params[:grades],
      application_ids: params[:application_id],
      student_type: params[:student_type]
    )
  end

  def payment_export
    Reporting::Admissions::ApplicantPaymentJob.perform_async(
      current_school.id,
      current_user.id,
      school_year_id: params[:school_year_id],
      payment_status: params[:payment_status],
      application_id: params[:application_id],
      grades: params[:grades],
      status: params[:status],
      student_type: params[:student_type],
      review: params[:review]&.to_bool,
      enrollment: params[:enrollment].to_bool,
      tag_ids: params[:tag_ids]
    )
  end

  private
    def permissions
      perms = [:index, :show, :agreements_pdf, :essays_pdf, :download_application, :export]
      if perms.include?(action_name.to_sym)
        ['read', 'write', 'manage']
      else
        ['write', 'manage']
      end
    end

    def applicants
      current_school.admission_applicants
    end

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

    def profile_fields
      @profile_fields ||= Admission::ProfileField.fields.keys - ['race']
    end

    def school_year
      @school_year ||= current_school.school_years.find(params[:school_year_id])
    end

    def application
      @application ||= current_school.admission_applications.find_by(id: params[:application_id])
    end

    def associations
      {}.tap do |props|
        props[:application] = application if application
      end
    end

    def applicant_params
      properties = profile_fields + [
        :first_name,
        :last_name,
        :date_of_birth,
        :status_id,
        :grade,
        :notes,
        :payment_status
      ]
      params.permit(properties, race: []).merge(associations)
    end

    def applicant_props(applicant)
      {}.tap do |prop|
        student = applicant.student
        prop[:id] = applicant.id
        prop[:full_name] = applicant.reviewed_prop(:full_name, :reverse)
        prop[:first_name] = applicant.reviewed_prop(:first_name)
        prop[:last_name] = applicant.reviewed_prop(:last_name)
        prop[:family] = applicant.family.name
        prop[:grade] = applicant.grade
        prop[:grade_name] = applicant.grade_level
        prop[:state] = applicant.state.capitalize
        prop[:status] = applicant.status_id || applicant.state
        prop[:status_name] = applicant.status&.name
        prop[:application_id] = applicant.application_id
        prop[:application_year_id] = applicant.application.school_year_id
        prop[:review] = applicant.review
        prop[:system_status] = applicant.system_status
        prop[:returning] = applicant.returning
        prop[:notes] = applicant.notes
        prop[:created_at] = applicant.created_at
        prop[:submitted_at] = applicant.submitted_at
        prop[:tags] = applicant.tags.sort_by(&:name)
        prop[:application_type] = applicant.application_type
        prop[:tag_ids] = applicant.tag_ids
        prop[:student_id] = applicant.student_id
        prop[:enrollment] = applicant.application.enrollment
        prop[:application_name] = applicant.application.name
        return prop if action_name.to_sym == :index

        if applicant.application.payment
          prop[:payment_description] = applicant.payment_description
          prop[:payment_amount] = applicant.payment_amount
          prop[:paid_at] = applicant.paid_at
          prop[:payment_status] = applicant.payment_status || :not_paid
        end
        prop[:date_of_birth] = applicant.reviewed_prop(:date_of_birth)
        prop[:gender] = applicant.reviewed_prop(:gender)
        prop[:gender_label] = applicant.reviewed_prop(:gender_label)
        prop[:ethnicity] = applicant.reviewed_prop(:ethnicity)
        prop[:email] = applicant.reviewed_prop(:email)
        prop[:cell_phone] = applicant.reviewed_prop(:cell_phone)
        prop[:work_phone] = applicant.reviewed_prop(:work_phone)
        prop[:middle_name] = applicant.reviewed_prop(:middle_name)
        prop[:suffix] = applicant.reviewed_prop(:suffix)
        prop[:race] = applicant.reviewed_prop(:race_ids)
        prop[:nickname] = applicant.review ? applicant.nickname : student.nickname&.first_name
        prop[:family_id] = applicant.family_id
        prop[:school_year] = applicant.application.school_year.name
        if student
          prop[:student_code] = student.code
          prop[:current_grade] = student.grade
          prop[:current_grade_name] = student.decorate.grade_level
        end
      end
    end
end
