module Interactor::Validation::Validates::InstanceMethods

def self.prepended(base)

def self.prepended(base)
  # Include all validator modules
  base.include(Validators::Presence)
  base.include(Validators::Numeric)
  base.include(Validators::Boolean)
  base.include(Validators::Format)
  base.include(Validators::Length)
  base.include(Validators::Inclusion)
  base.include(Validators::Hash)
  base.include(Validators::Array)
end

def errors

def errors
  @errors ||= Errors.new(halt_checker: -> { validation_config(:halt) })
end

def format_errors

def format_errors
  case validation_config(:mode)
  when :code
    format_errors_as_code
  else
    format_errors_as_default
  end
end

def format_errors_as_code

def format_errors_as_code
  errors.map do |err|
    { code: generate_error_code(err.attribute, err.type) }
  end
end

def format_errors_as_default

def format_errors_as_default
  errors.map do |err|
    {
      attribute: err.attribute,
      type: err.type,
      message: "#{err.attribute.to_s.humanize} #{err.message}"
    }
  end
end

def generate_error_code(attribute, type)

def generate_error_code(attribute, type)
  # Convert attribute to uppercase with underscores
  # Handle nested attributes: user.email → USER_EMAIL, items[0].name → ITEMS[0]_NAME
  code_attribute = attribute.to_s
                            .gsub(/\[(\d+)\]\./, '[\\1]_')
                            .gsub(".", "_")
                            .upcase
  # Use "IS_REQUIRED" for blank errors, otherwise use type name
  code_type = type == :blank ? "IS_REQUIRED" : type.to_s.upcase
  "#{code_attribute}_#{code_type}"
end

def run_validations!

def run_validations!
  param_errors = false
  begin
    # Run parameter validations
    if self.class._validations
      self.class._validations.each do |param, rules|
        value = context.respond_to?(param) ? context.public_send(param) : nil
        validate_param(param, value, rules)
      end
      param_errors = errors.any?
    end
    # Run custom validations if defined
    # Skip if param validations failed and skip_validate is true
    validate! if respond_to?(:validate!, true) && !(param_errors && validation_config(:skip_validate))
  rescue HaltValidation
    # Validation halted on first error - fall through to fail context
  end
  # Fail context if any errors exist
  context.fail!(errors: format_errors) if errors.any?
end

def validate_nested(param, value, nested_rules)

def validate_nested(param, value, nested_rules)
  if value.is_a?(::Array)
    validate_array(param, value, nested_rules)
  elsif value.is_a?(::Hash)
    validate_hash(param, value, nested_rules)
  end
end

def validate_param(param, value, rules)

def validate_param(param, value, rules)
  # Handle nested validation
  if rules[:_nested]
    validate_presence(param, value, rules[:presence]) if rules[:presence]
    validate_nested(param, value, rules[:_nested]) if value.present?
    return
  end
  # Standard validations
  validate_presence(param, value, rules[:presence]) if rules[:presence]
  return unless value.present?
  validate_boolean(param, value) if rules[:boolean]
  validate_format(param, value, rules[:format]) if rules[:format]
  validate_length(param, value, rules[:length]) if rules[:length]
  validate_inclusion(param, value, rules[:inclusion]) if rules[:inclusion]
  validate_numeric(param, value, rules[:numeric] || rules[:numericality]) if rules[:numeric] || rules[:numericality]
end

def validation_config(key)

def validation_config(key)
  # Check per-interactor config first, then fall back to global config
  self.class._validation_config.key?(key) ? self.class._validation_config[key] : Interactor::Validation.configuration.public_send(key)
end