module ActiveRecord::Enum

def self.extended(base) # :nodoc:

:nodoc:
def self.extended(base) # :nodoc:
  base.class_attribute(:defined_enums, instance_writer: false, default: {})
end

def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)

def _enum(name, values, prefix: nil, suffix: nil, scopes: true, instance_methods: true, validate: false, **options)
  assert_valid_enum_definition_values(values)
  assert_valid_enum_options(options)
  # statuses = { }
  enum_values = ActiveSupport::HashWithIndifferentAccess.new
  name = name.to_s
  # def self.statuses() statuses end
  detect_enum_conflict!(name, name.pluralize, true)
  singleton_class.define_method(name.pluralize) { enum_values }
  defined_enums[name] = enum_values
  detect_enum_conflict!(name, name)
  detect_enum_conflict!(name, "#{name}=")
  attribute(name, **options)
  decorate_attributes([name]) do |_name, subtype|
    if subtype == ActiveModel::Type.default_value
      raise "Undeclared attribute type for enum '#{name}' in #{self.name}. Enums must be" \
        " backed by a database column or declared with an explicit type" \
        " via `attribute`."
    end
    subtype = subtype.subtype if EnumType === subtype
    EnumType.new(name, enum_values, subtype, raise_on_invalid_values: !validate)
  end
  value_method_names = []
  _enum_methods_module.module_eval do
    prefix = if prefix
      prefix == true ? "#{name}_" : "#{prefix}_"
    end
    suffix = if suffix
      suffix == true ? "_#{name}" : "_#{suffix}"
    end
    pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
    pairs.each do |label, value|
      enum_values[label] = value
      label = label.to_s
      value_method_name = "#{prefix}#{label}#{suffix}"
      value_method_names << value_method_name
      define_enum_methods(name, value_method_name, value, scopes, instance_methods)
      method_friendly_label = label.gsub(/[\W&&[:ascii:]]+/, "_")
      value_method_alias = "#{prefix}#{method_friendly_label}#{suffix}"
      if value_method_alias != value_method_name && !value_method_names.include?(value_method_alias)
        value_method_names << value_method_alias
        define_enum_methods(name, value_method_alias, value, scopes, instance_methods)
      end
    end
  end
  detect_negative_enum_conditions!(value_method_names) if scopes
  if validate
    validate = {} unless Hash === validate
    validates_inclusion_of name, in: enum_values.keys, **validate
  end
  enum_values.freeze
end

def _enum_methods_module

def _enum_methods_module
  @_enum_methods_module ||= begin
    mod = EnumMethods.new(self)
    include mod
    mod
  end
end

def assert_valid_enum_definition_values(values)

def assert_valid_enum_definition_values(values)
  case values
  when Hash
    if values.empty?
      raise ArgumentError, "Enum values #{values} must not be empty."
    end
    if values.keys.any?(&:blank?)
      raise ArgumentError, "Enum values #{values} must not contain a blank name."
    end
  when Array
    if values.empty?
      raise ArgumentError, "Enum values #{values} must not be empty."
    end
    unless values.all?(Symbol) || values.all?(String)
      raise ArgumentError, "Enum values #{values} must only contain symbols or strings."
    end
    if values.any?(&:blank?)
      raise ArgumentError, "Enum values #{values} must not contain a blank name."
    end
  else
    raise ArgumentError, "Enum values #{values} must be either a non-empty hash or an array."
  end
end

def assert_valid_enum_options(options)

def assert_valid_enum_options(options)
  invalid_keys = options.keys & %i[_prefix _suffix _scopes _default _instance_methods]
  unless invalid_keys.empty?
    raise ArgumentError, "invalid option(s): #{invalid_keys.map(&:inspect).join(", ")}. Valid options are: :prefix, :suffix, :scopes, :default, :instance_methods, and :validate."
  end
end

def detect_enum_conflict!(enum_name, method_name, klass_method = false)

def detect_enum_conflict!(enum_name, method_name, klass_method = false)
  if klass_method && dangerous_class_method?(method_name)
    raise_conflict_error(enum_name, method_name, type: "class")
  elsif klass_method && method_defined_within?(method_name, Relation)
    raise_conflict_error(enum_name, method_name, type: "class", source: Relation.name)
  elsif klass_method && method_name.to_sym == :id
    raise_conflict_error(enum_name, method_name)
  elsif !klass_method && dangerous_attribute_method?(method_name)
    raise_conflict_error(enum_name, method_name)
  elsif !klass_method && method_defined_within?(method_name, _enum_methods_module, Module)
    raise_conflict_error(enum_name, method_name, source: "another enum")
  end
end

def detect_negative_enum_conditions!(method_names)

def detect_negative_enum_conditions!(method_names)
  return unless logger
  method_names.select { |m| m.start_with?("not_") }.each do |potential_not|
    inverted_form = potential_not.sub("not_", "")
    if method_names.include?(inverted_form)
      logger.warn "Enum element '#{potential_not}' in #{self.name} uses the prefix 'not_'." \
        " This has caused a conflict with auto generated negative scopes." \
        " Avoid using enum elements starting with 'not' where the positive form is also an element."
    end
  end
end

def enum(name, values = nil, **options)

def enum(name, values = nil, **options)
  values, options = options, {} unless values
  _enum(name, values, **options)
end

def inherited(base)

def inherited(base)
  base.defined_enums = defined_enums.deep_dup
  super
end

def raise_conflict_error(enum_name, method_name, type: "instance", source: "Active Record")

def raise_conflict_error(enum_name, method_name, type: "instance", source: "Active Record")
  raise ArgumentError, ENUM_CONFLICT_MESSAGE % {
    enum: enum_name,
    klass: name,
    type: type,
    method: method_name,
    source: source
  }
end