// ===== dist 握手五帧纯核(规格书 §4;真帧金罐随行)=====
// wire:dist 段 len 头=u32 BE(段外);段内帧形见各 fn。
// digest = MD5(cookie ‖ integer_to_list(challenge) 十进制 ASCII)
// (dist_util.erl:529;challenge 十进制直串——to_int >2³¹ 负溢出坑,规格书 §4)

///|
pub(all) suberror DistError {
  Truncated(String)
  Malformed(String)
  DigestUnavailable(String) // 骨架 v0:MD5 走 DigestPort 注入(核心零加密)
}

///|
/// DigestPort(digest 六边形位):真实现(mooncry/openssl)住 adapter;测试注入假实现
pub(open) trait DigestPort {
  fn md5(self : Self, data : Bytes) -> Bytes
}

///|
/// 我方 flags(单变量判决形 v2 2026-11-07——external.c:950 真源:段头期待位
/// =ATOM_CACHE(0x2000)|FRAGMENTS(0x800000) 双位,声明任一即被对端期待发帧
/// 带段头(四震 corrupted 根因);0.0.7 全量形(握手 PASS 铁证)仅去 FRAGMENTS
/// ——v1 0x33f5fbd 连裁高 32 位区=多变量违规握手拒;单变量律回归)
pub const DIST_FLAGS : UInt64 = 0x00000d033f5fbdUL

///|
/// 帧 1:SEND_NAME('N' | flags u64 | creation u32 | namelen u16 | name)
/// (真形勘定 2026-11-06:真网 probea FIN 勘——骨架役组帧序/域双错
/// (creation u16+flags 后置);moonactor dist_send_name 金罐真帧对拍
/// ——shot 门 B PASS 实证形为真:flags 先,creation u32)
pub fn send_name(creation : Int32, name : String) -> Bytes {
  let name_b = latin_bytes(name)
  let out : Array[Byte] = []
  out.push(78) // 'N'
  put_u64(out, DIST_FLAGS)
  put_u32(out, creation.reinterpret_as_uint())
  put_u16(out, name_b.length())
  append(out, name_b)
  Bytes::from_array(out)
}

///|
/// 帧 2:status "ok" 解('s' | len u16 | "ok")——u16 len 头外置
pub fn parse_status(data : Bytes) -> Bool raise DistError {
  if data.length() < 1 {
    raise DistError::Truncated("status empty")
  }
  data[0].to_int() == 115 // 's'
}

///|
pub(all) struct ServerChallenge {
  flags : UInt64
  challenge : UInt32 // u32 真域(家法 11:Int32 域负值——to_string 负号串 digest 错源)
  creation : Int32
  name : String
}

///|
/// 帧 3:CHALLENGE 解('N' | flags u64 | challenge u32 | creation u32 | namelen u16 | name)
pub fn parse_challenge(data : Bytes) -> ServerChallenge raise DistError {
  if data.length() < 1 || data[0].to_int() != 78 {
    raise DistError::Malformed("CHALLENGE 非 'N'")
  }
  if data.length() < 19 {
    raise DistError::Truncated("CHALLENGE 短")
  }
  let flags = rd_u64(data, 1)
  let challenge = rd_u32(data, 9)
  let creation = rd_u32(data, 13).reinterpret_as_int()
  let nlen = rd_u16(data, 17)
  if data.length() < 19 + nlen {
    raise DistError::Truncated("CHALLENGE name 短")
  }
  ServerChallenge::{ flags, challenge, creation, name: latin(data, 19, nlen), }
}

///|
/// 帧 4:REPLY 组帧('r' | client_chal u32 | digest 16B)
pub fn challenge_reply(
  digest : &DigestPort,
  client_chal : UInt32,
  server_chal : UInt32,
  cookie : String,
) -> Bytes {
  let out : Array[Byte] = []
  out.push(114) // 'r'
  put_u32(out, client_chal)
  let d = gen_digest(digest, server_chal, cookie)
  append(out, bytes_of_bytes(d))
  Bytes::from_array(out)
}

