class Audits::StudentService < ApplicationService
  def initialize(student_id, id=nil)
    @student = Student.find(student_id)
    @school = @student.school
    @id = id
  end

  def call
    if @id
      audit_props(audit)
    else
      audits.map { |a| audit_props(a) }
    end
  end

  private
    def audits
      @student.own_and_associated_audits.includes(:user)
    end

    def audit
      @audit ||= audits.find(@id)
    end

    def defaults(audit)
      {
        id: audit.id,
        action: audit.action,
        created_at: audit.created_at,
        user_name: audit.user&.full_name(:reverse)
      }
    end

    def audit_props(audit)
      defaults(audit).tap do |props|
        action = audit.action.to_sym

        case audit.auditable_type
        when 'Student'
          props[:types] = audit.audited_changes.keys
          return props unless @id

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        when 'StudentDetail'
          props[:types] = audit.audited_changes.keys
          return props unless @id

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        when 'RaceStudent'
          props[:types] = audit.audited_changes.keys
          return props unless @id

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        when 'StudentRequirement'
          props[:types] = audit.audited_changes.keys - ['id']
          return props unless @id

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        when 'AdditionalName'
          props[:types] = ["#{audit.revision.code}_name"]
          return props unless @id

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        when 'AdditionalId'
          props[:types] = ["#{audit.revision.code}_additional_id"]

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        end
      end
    end

    def changes(audit, current=true)
      return if audit.audited_changes.nil?

      index = current ? 0 : 1
      audit.audited_changes.map do |key, value|
        new_value = audit.action == 'update' ? value[index] : value

        case audit.auditable_type
        when 'Student'
          { "#{key}": new_value }
        when 'StudentDetail'
          case key.to_sym
          when :BirthCountryID
            { "#{key}": iso_country_hash[new_value] }
          when :BirthStateID
            { "#{key}": us_state_hash[new_value] }
          else
            { "#{key}": new_value }
          end
        when 'RaceStudent'
          next if key == 'id'

          { "#{key}": races_hash[new_value] }
        when 'StudentRequirement'
          next if key == 'id'

          { "#{key}": requirements_hash[new_value] }
        when 'AdditionalName'
          next unless [:first_name, :middle_name, :last_name, :suffix].include?(key.to_sym)

          { "#{key}": new_value }
        when 'AdditionalId'
          next unless key == 'number'

          { number: new_value }
        end
      end.compact
    end

    def iso_country_hash
      @iso_country_hash ||= IsoCountry.pluck(:id, :name).to_h
    end

    def us_state_hash
      @us_state_hash || UsState.pluck(:id, :name).to_h
    end

    def races_hash
      @races_hash ||= Race.pluck(:id, :name).to_h
    end

    def requirements_hash
      @requirements_hash ||= @school.requirement_labels.pluck(:id, :name).to_h
    end
end
