class Admin::Admissions::Applicants::AdditionalValuesController < Admin::Admissions::Controller
  include Admin::Admissions::ApplicantScoped

  def index
    render_success :ok, json: groups.map { |group| group_props(group) }
  end

  def update
    objects = []
    params[:additional_values].each do |param|
      additional_value = find_or_build_additional_value(param[:field_id])
      additional_value.value = param[:value]
      objects << additional_value
    end

    if transactional_save(objects)
      render_success :ok, object: 'Additional values'
    else
      render_error :unprocessable_entity, errors: multi_errors(objects)
    end
  end

  private
    def fields
      current_school.student_additional_fields
        .by_admission
        .joins_application_fields(applicant.application_id, display?)
    end

    def group_fields
      @group_fields ||= fields.ordered.group_by(&:group_id)
    end

    def groups
      query = current_school.student_additional_groups
        .by_admissions(true)
        .with_admission_application_fields(applicant.application_id, display?)
        .ordered
        .distinct

      group_fields.key?(0) ? query.with_default_group : query
    end

    def additional_values
      @additional_values ||= applicant.additional_values.index_by(&:student_additional_field_id)
    end

    def find_or_build_additional_value(field_id)
      additional_values[field_id] ||
        applicant.additional_values.build(student_additional_field_id: field_id)
    end

    def student_values
      @student_values ||= applicant.student.student_additional_values
        .where(student_additional_field_id: fields.pluck(:id))
        .index_by(&:student_additional_field_id)
    end

    def display?
      params.key?(:display) ? params[:display].to_bool : true
    end

    def group_props(group)
      {}.tap do |prop|
        prop[:id] = group.id
        prop[:name] = group.name
        prop[:order] = group.order
        prop[:description] = group.description
        prop[:fields] = (group_fields[group.id] || []).map { |f| field_props(f) }
      end
    end

    def field_props(field)
      {}.tap do |props|
        props[:id] = field.id
        props[:name] = field.name
        props[:type] = field.type
        props[:description] = field.description
        props[:choices] = field.choices
        props[:value] = find_or_build_additional_value(field.id).value
        return props if applicant.student_id.nil?

        student_value = student_values[field.id]
        props[:student_value] = field.date? ? student_value&.value_date : student_value&.value
      end
    end
end
