// ============================================================
// Markdown
// ============================================================
// 一个轻量的 Markdown 块级解析器:把文档按块结构拆分。
// 支持:标题(#)、段落、代码块(```)、引用(>)、列表(-/*/+/1.)、水平线(---)。
// 限制:不解析行内样式(**粗体**、[链接] 等)与嵌套列表,仅做块级划分。

///|
/// Markdown 块:标题 / 段落 / 代码块 / 引用 / 列表项 / 水平线
pub(all) enum MarkdownBlock {
  /// 标题:级别(1-6) + 文本
  Heading(Int, String)
  /// 普通段落
  Paragraph(String)
  /// 代码块:语言标识 + 代码内容
  CodeBlock(String, String)
  /// 引用块
  Quote(String)
  /// 列表项
  ListItem(String)
  /// 水平分隔线
  HorizontalRule
} derive(Eq, @debug.Debug)

///|
/// 读取并解析 Markdown 文件为块结构
pub fn read_markdown(
  file_path : String,
  encoding? : Encoding? = None,
) -> Array[MarkdownBlock] raise ReaderError {
  parse_markdown(read_txt(file_path, encoding~))
}

///|
/// 解析 Markdown 字符串为块结构
pub fn parse_markdown(text : String) -> Array[MarkdownBlock] {
  let blocks : Array[MarkdownBlock] = []
  let lines = text.split("\n".view()).to_array()
  let n = lines.length()
  let mut i = 0
  while i < n {
    let line = lines[i].trim_end(chars="\r".view()).to_owned()
    // 空行
    if line.trim().length() == 0 {
      i = i + 1
      continue
    }
    // 代码块
    if line.has_prefix("```".view()) {
      let lang = line[3:].trim().to_owned()
      let code : Array[String] = []
      i = i + 1
      while i < n {
        let cl = lines[i].trim_end(chars="\r".view()).to_owned()
        if cl.has_prefix("```".view()) {
          i = i + 1
          break
        }
        code.push(cl)
        i = i + 1
      }
      blocks.push(MarkdownBlock::CodeBlock(lang, code.join("\n".view())))
      continue
    }
    // 标题
    match parse_heading(line) {
      Some((level, text)) => {
        blocks.push(MarkdownBlock::Heading(level, text))
        i = i + 1
        continue
      }
      None => ()
    }
    // 水平线
    if is_horizontal_rule(line) {
      blocks.push(MarkdownBlock::HorizontalRule)
      i = i + 1
      continue
    }
    // 引用
    if line.has_prefix(">".view()) {
      let quoted : Array[String] = []
      while i < n {
        let ql = lines[i].trim_end(chars="\r".view()).to_owned()
        if !ql.has_prefix(">".view()) {
          break
        }
        quoted.push(ql[1:].trim_start(chars=" ".view()).to_owned())
        i = i + 1
      }
      blocks.push(MarkdownBlock::Quote(quoted.join("\n".view())))
      continue
    }
    // 列表项
    match list_item_text(line) {
      Some(item) => {
        blocks.push(MarkdownBlock::ListItem(item))
        i = i + 1
        continue
      }
      None => ()
    }
    // 段落:收集连续的非特殊行
    let para : Array[String] = []
    while i < n {
      let pl = lines[i].trim_end(chars="\r".view()).to_owned()
      if pl.trim().length() == 0 ||
        parse_heading(pl) is Some(_) ||
        pl.has_prefix(">".view()) ||
        pl.has_prefix("```".view()) ||
        is_horizontal_rule(pl) ||
        list_item_text(pl) is Some(_) {
        break
      }
      para.push(pl)
      i = i + 1
    }
    if para.length() > 0 {
      blocks.push(MarkdownBlock::Paragraph(para.join(" ".view())))
    }
  }
  blocks
}

///|
/// 渲染为 Markdown 文本(近似还原)
pub fn MarkdownBlock::to_string(self : MarkdownBlock) -> String {
  match self {
    Heading(level, text) => hashes(level) + " " + text
    Paragraph(text) => text
    CodeBlock(lang, code) => "```" + lang + "\n" + code + "\n```"
    Quote(text) => "> " + text
    ListItem(text) => "- " + text
    HorizontalRule => "---"
  }
}

// ============================================================
// 内部辅助
// ============================================================

///|
fn is_ws_char(c : Char) -> Bool {
  c == ' ' || c == '\t' || c == '\r' || c == '\n'
}

///|
fn is_ws_prefix(s : String) -> Bool {
  for c in s {
    return is_ws_char(c)
  }
  false
}

///|
/// 解析标题:返回 (级别, 文本),不是标题则返回 None
fn parse_heading(line : String) -> (Int, String)? {
  let mut level = 0
  for c in line {
    if c == '#' {
      level = level + 1
    } else {
      break
    }
  }
  if level == 0 || level > 6 {
    return None
  }
  let rest = line[level:].to_owned()
  if rest == "" || is_ws_prefix(rest) {
    return Some((level, rest.trim().to_owned()))
  }
  None
}

///|
/// 判断是否为水平线(--- / *** / ___,长度 ≥ 3 且全为同一字符)
fn is_horizontal_rule(line : String) -> Bool {
  let t = line.trim().to_owned()
  if t.length() < 3 {
    return false
  }
  let first = t[0:1].to_owned()
  if first != "-" && first != "*" && first != "_" {
    return false
  }
  for c in t {
    if c.to_string() != first {
      return false
    }
  }
  true
}

///|
/// 解析列表项:返回去掉标记后的文本,不是列表项则返回 None
fn list_item_text(line : String) -> String? {
  // 无序:- / * / + 后接空白
  if line.length() >= 2 &&
    (
      line.has_prefix("-".view()) ||
      line.has_prefix("*".view()) ||
      line.has_prefix("+".view())
    ) {
    let rest = line[1:].to_owned()
    if rest == "" || is_ws_prefix(rest) {
      return Some(line[2:].trim().to_owned())
    }
  }
  // 有序:数字 + '.' / ')' 后接内容
  let mut d = 0
  for c in line {
    if c >= '0' && c <= '9' {
      d = d + 1
    } else {
      break
    }
  }
  if d > 0 && d + 1 < line.length() {
    let sep = line[d:d + 1].to_owned()
    if sep == "." || sep == ")" {
      return Some(line[d + 1:].trim().to_owned())
    }
  }
  None
}

///|
fn hashes(n : Int) -> String {
  let mut s = ""
  let mut i = 0
  while i < n {
    s = s + "#"
    i = i + 1
  }
  s
}