module Hashable
  extend ActiveSupport::Concern

  included do
    before_save :preserve_changes, if: -> { closed? && !hash_string_valid? }
  end

  def closed?
    hash_string.present?
  end

  def hash_string_valid?
    hash_string.present? && hash_string == computed_hash_string
  end

  def set_hash_string(forced = false)
    return if closed? && !forced
    update_columns(previous_hash_string: computed_previous_hash_string)
    update_columns(hash_string: computed_hash_string)
  end

  def computed_previous_hash_string
    return self.class.last&.hash_string if new_record?
    self.class.find_by(id: id - 1)&.hash_string
  end

  def computed_hash_string
    Digest::SHA2.new(256).hexdigest [
      previous_hash_string,
      id,
      created_at&.utc&.strftime('%Y-%m-%d %H:%M:%S')
    ].join('/')
  end

  private

  def preserve_changes
    throw :abort
  end
end
