// Chapter manifest
const CHAPTERS = [
  {
    n: 1, slug: "clob-client", file: "01-clob-client",
    title: "CLOB Orderbook Client",
    why: "V2 replaces the REST/WS split with a unified CLOB endpoint. If you don't migrate your connection layer, nothing else works."
  },
  {
    n: 2, slug: "auth-client", file: "02-auth-client",
    title: "Auth Client",
    why: "EIP-712 v2 signatures and API-key auth. The domain separator changed — every V1 signing path silently produces invalid sigs."
  },
  {
    n: 3, slug: "positions", file: "03-positions",
    title: "Positions",
    why: "Reading and reconciling position state across the cutover window. Don't trust a single source."
  },
  {
    n: 4, slug: "order-struct", file: "04-order-struct",
    title: "Order Struct",
    why: "The V2 order struct adds fields, removes others, and reorders encoding. A one-byte mismatch rejects the whole order."
  },
  {
    n: 5, slug: "nonce", file: "05-nonce",
    title: "Nonce Management",
    why: "Monotonic timestamps with per-market-address namespacing. Get this wrong and you'll collide with your own pending orders."
  },
  {
    n: 6, slug: "signatures", file: "06-signatures",
    title: "Signature Schemes",
    why: "EOA vs EIP-1271. If you run a proxy wallet, this is the chapter that will eat your weekend."
  },
  {
    n: 7, slug: "pusd", file: "07-pusd",
    title: "pUSD Flow",
    why: "Wrap/unwrap mechanics and the 4/28 cutover. USDC balances don't auto-migrate — your balance reads 0 if you skip this."
  },
  {
    n: 8, slug: "cancel-pause", file: "08-cancel-pause",
    title: "Cancel & Pause",
    why: "The cancel registry, the pause window, and stale signed orders that can re-execute if you don't invalidate properly."
  },
  {
    n: 9, slug: "e2e", file: "09-e2e",
    title: "E2E Verification",
    why: "Running all 8 modules end-to-end against live V2. The script you wish existed before cutover."
  },
];

const CUTOVER_ISO = "2026-04-28T11:00:00Z";

// --- Chapter 1 ------------------------------------------------------------

const CH1_CODE_TS = `// 01-clob-client.ts
// Minimal V2 CLOB client: connect, snapshot-then-delta, reconcile.

import { ClobClient, ChainId } from "@polymarket/clob-client";
import { Wallet } from "ethers";

const HOST = "https://clob.polymarket.com";
const CHAIN = ChainId.PolygonMainnet;

async function main() {
  const signer = new Wallet(process.env.PK!);
  const client = new ClobClient(HOST, CHAIN, signer);

  // V2: fetch the authoritative book snapshot first.
  const market = "0x7f8a...c12"; // condition id
  const book = await client.getOrderBook(market);
  console.log("hash", book.hash);

  // Then open the WS stream and reconcile deltas by book hash.
  const ws = await client.subscribe({
    channel: "market",
    markets: [market],
  });

  ws.on("book_update", (ev) => {
    if (ev.prev_hash !== book.hash) return resync();
    applyDelta(book, ev);
    book.hash = ev.hash;
  });
}

main().catch(console.error);
`;

const CH1_CODE_PY = `# 01_clob_client.py
# Minimal V2 CLOB client: connect, snapshot-then-delta, reconcile.

import os
import asyncio
from py_clob_client.client import ClobClient
from py_clob_client.constants import POLYGON

HOST = "https://clob.polymarket.com"
CHAIN_ID = POLYGON

async def main():
    client = ClobClient(HOST, chain_id=CHAIN_ID, key=os.environ["PK"])
    client.set_api_creds(client.create_or_derive_api_creds())

    # V2: fetch the authoritative book snapshot first.
    market = "0x7f8a...c12"  # condition id
    book = client.get_order_book(market)
    print("hash", book.hash)

    # Then open the WS stream and reconcile deltas by book hash.
    ws = await client.subscribe(channel="market", markets=[market])

    async for ev in ws:
        if ev["prev_hash"] != book.hash:
            await resync()
            continue
        apply_delta(book, ev)
        book.hash = ev["hash"]

if __name__ == "__main__":
    asyncio.run(main())
`;

// Terminal (home hero + chapter "run it" section)
const CH1_TERMINAL_TS = [
  { k: "cmd", text: "pnpm tsx 01-clob-client.ts" },
  { k: "muted", text: "» connecting to https://clob.polymarket.com" },
  { k: "muted", text: "» chain polygon-mainnet  rpc-ok  latency 41ms" },
  { k: "ok", text: "✓ handshake ok   api_key=pm_live_••••7f3a" },
  { k: "muted", text: "» GET /book  market=0x7f8a...c12" },
  { k: "ok", text: "✓ snapshot   hash=a91c3f   bids=128  asks=113" },
  { k: "muted", text: "» WS /ws/market  subscribe [0x7f8a...c12]" },
  { k: "ok", text: "✓ stream open   seq=0   prev_hash=a91c3f" },
  { k: "muted", text: "« book_update  seq=1  Δbid +0.004  Δask −0.003" },
  { k: "muted", text: "« book_update  seq=2  Δbid +0.001" },
  { k: "warn", text: "! hash drift  prev=a91c3f  got=c02e11  → resync()" },
  { k: "muted", text: "» GET /book  market=0x7f8a...c12" },
  { k: "ok", text: "✓ resync ok  hash=c02e11   lag=22ms" },
  { k: "muted", text: "« book_update  seq=42  Δbid ±6  Δask ±4" },
  { k: "idle", text: "" },
];

const CH1_TERMINAL_PY = [
  { k: "cmd", text: "python 01_clob_client.py" },
  { k: "muted", text: ">> connecting to https://clob.polymarket.com" },
  { k: "muted", text: ">> chain polygon-mainnet  rpc-ok  latency 38ms" },
  { k: "ok", text: "✓ handshake ok   api_key=pm_live_••••7f3a" },
  { k: "muted", text: ">> GET /book  market=0x7f8a...c12" },
  { k: "ok", text: "✓ snapshot   hash=a91c3f   bids=128  asks=113" },
  { k: "muted", text: ">> WS /ws/market  subscribe ['0x7f8a...c12']" },
  { k: "ok", text: "✓ stream open   seq=0   prev_hash=a91c3f" },
  { k: "muted", text: "<< book_update  seq=1  Δbid +0.004  Δask −0.003" },
  { k: "muted", text: "<< book_update  seq=2  Δbid +0.001" },
  { k: "warn", text: "! hash drift  prev=a91c3f  got=c02e11  -> resync()" },
  { k: "muted", text: ">> GET /book  market=0x7f8a...c12" },
  { k: "ok", text: "✓ resync ok  hash=c02e11   lag=29ms" },
  { k: "muted", text: "<< book_update  seq=42  Δbid ±6  Δask ±4" },
  { k: "idle", text: "" },
];

const INSTALL_TS = `pnpm add @polymarket/clob-client ethers`;
const INSTALL_PY = `pip install py-clob-client`;
