module Lutaml::Model::Serialize

def self.included(base)

def self.included(base)
  base.extend(ClassMethods)
end

def ensure_utf8(value)

def ensure_utf8(value)
  case value
  when String
    value.encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
  when Array
    value.map { |v| ensure_utf8(v) }
  when Hash
    value.transform_keys do |k|
      ensure_utf8(k)
    end.transform_values { |v| ensure_utf8(v) }
  else
    value
  end
end

def handle_delegate(_obj, rule, hash)

def handle_delegate(_obj, rule, hash)
  name = rule.to
  value = send(rule.delegate).send(name)
  return if value.nil? && !rule.render_nil
  attribute = send(rule.delegate).class.attributes[name]
  hash[rule.from] = case value
                    when Array
                      value.map do |v|
                        if v.is_a?(Serialize)
                          v.hash_representation(format, options)
                        else
                          attribute.type.serialize(v)
                        end
                      end
                    else
                      if value.is_a?(Serialize)
                        value.hash_representation(format, options)
                      else
                        attribute.type.serialize(value)
                      end
                    end
end

def hash_representation(format, options = {})

def hash_representation(format, options = {})
  only = options[:only]
  except = options[:except]
  mappings = self.class.mappings_for(format).mappings
  mappings.each_with_object({}) do |rule, hash|
    name = rule.to
    next if except&.include?(name) || (only && !only.include?(name))
    next handle_delegate(self, rule, hash) if rule.delegate
    value = if rule.custom_methods[:to]
              send(rule.custom_methods[:to], self, send(name))
            else
              send(name)
            end
    next if value.nil? && !rule.render_nil
    attribute = self.class.attributes[name]
    hash[rule.from] = case value
                      when Array
                        value.map do |v|
                          if v.is_a?(Serialize)
                            v.hash_representation(format, options)
                          else
                            attribute.type.serialize(v)
                          end
                        end
                      else
                        if value.is_a?(Serialize)
                          value.hash_representation(format, options)
                        else
                          attribute.type.serialize(value)
                        end
                      end
  end
end

def initialize(attrs = {})

rubocop:disable Layout/LineLength
def initialize(attrs = {})
  return unless self.class.attributes
  self.class.attributes.each do |name, attr|
    value = if attrs.key?(name)
              attrs[name]
            elsif attrs.key?(name.to_sym)
              attrs[name.to_sym]
            elsif attrs.key?(name.to_s)
              attrs[name.to_s]
            else
              attr.default
            end
    value = if attr.collection?
              (value || []).map do |v|
                if v.is_a?(Hash)
                  attr.type.new(v)
                else
                  Lutaml::Model::Type.cast(
                    v, attr.type
                  )
                end
              end
            elsif value.is_a?(Hash) && attr.type != Lutaml::Model::Type::Hash
              attr.type.new(value)
            else
              Lutaml::Model::Type.cast(value, attr.type)
            end
    send(:"#{name}=", ensure_utf8(value))
  end
end

def to_json(options = {})

def to_json(options = {})
  adapter = Lutaml::Model::Config.json_adapter
  adapter.new(hash_representation(:json, options)).to_json(options)
end

def to_toml(options = {})

def to_toml(options = {})
  adapter = Lutaml::Model::Config.toml_adapter
  adapter.new(hash_representation(:toml, options)).to_toml
end

def to_xml(options = {})

def to_xml(options = {})
  adapter = Lutaml::Model::Config.xml_adapter
  adapter.new(self).to_xml(options)
end

def to_yaml(options = {})

def to_yaml(options = {})
  adapter = Lutaml::Model::Config.yaml_adapter
  adapter.to_yaml(self, options)
end