///|
/// Parser state
priv struct Parser {
  lexer : Lexer
  mut current : Token
}

///|
/// Create new parser
fn Parser::new(input : String) -> Parser raise JsonError {
  let lexer = Lexer::new(input)
  let current = lexer.next_token()
  { lexer, current }
}

///|
/// Advance to next token
fn Parser::advance(self : Parser) -> Unit raise JsonError {
  self.current = self.lexer.next_token()
}

///|
/// Parse a JSON value
fn Parser::parse_value(self : Parser) -> JsonValue raise JsonError {
  match self.current {
    TNull => {
      self.advance()
      Null
    }
    TTrue => {
      self.advance()
      Bool(true)
    }
    TFalse => {
      self.advance()
      Bool(false)
    }
    TNumber(n) => {
      self.advance()
      Number(n)
    }
    TString(s) => {
      self.advance()
      String(s)
    }
    TLeftBracket => self.parse_array()
    TLeftBrace => self.parse_object()
    _ => {
      let pos = self.lexer.position()
      let msg = "Expected value, got \{self.current}"
      raise JsonError::UnexpectedToken(pos, msg)
    }
  }
}

///|
/// Parse array
fn Parser::parse_array(self : Parser) -> JsonValue raise JsonError {
  self.advance() // consume [
  let values : Array[JsonValue] = []

  // Empty array
  if self.current == TRightBracket {
    self.advance()
    return Array(values)
  }
  while true {
    let value = self.parse_value()
    values.push(value)
    match self.current {
      TComma => {
        self.advance()
        // Check for trailing comma
        if self.current == TRightBracket {
          let pos = self.lexer.position()
          raise JsonError::TrailingComma(pos)
        }
        continue
      }
      TRightBracket => {
        self.advance()
        break
      }
      _ => {
        let pos = self.lexer.position()
        let msg = "Expected comma or ] in array"
        raise JsonError::UnexpectedToken(pos, msg)
      }
    }
  }
  Array(values)
}

///|
/// Parse object
fn Parser::parse_object(self : Parser) -> JsonValue raise JsonError {
  self.advance() // consume {
  let obj : Map[String, JsonValue] = {}

  // Empty object
  if self.current == TRightBrace {
    self.advance()
    return Object(obj)
  }
  while true {
    // Parse key (must be string)
    let key = match self.current {
      TString(s) => {
        self.advance()
        s
      }
      _ => {
        let pos = self.lexer.position()
        let msg = "Expected string key in object"
        raise JsonError::UnexpectedToken(pos, msg)
      }
    }

    // Expect colon
    match self.current {
      TColon => self.advance()
      _ => {
        let pos = self.lexer.position()
        let msg = "Expected : after key"
        raise JsonError::UnexpectedToken(pos, msg)
      }
    }

    // Parse value
    let value = self.parse_value()

    // Check for duplicate key
    if obj.contains(key) {
      let pos = self.lexer.position()
      let msg = "Duplicate key: \{key}"
      raise JsonError::DuplicateKey(pos, msg)
    }
    obj[key] = value
    match self.current {
      TComma => {
        self.advance()
        // Check for trailing comma
        if self.current == TRightBrace {
          let pos = self.lexer.position()
          raise JsonError::TrailingComma(pos)
        }
        continue
      }
      TRightBrace => {
        self.advance()
        break
      }
      _ => {
        let pos = self.lexer.position()
        let msg = "Expected comma or } in object"
        raise JsonError::UnexpectedToken(pos, msg)
      }
    }
  }
  Object(obj)
}

///|
/// Main parse function
pub fn parse(input : String) -> JsonValue raise JsonError {
  let parser = Parser::new(input)
  let value = parser.parse_value()

  // Ensure no trailing content
  if parser.current != TEof {
    let pos = parser.lexer.position()
    let msg = "Unexpected content after JSON value"
    raise JsonError::UnexpectedToken(pos, msg)
  }
  value
}