///|
/// JSON Value representation
pub enum JsonValue {
  Null
  Bool(Bool)
  Number(Double)
  String(String)
  Array(Array[JsonValue])
  Object(Map[String, JsonValue])
} derive(Show, Eq)

///|
/// Position in the input for error reporting
struct Position {
  line : Int
  column : Int
} derive(Show, Eq)

///|
/// Parse errors with position information
pub(all) suberror ParseError {
  UnexpectedChar(Position, Char)
  UnexpectedEof(Position)
  InvalidNumber(Position, String)
  InvalidEscape(Position)
  InvalidUnicodeEscape(Position)
} derive(Eq, Show)

///|
/// Lexer state
struct Lexer {
  input : String
  mut pos : Int
  mut line : Int
  mut column : Int
}

///|
/// Create a new lexer
fn Lexer::new(input : String) -> Lexer {
  { input, pos: 0, line: 1, column: 1 }
}

///|
/// Get current position
fn Lexer::position(self : Lexer) -> Position {
  { line: self.line, column: self.column }
}

///|
/// Peek at the current character without consuming it
fn Lexer::peek(self : Lexer) -> Char? {
  if self.pos >= self.input.length() {
    None
  } else {
    self.input.get_char(self.pos)
  }
}

///|
/// Consume and return the current character
fn Lexer::advance(self : Lexer) -> Char? {
  match self.peek() {
    Some(ch) => {
      self.pos += ch.to_string().length()
      if ch == '\n' {
        self.line += 1
        self.column = 1
      } else {
        self.column += 1
      }
      Some(ch)
    }
    None => None
  }
}

///|
/// Skip whitespace characters
fn Lexer::skip_whitespace(self : Lexer) -> Unit {
  while true {
    match self.peek() {
      Some(ch) if ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' =>
        self.advance() |> ignore
      _ => break
    }
  }
}

///|
/// Expect a specific character
fn Lexer::expect(self : Lexer, expected : Char) -> Unit raise ParseError {
  match self.advance() {
    Some(ch) if ch == expected => ()
    Some(ch) => raise ParseError::UnexpectedChar(self.position(), ch)
    None => raise ParseError::UnexpectedEof(self.position())
  }
}

///|
/// Parse a JSON value
pub fn parse(input : String) -> JsonValue raise ParseError {
  let lexer = Lexer::new(input)
  let value = parse_value(lexer)
  lexer.skip_whitespace()
  match lexer.peek() {
    Some(ch) => raise ParseError::UnexpectedChar(lexer.position(), ch)
    None => value
  }
}

///|
/// Parse any JSON value
fn parse_value(lexer : Lexer) -> JsonValue raise ParseError {
  lexer.skip_whitespace()
  match lexer.peek() {
    Some('n') => parse_null(lexer)
    Some('t') | Some('f') => parse_bool(lexer)
    Some('"') => String(parse_string(lexer))
    Some('[') => parse_array(lexer)
    Some('{') => parse_object(lexer)
    Some(ch) if ch == '-' || is_digit(ch) => parse_number(lexer)
    Some(ch) => raise ParseError::UnexpectedChar(lexer.position(), ch)
    None => raise ParseError::UnexpectedEof(lexer.position())
  }
}

///|
/// Parse null literal
fn parse_null(lexer : Lexer) -> JsonValue raise ParseError {
  lexer.expect('n')
  lexer.expect('u')
  lexer.expect('l')
  lexer.expect('l')
  Null
}

///|
/// Parse boolean literal
fn parse_bool(lexer : Lexer) -> JsonValue raise ParseError {
  match lexer.peek() {
    Some('t') => {
      lexer.expect('t')
      lexer.expect('r')
      lexer.expect('u')
      lexer.expect('e')
      Bool(true)
    }
    Some('f') => {
      lexer.expect('f')
      lexer.expect('a')
      lexer.expect('l')
      lexer.expect('s')
      lexer.expect('e')
      Bool(false)
    }
    Some(ch) => raise ParseError::UnexpectedChar(lexer.position(), ch)
    None => raise ParseError::UnexpectedEof(lexer.position())
  }
}

///|
/// Check if a character is a decimal digit
fn is_digit(ch : Char) -> Bool {
  ch >= '0' && ch <= '9'
}

