class Audits::EmployeeService < ApplicationService
  def initialize(employee_id, id=nil)
    @employee = Employee.find(employee_id)
    @id = id
  end

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

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

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

    def defaults(audit)
      {
        id: audit.id,
        action: audit.decorate.action_title,
        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 'Address'
          props[:type] = "#{audit.revision.code.titleize} Address"
          return props unless @id

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        when 'User'
          props[:type] = audit.audited_changes.keys.map(&:titleize).join(', ')
          return props unless @id

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

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        when 'AdditionalId'
          props[:type] = EmployeeAdditionalId::CODE_DISPLAY[audit.revision.code.to_sym]
          return props unless @id

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        when 'EmployeeNote'
          props[:type] = 'Note'
          return props unless @id

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        when 'EmployeeDetail'
          props[:type] = 'Status'
          return props unless @id

          props[:previous_state] = changes(audit) unless action == :create
          props[:current_state] = changes(audit, false) unless action == :destroy
        when 'Substitute'
          props[:action] = 'Updated'
          props[:type] = 'Substitute'
          return props unless @id

          unless action == :create
            props[:previous_state] = "Substitute: #{audit.action == 'created' ? 'True' : 'False'}"
          end
          unless action == :destroy
            props[:current_state] = "Substitute: #{audit.action == 'created' ? 'False' : 'True'}"
          end
        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 'Address'
          next if associated?(key)
          next if key == 'type'

          if key == 'code'
            "Address Type: #{EmployeeAddress.codes.key(new_value).titleize} Address"
          else
            "#{key.titleize}: #{new_value}"
          end
        when 'User'
          case key.to_sym
          when :Active
            "#{key.titleize}: #{new_value.to_s.titleize}"
          when :DOB
            "Date of Birth: #{new_value&.strftime('%m/%d/%Y')}"
          when :TitleID
            "Title: #{Title.find_by(id: new_value)&.name}"
          when :ManagerID
            "#{key.titleize}: #{User.find_by(id: new_value)&.full_name(:reverse)}"
          when :PositionID
            "#{key.titleize}: #{EmployeePosition.find_by(id: new_value)&.name}"
          when :PIN
            "#{key}: #{current ? '' : 'Changed'}"
          else
            "#{key.titleize}: #{new_value.is_a?(String) ? new_value.titleize : new_value}"
          end
        when 'Phone'
          next if associated?(key)
          next if key == 'type'

          if key == 'code'
            "Phone Type: #{EmployeePhone.codes.key(new_value).titleize} Phone"
          else
            "#{key.titleize}: #{new_value}"
          end
        when 'AdditionalId'
          next if associated?(key)
          next if key == 'type'

          if key == 'code'
            code = EmployeeAdditionalId.codes.key(new_value).to_sym
            EmployeeAdditionalId::CODE_DISPLAY[code]
          else
            "#{key.titleize}: #{new_value}"
          end
        when 'EmployeeNote'
          next if [:SchoolID, :UserID, :DateTime].include?(key.to_sym)

          if key.to_sym == :AuthorID
            "Author: #{User.find_by(id: new_value)&.full_name(:reverse)}"
          else
            "#{key.titleize}: #{new_value}"
          end
        when 'EmployeeDetail'
          next unless key.to_sym == :NCEAStatus

          "Status: #{new_value.titleize}"
        end
      end.compact.join("\n")
    end

    def associated?(key)
      key.to_sym == :associated_id || key.to_sym == :associated_type
    end
end
