///|
/// TOML Value types that represent different TOML data types
pub(all) enum TomlValue {
  TomlString(String)
  TomlInteger(Int64)
  TomlFloat(Double)
  TomlBoolean(Bool)
  TomlArray(Array[TomlValue])
  TomlTable(Map[String, TomlValue])
  TomlDateTime(TomlDateTime)
} derive(Eq, ToJson, Debug)

///|
/// Parser state (will implement methods later)
pub struct Parser {
  tokens : Array[Token]
  mut position : Int
}

///|
pub fn Parser::view(
  self : Self,
  skip_newlines? : Bool = false,
) -> ArrayView[Token] {
  if skip_newlines {
    loop self.view() {
      [Newline(..), .. rest] => continue rest
      rest => rest
    }
  } else {
    self.tokens[self.position:]
  }
}

///|
/// FIXME: expose upstream in the core
fn[T] ArrayView::start(self : ArrayView[T]) -> Int = "%arrayview.start"

///|
pub fn Parser::update_view(self : Parser, view : ArrayView[Token]) -> Unit {
  let new_offset = view.start() // consistent
  self.position = new_offset
}

///|
/// Create a new parser
pub fn Parser::new(tokens : Array[Token]) -> Parser {
  { tokens, position: 0 }
}

///|
/// Check if an array contains homogeneous types (TOML spec requirement)
pub fn TomlValue::is_homogeneous_array(arr : Array[TomlValue]) -> Bool {
  match arr {
    [] => true
    [first, .. rest] => {
      fn type_id(value : TomlValue) -> Int {
        match value {
          TomlString(_) => 0
          TomlInteger(_) => 1
          TomlFloat(_) => 2
          TomlBoolean(_) => 3
          TomlArray(_) => 4
          TomlTable(_) => 5
          TomlDateTime(_) => 6
        }
      }

      let first_type = type_id(first)
      rest.all(x => type_id(x) == first_type)
    }
  }
}

///|
/// Get the type name of a TomlValue for error messages
pub fn TomlValue::type_name(self : TomlValue) -> String {
  match self {
    TomlString(_) => "string"
    TomlInteger(_) => "integer"
    TomlFloat(_) => "float"
    TomlBoolean(_) => "boolean"
    TomlArray(_) => "array"
    TomlTable(_) => "table"
    TomlDateTime(_) => "datetime"
  }
}

///|
/// Validate that a TomlValue follows TOML specification rules
pub fn TomlValue::validate(self : TomlValue) -> Bool {
  match self {
    TomlArray(arr) => {
      // Check homogeneity
      if !TomlValue::is_homogeneous_array(arr) {
        return false
      }
      // Recursively validate nested values
      for i = 0; i < arr.length(); i = i + 1 {
        if !arr[i].validate() {
          return false
        }
      }
      true
    }
    TomlTable(table) => {
      // Recursively validate all values in the table
      let mut valid = true
      table.each(fn(_key, value) { if !value.validate() { valid = false } })
      valid
    }
    _ => true // All other types are always valid by themselves
  }
}