///|
/// Parse a number
fn parse_number(lexer : Lexer) -> JsonValue raise ParseError {
  let pos = lexer.position()
  let mut num_str = ""

  // Optional minus sign
  if lexer.peek() == Some('-') {
    num_str += "-"
    lexer.advance() |> ignore
  }

  // Integer part
  match lexer.peek() {
    Some('0') => {
      num_str += "0"
      lexer.advance() |> ignore
    }
    Some(ch) if is_digit(ch) =>
      while true {
        match lexer.peek() {
          Some(ch) if is_digit(ch) => {
            num_str += ch.to_string()
            lexer.advance() |> ignore
          }
          _ => break
        }
      }
    _ => raise ParseError::InvalidNumber(pos, num_str)
  }

  // Fractional part
  if lexer.peek() == Some('.') {
    num_str += "."
    lexer.advance() |> ignore
    let mut has_digit = false
    while true {
      match lexer.peek() {
        Some(ch) if is_digit(ch) => {
          num_str += ch.to_string()
          lexer.advance() |> ignore
          has_digit = true
        }
        _ => break
      }
    }
    if not(has_digit) {
      raise ParseError::InvalidNumber(pos, num_str)
    }
  }

  // Exponent part
  match lexer.peek() {
    Some('e') | Some('E') => {
      num_str += "e"
      lexer.advance() |> ignore
      match lexer.peek() {
        Some('+') => lexer.advance() |> ignore
        Some('-') => {
          num_str += "-"
          lexer.advance() |> ignore
        }
        _ => ()
      }
      let mut has_digit = false
      while true {
        match lexer.peek() {
          Some(ch) if is_digit(ch) => {
            num_str += ch.to_string()
            lexer.advance() |> ignore
            has_digit = true
          }
          _ => break
        }
      }
      if not(has_digit) {
        raise ParseError::InvalidNumber(pos, num_str)
      }
    }
    _ => ()
  }
  try @strconv.parse_double(num_str) catch {
    _ => raise ParseError::InvalidNumber(pos, num_str)
  } noraise {
    n => Number(n)
  }
}

///|
/// Parse a string
fn parse_string(lexer : Lexer) -> String raise ParseError {
  let pos = lexer.position()
  lexer.expect('"')
  let mut result = ""
  while true {
    match lexer.advance() {
      Some('"') => break
      Some('\\') =>
        match lexer.advance() {
          Some('"') => result += "\""
          Some('\\') => result += "\\"
          Some('/') => result += "/"
          Some('b') => result += "\u{8}" // backspace
          Some('f') => result += "\u{c}" // form feed
          Some('n') => result += "\n"
          Some('r') => result += "\r"
          Some('t') => result += "\t"
          Some('u') => {
            // Parse unicode escape \uXXXX
            let mut hex = ""
            for i = 0; i < 4; i = i + 1 {
              match lexer.advance() {
                Some(ch) if is_hex_digit(ch) => hex += ch.to_string()
                _ => raise ParseError::InvalidUnicodeEscape(pos)
              }
            }
            match parse_hex(hex) {
              Some(code) =>
                match code.to_char() {
                  Some(ch) => result += ch.to_string()
                  None => raise ParseError::InvalidUnicodeEscape(pos)
                }
              None => raise ParseError::InvalidUnicodeEscape(pos)
            }
          }
          _ => raise ParseError::InvalidEscape(pos)
        }
      Some(ch) if ch.to_int() < 0x20 =>
        raise ParseError::UnexpectedChar(pos, ch)
      Some(ch) => result += ch.to_string()
      None => raise ParseError::UnexpectedEof(pos)
    }
  }
  result
}

///|
/// Check if character is a hex digit
fn is_hex_digit(ch : Char) -> Bool {
  (ch >= '0' && ch <= '9') ||
  (ch >= 'a' && ch <= 'f') ||
  (ch >= 'A' && ch <= 'F')
}

///|
/// Parse hexadecimal string to integer
fn parse_hex(s : String) -> Int? {
  let mut result = 0
  for i = 0; i < s.length(); i = i + 1 {
    let ch = s[i]
    let digit = if ch >= '0' && ch <= '9' {
      ch - '0'
    } else if ch >= 'a' && ch <= 'f' {
      ch - 'a' + 10
    } else if ch >= 'A' && ch <= 'F' {
      ch - 'A' + 10
    } else {
      return None
    }
    result = result * 16 + digit
  }
  Some(result)
}

///|
/// Parse an array
fn parse_array(lexer : Lexer) -> JsonValue raise ParseError {
  lexer.expect('[')
  lexer.skip_whitespace()
  let arr : Array[JsonValue] = []

  // Check for empty array
  if lexer.peek() == Some(']') {
    lexer.advance() |> ignore
    return Array(arr)
  }
  while true {
    arr.push(parse_value(lexer))
    lexer.skip_whitespace()
    match lexer.advance() {
      Some(',') => {
        lexer.skip_whitespace()
        continue
      }
      Some(']') => break
      Some(ch) => raise ParseError::UnexpectedChar(lexer.position(), ch)
      None => raise ParseError::UnexpectedEof(lexer.position())
    }
  }
  Array(arr)
}

///|
/// Parse an object
fn parse_object(lexer : Lexer) -> JsonValue raise ParseError {
  lexer.expect('{')
  lexer.skip_whitespace()
  let obj : Map[String, JsonValue] = {}

  // Check for empty object
  if lexer.peek() == Some('}') {
    lexer.advance() |> ignore
    return Object(obj)
  }
  while true {
    // Parse key
    let key = parse_string(lexer)
    lexer.skip_whitespace()

    // Expect colon
    lexer.expect(':')
    lexer.skip_whitespace()

    // Parse value
    let value = parse_value(lexer)
    obj[key] = value
    lexer.skip_whitespace()
    match lexer.advance() {
      Some(',') => {
        lexer.skip_whitespace()
        continue
      }
      Some('}') => break
      Some(ch) => raise ParseError::UnexpectedChar(lexer.position(), ch)
      None => raise ParseError::UnexpectedEof(lexer.position())
    }
  }
  Object(obj)
}