class DossierOperationLog < ApplicationRecord
  enum operation: {
    changer_groupe_instructeur: 'changer_groupe_instructeur',
    passer_en_instruction: 'passer_en_instruction',
    repasser_en_construction: 'repasser_en_construction',
    demander_une_correction: 'demander_une_correction',
    demander_a_completer: 'demander_a_completer',
    repasser_en_instruction: 'repasser_en_instruction',
    accepter: 'accepter',
    refuser: 'refuser',
    classer_sans_suite: 'classer_sans_suite',
    supprimer: 'supprimer',
    restaurer: 'restaurer',
    modifier_annotation: 'modifier_annotation',
    demander_un_avis: 'demander_un_avis'
  }

  has_one_attached :serialized

  belongs_to :dossier, optional: true
  belongs_to :bill_signature, optional: true

  scope :not_deletion, -> { where.not(operation: operations.fetch(:supprimer)) }
  scope :with_data, -> { where.not(data: nil) }
  scope :brouillon_expired, -> { where(dossier: Dossier.brouillon_expired).not_deletion }
  scope :en_construction_expired, -> { where(dossier: Dossier.en_construction_expired).not_deletion }
  scope :termine_expired, -> { where(dossier: Dossier.termine_expired).not_deletion }

  def move_to_cold_storage!
    if data.present?
      serialized.attach(
        io: StringIO.new(data.to_json),
        filename: "operation-#{digest}.json",
        content_type: 'application/json',
        # we don't want to run virus scanner on this file
        metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
      )
      update!(data: nil)
    end
  end

  def self.purge_discarded
    not_deletion.destroy_all
    with_data.each(&:move_to_cold_storage!)
  end

  def self.create_and_serialize(params)
    dossier = params.fetch(:dossier)

    duree_conservation_dossiers = dossier.procedure.duree_conservation_dossiers_dans_ds
    keep_until = if duree_conservation_dossiers.present?
      if dossier.en_instruction_at
        dossier.en_instruction_at + duree_conservation_dossiers.months
      else
        dossier.created_at + duree_conservation_dossiers.months
      end
    end

    operation_log = new(operation: params.fetch(:operation),
      dossier_id: dossier.id,
      keep_until: keep_until,
      executed_at: Time.zone.now,
      automatic_operation: !!params[:automatic_operation])

    data = {
      operation: operation_log.operation,
      dossier_id: operation_log.dossier_id,
      author: self.serialize_author(params[:author]),
      subject: self.serialize_subject(params[:subject], operation_log.operation),
      automatic_operation: operation_log.automatic_operation?,
      executed_at: operation_log.executed_at.iso8601
    }.compact

    operation_log.data = data
    operation_log.digest = Digest::SHA256.hexdigest(data.to_json)

    operation_log.save!
  end

  def self.serialize_author(author)
    if author.nil?
      nil
    else
      {
        id: serialize_author_id(author),
        email: author.email
      }.as_json
    end
  end

  def self.serialize_author_id(object)
    case object
    when User
      "Usager##{object.id}"
    when Instructeur
      "Instructeur##{object.id}"
    when Administrateur
      "Administrateur##{object.id}"
    when SuperAdmin
      "Manager##{object.id}"
    else
      nil
    end
  end

  def self.serialize_subject(subject, operation = nil)
    if subject.nil?
      nil
    elsif operation == operations.fetch(:supprimer)
      {
        date_de_depot: subject.depose_at,
        date_de_mise_en_instruction: subject.en_instruction_at,
        date_de_decision: subject.processed_at
      }.as_json
    else
      case subject
      when Dossier
        SerializerService.dossier(subject)
      when Champ
        SerializerService.champ(subject)
      when Avis
        SerializerService.avis(subject)
      when Commentaire
        SerializerService.message(subject)
      end
    end
  end
end