///|
pub struct PendingQuad {
  mut subj : Span?
  mut pred : Span?
  mut obj : Span?
  mut graph : Span? // 图名(可选)
  // mut term_type : TermType?
  mut has_dot : Bool
  mut state : PendingState
  mut line : Int
} derive(Debug, Eq)

///|
pub impl Show for PendingQuad with fn output(
  self : PendingQuad,
  logger : &Logger,
) -> Unit {
  let span = self.compute_span()
  let (offset, length) = span
  logger.write_string(" \{offset}:\{length}: \{self.state}")
}

///|
pub fn PendingQuad::default() -> PendingQuad {
  {
    subj: None,
    pred: None,
    obj: None,
    graph: None,
    has_dot: false,
    state: ExpectSubject,
    line: 0,
  }
}

///|
/// 检查是否完整
pub fn PendingQuad::is_complete(self : PendingQuad) -> Bool {
  self.subj is Some(_) &&
  self.pred is Some(_) &&
  self.obj is Some(_) &&
  (self.has_dot || self.state == Complete)
}

///|
/// 获取总 span
pub fn PendingQuad::compute_span(self : PendingQuad) -> Span {
  let start = match self.subj {
    Some((offset, _)) => offset
    None => 0
  }
  let end = match (self.obj, self.graph) {
    (Some((offset, length)), _) => offset + length
    (_, Some((offset, length))) => offset + length
    _ => start
  }
  (start, end - start)
}

///|
/// 重置状态
pub fn PendingQuad::reset(self : PendingQuad) -> Unit {
  self.subj = None
  self.pred = None
  self.obj = None
  self.graph = None
  self.has_dot = false
  self.state = ExpectSubject
  self.line = 0
}

///|
/// 获取 span 的结束偏移
pub fn end_offset(span : Span) -> Int {
  let (offset, length) = span
  offset + length
}

///|
/// Quad 组装状态机
/// PendingQuad 的组装状态
pub(all) enum PendingState {
  ExpectSubject
  ExpectPredicate
  ExpectObject
  ExpectDotOrGraph // 期望 . 或 
  ExpectGraph // 期望图名
  ExpectDot // 期望 .
  Complete
} derive(Debug, Eq)

///|
pub impl Show for PendingState with fn output(
  self : PendingState,
  logger : &Logger,
) -> Unit {
  match self {
    ExpectSubject => logger.write_string("ExpectSubject")
    ExpectPredicate => logger.write_string("ExpectPredicate")
    ExpectObject => logger.write_string("ExpectObject")
    ExpectDotOrGraph => logger.write_string("ExpectDotOrGraph")
    ExpectGraph => logger.write_string("ExpectGraph")
    ExpectDot => logger.write_string("ExpectDot")
    Complete => logger.write_string("Complete")
  }
}
// ============================================================
// NQuadsEngine 主结构
// ============================================================

///|
pub impl ParserEngine for NQuadsEngine with fn error_recovery_state(
  _self : NQuadsEngine,
) -> NQuadsEngine {
  NQuadsEngine::new()
}

///|
pub impl ParserEngine for NQuadsEngine with fn create_pending(
  _self : NQuadsEngine,
) -> PendingQuad {
  PendingQuad::default()
}

///|
pub impl ParserEngine for NQuadsEngine with fn is_complete(
  _self : NQuadsEngine,
  pending : PendingQuad,
) -> Bool {
  pending.is_complete()
}

