// WebAssembly Module Validator - Type Checking

///|
/// Validation error types
pub(all) suberror ValidationError {
  TypeMismatch(String) // Expected vs actual type mismatch
  StackUnderflow(String) // Not enough values on validation stack
  StackHeightMismatch(String) // Stack height doesn't match expected
  InvalidFunctionIndex(Int32)
  InvalidTypeIndex(Int32)
  InvalidLocalIndex(Int32)
  InvalidGlobalIndex(Int32)
  InvalidTableIndex(Int32)
  InvalidMemoryIndex(Int32)
  InvalidLabelIndex(Int32)
  InvalidElemIndex(Int32)
  InvalidDataIndex(Int32) // Unknown data segment index
  UnknownTag(Int32) // Unknown tag index
  UnknownType(Int32) // Forward type reference outside rec group
  UnreachableCode
  MultipleMemories // More than one memory is not allowed in MVP
  MultipleTables // More than one table is not allowed in MVP
  InvalidLimits(String) // Invalid limits (e.g., min > max)
  InvalidAlignment(String) // Alignment must not be larger than natural
  InvalidLaneIndex(Int32, Int32) // lane index, max lanes
  ConstantExpressionRequired // Non-constant instruction in init expression
  MutableGlobalInConstExpr // Mutable global referenced in constant expression
  DuplicateExportName(String) // Same export name used more than once
  UnknownExport(String) // Export references unknown entity
  UninitializedLocal(Int32) // Non-nullable ref local read before initialization
  InvalidStartFunction(String) // Start function has invalid signature
  UndeclaredFunctionReference(Int32) // ref.func used on function not declared in elem/global
  UnsupportedInstruction(String) // Instruction missing from validator dispatch
  // Error with location context
  WithContext(ValidationErrorContext)
} derive(Debug)

///|
/// Keep `Show` behavior while migrating from deprecated `derive(Show)` to
/// `derive(Debug)`.
pub impl Show for ValidationError with fn output(self, logger) {
  logger.write_string(@types.compact_show_repr(Repr(self).to_string()))
}

///|
/// Validation error with location context for debugging
pub(all) struct ValidationErrorContext {
  error_msg : String // The original error message
  func_idx : Int32? // The function index where validation failed
  instr_offset : Int32? // The instruction offset within the function body
  instruction : String? // The instruction that caused the error
} derive(Debug)

///|
pub fn ValidationErrorContext::ValidationErrorContext(
  msg : String,
) -> ValidationErrorContext {
  { error_msg: msg, func_idx: None, instr_offset: None, instruction: None, }
}

///|
pub fn ValidationErrorContext::from_error(
  error : ValidationError,
) -> ValidationErrorContext {
  let msg = match error {
    TypeMismatch(m) => "type mismatch: \{m}"
    StackUnderflow(m) => "stack underflow: \{m}"
    StackHeightMismatch(m) => "stack height mismatch: \{m}"
    InvalidFunctionIndex(idx) => "invalid function index: \{idx}"
    InvalidTypeIndex(idx) => "unknown type: \{idx}"
    InvalidLocalIndex(idx) => "invalid local index: \{idx}"
    InvalidGlobalIndex(idx) => "invalid global index: \{idx}"
    InvalidTableIndex(idx) => "invalid table index: \{idx}"
    InvalidMemoryIndex(idx) => "invalid memory index: \{idx}"
    InvalidLabelIndex(idx) => "invalid label index: \{idx}"
    InvalidElemIndex(idx) => "unknown elem segment \{idx}"
    InvalidDataIndex(idx) => "unknown data segment \{idx}"
    UnknownTag(idx) => "unknown tag \{idx}"
    UnknownType(_) => "unknown type"
    UnreachableCode => "unreachable code"
    MultipleMemories => "multiple memories not allowed in MVP"
    MultipleTables => "multiple tables not allowed in MVP"
    InvalidLimits(m) => "invalid limits: \{m}"
    InvalidAlignment(m) => "alignment must not be larger than natural: \{m}"
    InvalidLaneIndex(lane, max) =>
      "invalid lane index: \{lane} (max: \{max - 1})"
    ConstantExpressionRequired => "constant expression required"
    MutableGlobalInConstExpr => "constant expression required"
    DuplicateExportName(name) => "duplicate export name: \{name}"
    UnknownExport(m) => m
    UninitializedLocal(_) => "uninitialized local"
    InvalidStartFunction(m) => m
    UndeclaredFunctionReference(_) => "undeclared function reference"
    UnsupportedInstruction(m) => m
    WithContext(ctx) => ctx.error_msg
  }
  { error_msg: msg, func_idx: None, instr_offset: None, instruction: None, }
}

///|
pub fn ValidationErrorContext::with_func_idx(
  self : ValidationErrorContext,
  idx : Int32,
) -> ValidationErrorContext {
  { ..self, func_idx: Some(idx), }
}

///|
pub fn ValidationErrorContext::with_instr_offset(
  self : ValidationErrorContext,
  offset : Int32,
) -> ValidationErrorContext {
  { ..self, instr_offset: Some(offset), }
}

///|
pub fn ValidationErrorContext::with_instruction(
  self : ValidationErrorContext,
  instr : String,
) -> ValidationErrorContext {
  { ..self, instruction: Some(instr), }
}

///|
/// Format the validation error with full context for display
pub fn ValidationErrorContext::format(self : ValidationErrorContext) -> String {
  let result = StringBuilder::StringBuilder()
  result.write_string("validation error: ")
  result.write_string(self.error_msg)
  result.write_string("\n")

  // Show function index if available
  if self.func_idx is Some(idx) {
    result.write_string("  in function: func[\{idx}]\n")
  }

  // Show instruction offset if available
  if self.instr_offset is Some(offset) {
    result.write_string("  at instruction offset: \{offset}\n")
  }

  // Show instruction if available
  if self.instruction is Some(instr) {
    result.write_string("  instruction: \{instr}\n")
  }
  result.to_string()
}

///|
pub impl Show for ValidationErrorContext with fn output(self, logger) {
  logger.write_string(self.format())
}

///|
/// Format a basic ValidationError without context
pub fn format_validation_error(error : ValidationError) -> String {
  ValidationErrorContext::from_error(error).format()
}