///|
/// 帧 5:ACK 校验('a' | digest 16B——server 真算我方 chal 的 digest)
pub fn parse_ack(
  digest : &DigestPort,
  data : Bytes,
  client_chal : UInt32,
  cookie : String,
) -> Bool raise DistError {
  if data.length() < 17 {
    raise DistError::Truncated("ACK 短")
  }
  if data[0].to_int() != 97 {
    raise DistError::Malformed("ACK 非 'a'")
  }
  let expect = gen_digest(digest, client_chal, cookie)
  let mut i = 1
  while i < 17 {
    if data[i] != expect[i - 1] {
      return false
    }
    i += 1
  }
  true
}

///|
/// digest 算法真形:MD5(cookie ‖ decimal_string(challenge))
/// (dist_util.erl:529;challenge 十进制 ASCII 直串——规格书 §4 坑账)
pub fn gen_digest(
  digest : &DigestPort,
  challenge : UInt32,
  cookie : String,
) -> Bytes {
  let buf : Array[Byte] = []
  append(buf, latin_bytes(cookie))
  append(buf, latin_bytes(challenge.to_string()))
  digest.md5(Bytes::from_array(buf))
}

///|
fn latin_bytes(s : String) -> Array[Byte] {
  let arr : Array[Byte] = []
  for ch in s {
    let _ = arr.push((ch.to_int() & 255).to_byte())
  }
  arr
}

///|
fn put_u16(out : Array[Byte], v : Int32) -> Unit {
  out.push(((v >> 8) & 255).to_byte())
  out.push((v & 255).to_byte())
}

///|
fn put_u32(out : Array[Byte], v : UInt32) -> Unit {
  out.push(((v >> 24) & 255).to_byte())
  out.push(((v >> 16) & 255).to_byte())
  out.push(((v >> 8) & 255).to_byte())
  out.push((v & 255).to_byte())
}

///|
fn put_u64(out : Array[Byte], v : UInt64) -> Unit {
  for k in 0..<8 {
    let sh = 56 - k * 8
    out.push(((v >> sh).to_int() & 255).to_byte())
  }
}

///|
fn rd_u16(data : Bytes, pos : Int32) -> Int32 raise DistError {
  if pos + 2 > data.length() {
    raise DistError::Truncated("u16 at \{pos}")
  }
  (data[pos].to_int() << 8) | data[pos + 1].to_int()
}

///|
fn rd_u32(data : Bytes, pos : Int32) -> UInt32 raise DistError {
  if pos + 4 > data.length() {
    raise DistError::Truncated("u32 at \{pos}")
  }
  let v = (data[pos].to_int() << 24) |
    (data[pos + 1].to_int() << 16) |
    (data[pos + 2].to_int() << 8) |
    data[pos + 3].to_int()
  v.reinterpret_as_uint()
}

///|
fn rd_u64(data : Bytes, pos : Int32) -> UInt64 raise DistError {
  if pos + 8 > data.length() {
    raise DistError::Truncated("u64 at \{pos}")
  }
  let mut v : UInt64 = 0UL
  for k in 0..<8 {
    v = (v << 8) | data[pos + k].to_int().to_uint64()
  }
  v
}

///|
fn latin(data : Bytes, pos : Int32, len : Int32) -> String raise DistError {
  if pos + len > data.length() {
    raise DistError::Truncated("latin[\{len}] at \{pos}")
  }
  let sb = StringBuilder()
  let mut i = pos
  while i < pos + len {
    match data[i].to_int().to_char() {
      Some(c) => sb.write_char(c)
      None => sb.write_char('?')
    }
    i = i + 1
  }
  sb.to_string()
}

///|
fn append(out : Array[Byte], src : Array[Byte]) -> Unit {
  for b in src {
    let _ = out.push(b)
  }
}

///|
/// ServerChallenge 派生字段外——bytes_of(string)别名

///|
fn bytes_of_bytes(b : Bytes) -> Array[Byte] {
  let arr : Array[Byte] = []
  for byte in b {
    let _ = arr.push(byte)
  }
  arr
}