module JsonbAccessor::Macro::ClassMethods

def jsonb_accessor(jsonb_attribute, *value_fields, **typed_fields)

def jsonb_accessor(jsonb_attribute, *value_fields, **typed_fields)
  all_fields = Macro.group_attributes(value_fields, typed_fields)
  nested_fields, typed_fields = all_fields.values_at(:nested, :typed)
  class_namespace = Macro.build_class_namespace(name)
  attribute_namespace = Module.new
  class_namespace.const_set(jsonb_attribute.to_s.camelize, attribute_namespace)
  nested_classes = ClassBuilder.generate_nested_classes(attribute_namespace, nested_fields)
  singleton_class.send(:define_method, "#{jsonb_attribute}_classes") do
    nested_classes
  end
  delegate "#{jsonb_attribute}_classes", to: :class
  jsonb_attribute_initialization_method_name = "initialize_jsonb_attrs_for_#{jsonb_attribute}"
  define_method(jsonb_attribute_initialization_method_name) do
    jsonb_attribute_hash = send(jsonb_attribute) || {}
    (typed_fields.keys + nested_fields.keys).each do |field|
      send("#{field}=", jsonb_attribute_hash[field.to_s])
    end
  end
  after_initialize(jsonb_attribute_initialization_method_name)
  jsonb_accessor_methods = Module.new do
    define_method("#{jsonb_attribute}=") do |value|
      write_attribute(jsonb_attribute, value)
      send(jsonb_attribute_initialization_method_name)
    end
    define_method(:reload) do |*args, &block|
      super(*args, &block)
      send(jsonb_attribute_initialization_method_name)
      self
    end
  end
  typed_fields.each do |field, type|
    attribute(field.to_s, TypeHelper.fetch(type))
    jsonb_accessor_methods.instance_eval do
      define_method("#{field}=") do |value, *args, &block|
        super(value, *args, &block)
        new_jsonb_value = (send(jsonb_attribute) || {}).merge(field => attributes[field.to_s])
        write_attribute(jsonb_attribute, new_jsonb_value)
      end
    end
  end
  nested_fields.each do |field, nested_attributes|
    attribute(field.to_s, TypeHelper.fetch(:value))
    jsonb_accessor_methods.instance_eval do
      define_method("#{field}=") do |value|
        instance_class = nested_classes[field]
        case value
        when instance_class
          instance = instance_class.new(value.attributes)
        when Hash
          instance = instance_class.new(value)
        when nil
          instance = instance_class.new
        else
          raise UnknownValue, "unable to set value '#{value}' is not a hash, `nil`, or an instance of #{instance_class} in #{__method__}"
        end
        instance.parent = self
        new_jsonb_value = (send(jsonb_attribute) || {}).merge(field.to_s => instance.attributes)
        write_attribute(jsonb_attribute, new_jsonb_value)
        super(instance)
      end
    end
  end
  include jsonb_accessor_methods
end