///| GFM table parsing (split from block_parser.mbt).

///|
/// Try to parse GFM table
fn BlockParser::try_parse_table(self : BlockParser, start : Int) -> Block? {
  let saved = self.scanner.pos
  let leading = self.read_leading_trivia()

  // First line must be a potential header row (contains |)
  let header_line = self.scanner.read_line()
  if !header_line.contains("|") {
    self.scanner.restore(saved)
    return None
  }
  if char_is(self.scanner.peek(), '\n') {
    self.scanner.advance(1)
  }

  // Second line must be separator row (contains | and -)
  let separator_line = self.scanner.read_line()
  if !separator_line.contains("|") || !separator_line.contains("-") {
    self.scanner.restore(saved)
    return None
  }

  // Parse alignments from separator row
  let alignments = parse_table_alignments(separator_line)
  if alignments.is_empty() {
    self.scanner.restore(saved)
    return None
  }

  // Count header columns - must match separator columns for valid table
  let header_cells = split_table_cells(header_line)
  let header_col_count = header_cells
    .filter(fn(c) { !c.trim(chars=" \t\n\r").is_empty() })
    .length()
  if header_col_count != alignments.length() {
    // Column count mismatch - not a valid table
    self.scanner.restore(saved)
    return None
  }
  if char_is(self.scanner.peek(), '\n') {
    self.scanner.advance(1)
  }

  // Parse header cells
  let header = parse_table_row(
    header_line,
    alignments.length(),
    self.strict,
    self.wikilinks,
  )

  // Parse data rows
  let rows : Array[Array[TableCell]] = []
  while !self.scanner.is_eof() && !self.scanner.is_blank_line() {
    let row_start = self.scanner.pos
    let row_line = self.scanner.read_line()
    if !row_line.contains("|") {
      // Not a table row, restore position and stop
      self.scanner.restore(row_start)
      break
    }
    rows.push(
      parse_table_row(
        row_line,
        alignments.length(),
        self.strict,
        self.wikilinks,
      ),
    )
    if char_is(self.scanner.peek(), '\n') {
      self.scanner.advance(1)
    }
  }
  Some(
    Block::Table(
      header~,
      alignments~,
      rows~,
      span=Span::new(start, self.scanner.pos),
      leading_trivia=leading,
      trailing_trivia=Trivia::empty(),
    ),
  )
}

///|
/// Parse table alignments from separator row
fn parse_table_alignments(line : String) -> Array[TableAlign] {
  let alignments : Array[TableAlign] = []
  let cells = split_table_cells(line)
  for cell in cells {
    let trimmed = cell.trim(chars=" \t\n\r").to_owned()
    if trimmed.is_empty() {
      continue
    }
    let has_left_colon = trimmed.has_prefix(":")
    let has_right_colon = trimmed.has_suffix(":")

    // Check if it's a valid separator (at least one dash)
    let mut has_dash = false
    for i = 0; i < trimmed.length(); i = i + 1 {
      match trimmed.get_char(i) {
        Some('-') => has_dash = true
        Some(':') => () // Allowed
        _ =>
          // Invalid character in separator
          return []
      }
    }
    if !has_dash {
      return []
    }
    let align = if has_left_colon && has_right_colon {
      TableAlign::Center
    } else if has_left_colon {
      TableAlign::Left
    } else if has_right_colon {
      TableAlign::Right
    } else {
      TableAlign::None
    }
    alignments.push(align)
  }
  alignments
}

///|
/// Parse a table row into cells
fn parse_table_row(
  line : String,
  expected_cols : Int,
  strict : Bool,
  wikilinks : Bool,
) -> Array[TableCell] {
  let cells : Array[TableCell] = []
  let raw_cells = split_table_cells(line)
  for i, cell in raw_cells {
    if i >= expected_cols {
      break
    }
    let content = cell.trim(chars=" \t\n\r").to_owned()
    let children = parse_inlines(content, strict~, wikilinks~)
    cells.push({ children, span: Span::new(0, content.length()) }, // Simplified span
    )
  }

  // Pad with empty cells if needed
  while cells.length() < expected_cols {
    cells.push({ children: [], span: Span::new(0, 0) })
  }
  cells
}

///|
/// Split table row into cells by |
fn split_table_cells(line : String) -> Array[String] {
  let cells : Array[String] = []
  let buf = StringBuilder::new()
  let mut in_escape = false
  for i = 0; i < line.length(); i = i + 1 {
    match line.get_char(i) {
      Some('\\') if !in_escape => {
        in_escape = true
        buf.write_char('\\')
      }
      Some('|') if !in_escape => {
        cells.push(buf.to_string())
        // Reset buffer by creating new one
        buf.reset()
      }
      Some(c) => {
        in_escape = false
        buf.write_char(c)
      }
      None => ()
    }
  }

  // Add last cell
  let last = buf.to_string()
  if !last.trim(chars=" \t\n\r").is_empty() {
    cells.push(last)
  }

  // Remove first cell if empty (leading |)
  if cells.length() > 0 {
    match cells[0].trim(chars=" \t\n\r").to_owned() {
      "" => {
        let _ = cells.remove(0)
      }
      _ => ()
    }
  }
  cells
}