///|
pub impl ParserEngine for NQuadsEngine with fn step(
  _self : NQuadsEngine,
  pending : PendingQuad,
  token : Token,
) -> StepResult {
  match (pending.state, token) {
    // =====================
    // 期望主语
    // =====================
    (ExpectSubject, Iri(span) | BlankNode(span)) => {
      pending.subj = Some(span)
      pending.state = ExpectPredicate
      //  pending.term_type = Some(TermType::Iri)
      Continue
    }
    (ExpectSubject, PrefName(_)) =>
      // N-Quads 不支持前缀名作为主语
      Error(
        ParseError::InvalidToken(
          "N-Quads does not support prefixed names.",
          ParseError::span(token),
        ),
      )
    (ExpectSubject, Unknown(_)) => Continue

    // =====================
    // 期望谓语
    // =====================
    (ExpectPredicate, Iri(span)) => {
      pending.pred = Some(span)
      pending.state = ExpectObject
      //  pending.term_type = Some(TermType::Iri)

      Continue
    }
    (ExpectPredicate, PrefName(_)) =>
      Error(
        ParseError::InvalidToken(
          "Predicate must be an IRI",
          ParseError::span(token),
        ),
      )
    (ExpectPredicate, token) =>
      Error(
        ParseError::InvalidToken(
          "Expected predicate (IRI)",
          ParseError::span(token),
        ),
      )

    // =====================
    // 期望宾语
    // =====================
    (ExpectObject, Iri(span) | Literal(span) | BlankNode(span)) => {
      pending.obj = Some(span)
      pending.state = ExpectDotOrGraph
      Continue
    }
    (ExpectObject, PrefName(_)) =>
      // N-Quads 中前缀名当作 IRI
      Error(
        ParseError::InvalidToken(
          "N-Quads does not support prefixed names.",
          ParseError::span(token),
        ),
      )
    (ExpectObject, token) =>
      Error(
        ParseError::InvalidToken(
          "Expected object (IRI or Literal)",
          ParseError::span(token),
        ),
      )

    // =====================
    // 期望 . 或 图名
    // =====================
    (ExpectDotOrGraph, Dot(_)) => {
      pending.has_dot = true
      pending.state = Complete
      pending.line += 1
      Emit
    }
    (ExpectDotOrGraph, Iri(span)) => {
      // 图名
      pending.graph = Some(span)
      pending.state = ExpectDot
      Continue
    }
    (ExpectDotOrGraph, PrefName(_)) =>
      // 图名必须是完整 IRI
      Error(
        ParseError::InvalidToken(
          "Graph must be an IRI",
          ParseError::span(token),
        ),
      )
    (ExpectDotOrGraph, Unknown(_)) => {
      // . 可选
      pending.has_dot = true
      pending.state = Complete
      Emit
    }

    // =====================
    // 期望 . (在图名之后)
    // =====================
    (ExpectDot, Dot(_)) => {
      pending.has_dot = true
      pending.state = Complete
      pending.line += 1
      Emit
    }
    (ExpectDot, token) =>
      Error(ParseError::InvalidToken("Expected '.'", ParseError::span(token)))

    // =====================
    // 已完成
    // =====================
    (Complete, token) =>
      Error(
        ParseError::InvalidToken(
          "Unexpected token after complete triple",
          ParseError::span(token),
        ),
      )

    // =====================
    // 默认跳过
    // =====================
    _ => SkipLine
  }
}

///|
pub impl ParserEngine for NQuadsEngine with fn recognize_end(
  _self : NQuadsEngine,
  pending : PendingQuad,
  results : Array[Span],
) -> Unit {
  if pending.subj is Some(_) &&
    pending.pred is Some(_) &&
    pending.obj is Some(_) {
    results.push(pending.compute_span())
  }
}

///|
/// NQuadsEngine - 直接对接 Lexerc,管理 PendingQuad 组装和错误收集
pub(all) struct NQuadsEngine {
  lexer : Lexerc
  mut pending : PendingQuad
}

///|
/// 从字节数组创建 NQuadsEngine
pub fn NQuadsEngine::from_bytes(data : FixedArray[Byte]) -> NQuadsEngine {
  NQuadsEngine::{
    lexer: Lexerc::new(data),
    pending: PendingQuad::{
      subj: None,
      pred: None,
      obj: None,
      graph: None,
      has_dot: false,
      state: PendingState::ExpectSubject,
      line: 0,
    },
  }
}

///|
/// 从字符串创建 NQuadsEngine
pub fn NQuadsEngine::from_string(s : String) -> NQuadsEngine {
  NQuadsEngine::from_bytes(@utf8.encode(s).to_fixedarray())
}

///|
/// 创建空 NQuadsEngine
pub fn NQuadsEngine::new() -> NQuadsEngine {
  NQuadsEngine::{
    lexer: Lexerc::new(FixedArray::make(0, 0)),
    pending: PendingQuad::{
      subj: None,
      pred: None,
      obj: None,
      graph: None,
      // term_type: None,
      has_dot: false,
      state: PendingState::ExpectSubject,
      line: 1,
    },
  }
}