# Usage:
# This module adds single scoped sequential id on AR model.
# In your model, include this module like:
#   include SequentialId[:number, scope: :user_id]
module SequentialId
  def self.[](column_name, scope:)
    options = Struct.new(:column_name, :scope)
    Module.new do
      extend ActiveSupport::Concern
      include SequentialId

      included do
        before_save :set_sequential_id
      end

      define_method(:sequential_id_options) { options.new(column_name, scope) }
    end
  end

  private

  def query_last_sequential_id_value
    column_name = sequential_id_options.column_name
    scope_column_name = sequential_id_options.scope

    scope_condition = { scope_column_name => self[scope_column_name] }
    base_relation = self.class.base_class.unscoped

    value = base_relation.where(scope_condition).where.not(column_name => nil)
                         .lock
                         .order(column_name => :desc).limit(1)
                         .first&.send(column_name)

    value || 0
  end

  def set_sequential_id
    column_name = sequential_id_options.column_name

    return if self[column_name]

    self[column_name] = query_last_sequential_id_value + 1
  end
end