///|
pub struct PendingQuad {
  mut subj : Span
  mut pred : Span
  mut obj : Span
  mut graph : Span // 图名 span,错误时保存错误 span
  mut has_dot : Bool
  mut state : PendingState
} 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: (0, 0),
    pred: (0, 0),
    obj: (0, 0),
    graph: (0, 0),
    has_dot: false,
    state: ExpectSubject,
  }
}

///|
/// 检查是否完整
pub fn PendingQuad::is_complete(self : PendingQuad) -> Bool {
  self.has_dot || self.state == Complete
}

///|
/// 获取总 span
pub fn PendingQuad::compute_span(self : PendingQuad) -> Span {
  let start = self.subj.0
  let end = if self.graph.0 != 0 || self.graph.1 != 0 {
    end_offset(self.graph)
  } else {
    end_offset(self.obj)
  }
  (start, end - start)
}

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

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

///|
/// Quad 组装状态机
pub(all) enum PendingState {
  ExpectSubject
  ExpectPredicate
  ExpectObject
  ExpectDotOrGraph // 期望 . 或 
  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")
    ExpectDot => logger.write_string("ExpectDot")
    Complete => logger.write_string("Complete")
  }
}
// ============================================================
// NQuadsEngine 主结构
// ============================================================

///|
/// 解析步骤
fn NQuadsEngine::step(self : NQuadsEngine, token : Token) -> StepResult {
  match (self.pending.state, token) {
    // 期望主语
    (ExpectSubject, Iri(span) | BlankNode(span)) => {
      self.pending.subj = span
      self.pending.state = ExpectPredicate
      Continue
    }
    (ExpectSubject, PrefName(span)) => SkipError(span)
    (ExpectSubject, Unknown(_)) => Continue

    // 期望谓语
    (ExpectPredicate, Iri(span)) => {
      self.pending.pred = span
      self.pending.state = ExpectObject
      Continue
    }
    (ExpectPredicate, token) => SkipError(ParseError::span(token))

    // 期望宾语
    (ExpectObject, Iri(span) | Literal(span) | BlankNode(span)) => {
      self.pending.obj = span
      self.pending.state = ExpectDotOrGraph
      Continue
    }
    (ExpectObject, token) => SkipError(ParseError::span(token))

    // 期望 . 或 图名
    (ExpectDotOrGraph, Dot(_)) => {
      self.pending.has_dot = true
      self.pending.state = Complete
      Emit
    }
    (ExpectDotOrGraph, Iri(span)) => {
      self.pending.graph = span
      self.pending.state = ExpectDot
      Continue
    }
    (ExpectDotOrGraph, PrefName(span)) => SkipError(span)
    (ExpectDotOrGraph, Unknown(_)) => {
      self.pending.has_dot = true
      self.pending.state = Complete
      Emit
    }

    // 期望 . (在图名之后)
    (ExpectDot, Dot(_)) => {
      self.pending.has_dot = true
      self.pending.state = Complete
      Emit
    }
    (ExpectDot, token) => SkipError(ParseError::span(token))

    // 已完成
    (Complete, token) => SkipError(ParseError::span(token))

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

///|
/// NQuadsEngine - 直接对接 Lexerc,管理 PendingQuad 组装和错误收集
pub(all) struct NQuadsEngine {
  mut pending : PendingQuad
  lexer : Lexerc
  data : ArrayView[Byte]
  mut last_error : (Span, Int)? // (错误位置, 行号)
  mut line : Int
}

///|
/// 创建空 NQuadsEngine
pub fn NQuadsEngine::new(
  lexer : Lexerc,
  data : ArrayView[Byte],
) -> NQuadsEngine {
  NQuadsEngine::{
    pending: PendingQuad::{
      subj: (0, 0),
      pred: (0, 0),
      obj: (0, 0),
      graph: (0, 0),
      has_dot: false,
      state: PendingState::ExpectSubject,
    },
    lexer,
    data,
    last_error: None,
    line: 0,
  }
}

///|
/// 从字节数组创建
pub fn NQuadsEngine::from_bytes(data : FixedArray[Byte]) -> NQuadsEngine {
  NQuadsEngine::new(Lexerc::new(data), data)
}

///|
/// 获取原始数据
pub fn NQuadsEngine::data(self : NQuadsEngine) -> ArrayView[Byte] {
  self.data
}

// ============================================================
// 主解析循环
// ============================================================

///|
/// 获取下一个三元组
pub fn NQuadsEngine::next(
  self : NQuadsEngine,
) -> Result[PendingQuad, ParseError]? {
  self.pending.reset()

  for ;; {
    match self.lexer.next() {
      None => {
        if self.pending.state != ExpectSubject {
          return Some(
            Err(
              ParseError::SyntaxErr(
                "Incomplete triple at end of input",
                self.pending.compute_span(),
              ),
            ),
          )
        }
        return None
      }
      Some(token) =>
        if is_eof_token(token) {
          if self.pending.state != ExpectSubject {
            return Some(
              Err(
                ParseError::SyntaxErr(
                  "Incomplete triple at end of input",
                  self.pending.compute_span(),
                ),
              ),
            )
          }
          return None
        } else {
          match self.step(token) {
            Continue => continue
            Emit => {
              let result = self.pending
              self.line += 1
              return Some(Ok(result))
            }
            SkipLine => {
              self.line += 1
              self.pending.reset()
              continue
            }
            SkipError(span) => {
              self.last_error = Some((span, self.line))
              // 消费整行直到 . 或 EOF
              for ;; {
                match self.lexer.next() {
                  None => break
                  Some(t) =>
                    if is_dot_token(t) {
                      self.line += 1
                      break
                    } else if is_eof_token(t) {
                      break
                    }
                }
              }
              self.pending.reset()
              continue
            }
            Error(err) => {
              self.pending.reset()
              return Some(Err(err))
            }
          }
        }
    }
  }
}