// main.mbt — 会话全生命周期演示:登录 → 进门 → 过期 → 换发续命 → 登出吊销
// 运行:cd moongrd && moon run examples/session_lifecycle --target native
// access_ttl 故意给 30s 短档,时间全常量跳进(D-G2:核心零时钟零随机;
// 生产 = 真钟 + CSPRNG)。展示三层语义:令牌有效期 / 旋转换发 / 登出吊销。

///|
/// 校验拒的短因(审计友好,不倾倒载荷)。
fn reason(e : @moongrd.VerifyErr) -> String {
  match e {
    @moongrd.VerifyErr::Expired(_) => "令牌过期"
    @moongrd.VerifyErr::BadMac => "签名不符"
    @moongrd.VerifyErr::Malformed(_) => "线形畸形"
    @moongrd.VerifyErr::WrongType(_) => "型不符"
    @moongrd.VerifyErr::WrongIssuer(_) => "签发方不符"
    @moongrd.VerifyErr::WrongAudience(_) => "受众不符"
    @moongrd.VerifyErr::NotYetValid(_) => "生效未到"
  }
}

///|
fn main {
  let config = @moongrd.GuardConfig::make(
    issuer="demo-iss",
    audience="demo-app",
    access_ttl_ms=30000L,
    refresh_ttl_ms=600000L,
  )
  let signer : &@moongrd.Signer = @mooncry.HmacSha256Signer::new(
    Bytes::make(32, b'\x44'),
  )
  let family = @memstore.MemRefreshStore::new()
  let store : &@moongrd.RefreshStore = family
  let revocations = @memstore.MemRevocationStore::new()
  let rev : &@moongrd.RevocationStore = revocations
  // 真实门禁两查:先吊销表,后令牌校验。
  let door_check = fn(now : Int64, jti : String, token : String) -> String {
    if rev.revoked(jti) {
      return "拒(已吊销——登出生效)"
    }
    match
      @moongrd.verify_for(
        config,
        signer,
        now,
        token,
        @moongrd.TokenType::Access,
      ) {
      Ok(_) => "放行"
      Err(e) => "拒(\{reason(e)})"
    }
  }
  println("== 幕 1 登录:双 token 入手 ==")
  let mut now = 1000000L
  let access = @moongrd.issue(
    config,
    signer,
    now,
    "alice",
    @moongrd.TokenType::Access,
    "jti-a1",
  )
  let refresh = @moongrd.issue(
    config,
    signer,
    now,
    "alice",
    @moongrd.TokenType::Refresh,
    "jti-r1",
  )
  let record : @moongrd.RefreshRecord = {
    family_id: "fam-1",
    sub: "alice",
    issued_at: now,
    expires_at: refresh.claims.exp,
    used: false,
    revoked: false,
  }
  store.put("jti-r1", record)
  println(
    "access 有效至 \{access.claims.exp};refresh 有效至 \{refresh.claims.exp}",
  )
  println("")
  println("== 幕 2 十秒后进门:放行 ==")
  now = 1010000L
  let verdict = door_check(now, "jti-a1", access.token)
  println("  now=\{now} → \{verdict}")
  println("")
  println("== 幕 3 四十秒后:access 过期,refresh 换发续命 ==")
  now = 1040000L
  let verdict = door_check(now, "jti-a1", access.token)
  println("  now=\{now} → \{verdict}")
  let mut live_access = access.token
  let mut live_jti = "jti-a1"
  let mut live_refresh = refresh.token
  match @moongrd.refresh(config, signer, store, now, refresh.token, "jti-r2") {
    Ok(r) => {
      let access2 = @moongrd.issue(
        config,
        signer,
        now,
        r.sub,
        @moongrd.TokenType::Access,
        "jti-a2",
      )
      live_access = access2.token
      live_jti = "jti-a2"
      live_refresh = r.refresh.token
      println(
        "  换发成功:新 refresh 入族 \{r.family_id},新 access 已发",
      )
    }
    Err(_) => println("  换发败(意外)")
  }
  println("")
  println("== 幕 4 新 access 进门:会话无感续命 ==")
  now = 1045000L
  let verdict = door_check(now, live_jti, live_access)
  println("  now=\{now} → \{verdict}")
  println("")
  println("== 幕 5 登出:吊销 access + 撤 refresh 全族 ==")
  rev.revoke(live_jti)
  store.revoke_family("fam-1")
  println("  now=\{now} → 门禁:\{door_check(now, live_jti, live_access)}")
  match @moongrd.refresh(config, signer, store, now, live_refresh, "jti-r3") {
    Err(@moongrd.RefreshErr::Revoked(_)) =>
      println("  refresh 也回不去 → 全族已撤,回握手重登录")
    Err(e) => println("  refresh 意外拒 → \{e.to_repr()}")
    Ok(_) => println("  ?!已登出还能换发")
  }
  println("")
  println("== 幕终:会话作废,要再进来请重新登录 ==")
}