///| CRDT初期検証: LogicalId導入のオーバーヘッド測定

// =============================================================================
// 実験用型定義
// =============================================================================

///|
/// Agent識別子 (簡易版: Int)
pub(all) struct AgentId(Int) derive(Eq, Show)

///|
/// 論理ID: (agent, seq) ペア
#valtype
pub(all) struct LogicalId {
  agent : AgentId
  seq : Int
} derive(Eq, Show)

///|
/// LogicalId生成器
pub(all) struct IdGenerator {
  agent : AgentId
  mut next_seq : Int
}

///|
pub fn IdGenerator::new(agent : AgentId) -> IdGenerator {
  { agent, next_seq: 0 }
}

///|
pub fn IdGenerator::next(self : IdGenerator) -> LogicalId {
  let id = { agent: self.agent, seq: self.next_seq }
  self.next_seq += 1
  id
}

///|
/// CRDT対応Span (キャッシュ付き)
pub(all) struct CrdtSpan {
  start_id : LogicalId
  end_id : LogicalId
  // 絶対位置キャッシュ(高速アクセス用)
  cached_from : Int
  cached_to : Int
}

///|
pub fn CrdtSpan::new(
  start_id : LogicalId,
  end_id : LogicalId,
  from : Int,
  to : Int,
) -> CrdtSpan {
  { start_id, end_id, cached_from: from, cached_to: to }
}

///|
/// TextRun: 連続テキストの圧縮表現
pub(all) struct TextRun {
  id : LogicalId // 開始ID
  content : String // テキスト内容
  deleted : Bool // Tombstone
}

///|
/// 実験用ドキュメント構造
pub(all) struct CrdtDocument {
  runs : Array[TextRun]
  gen : IdGenerator
}

///|
pub fn CrdtDocument::new(agent : AgentId) -> CrdtDocument {
  { runs: [], gen: IdGenerator::new(agent) }
}

///|
/// テキスト挿入
pub fn CrdtDocument::insert(self : CrdtDocument, text : String) -> LogicalId {
  let id = self.gen.next()
  self.runs.push({ id, content: text, deleted: false })
  id
}

///|
/// 削除(Tombstone化)
pub fn CrdtDocument::delete(self : CrdtDocument, idx : Int) -> Unit {
  if idx < self.runs.length() {
    let run = self.runs[idx]
    self.runs[idx] = { ..run, deleted: true }
  }
}

///|
/// アクティブなテキストを取得
pub fn CrdtDocument::get_text(self : CrdtDocument) -> String {
  let buf = StringBuilder::new()
  for run in self.runs {
    if not(run.deleted) {
      buf.write_string(run.content)
    }
  }
  buf.to_string()
}

///|
/// アクティブなRun数
pub fn CrdtDocument::active_count(self : CrdtDocument) -> Int {
  let mut count = 0
  for run in self.runs {
    if not(run.deleted) {
      count += 1
    }
  }
  count
}

///|
/// 全Run数(Tombstone含む)
pub fn CrdtDocument::total_count(self : CrdtDocument) -> Int {
  self.runs.length()
}

// =============================================================================
// LogicalId 比較関数 (CRDT merge用)
// =============================================================================

///|
/// LogicalId の順序比較 (Lamport順序)
pub fn LogicalId::compare(self : LogicalId, other : LogicalId) -> Int {
  // まずseqで比較、同じならagentで比較
  if self.seq != other.seq {
    self.seq - other.seq
  } else {
    let AgentId(a1) = self.agent
    let AgentId(a2) = other.agent
    a1 - a2
  }
}

///|
pub fn LogicalId::lt(self : LogicalId, other : LogicalId) -> Bool {
  self.compare(other) < 0
}

///|
pub fn LogicalId::le(self : LogicalId, other : LogicalId) -> Bool {
  self.compare(other) <= 0
}