// /sdk — SDK reference

const SDK_LANGS = [
  { id: "ts",     label: "TypeScript", letters: "Ts", color: "green" },
  { id: "rust",   label: "Rust",       letters: "Rs", color: "green" },
  { id: "python", label: "Python",     letters: "Py", color: "purple" },
  { id: "go",     label: "Go",         letters: "Go", color: "purple" },
];

const SDK_NAV = [
  { h: "Reference", items: [
    { id: "install",    label: "Install" },
    { id: "client",     label: "Client" },
    { id: "agentscan",  label: "agentScan()" },
    { id: "reposcan",   label: "repoScan()" },
    { id: "registry",   label: "registry" },
    { id: "providerhub",label: "providerHub" },
    { id: "events",     label: "Events" },
    { id: "types",      label: "Types" },
  ]},
  { h: "Examples", items: [
    { id: "ex-gate",    label: "Gating a swap" },
    { id: "ex-monitor", label: "Live monitor" },
    { id: "ex-attest",  label: "Verifying on-chain" },
  ]},
];

const TS_INSTALL = `pnpm add @lumiscan/sdk`;
const RUST_INSTALL = `cargo add lumiscan`;
const PY_INSTALL = `pip install lumiscan`;
const GO_INSTALL = `go get github.com/lumiscan/lumiscan-go`;

const CLIENT_TS = `import { Lumiscan } from "@lumiscan/sdk";

const lumi = new Lumiscan({
  cluster:  "mainnet-beta",
  apiKey:   process.env.LUMI_KEY,       // optional, raises rate limits
  oracle:   "trust1Oracle...8aF",        // pin a specific oracle keypair
});`;

const CLIENT_RUST = `use lumiscan::{Lumiscan, Cluster};

let lumi = Lumiscan::builder()
    .cluster(Cluster::MainnetBeta)
    .api_key(std::env::var("LUMI_KEY").ok())
    .build()?;`;

const CLIENT_PY = `from lumiscan import Lumiscan

lumi = Lumiscan(
    cluster="mainnet-beta",
    api_key=os.getenv("LUMI_KEY"),
)`;

const CLIENT_GO = `import "github.com/lumiscan/lumiscan-go"

lumi, _ := lumiscan.New(lumiscan.Config{
    Cluster: "mainnet-beta",
    APIKey:  os.Getenv("LUMI_KEY"),
})`;

const AGENT_TS = `const report = await lumi.agentScan({
  address: "sol1jit72b9k4...9xQ",
  depth:   "deep",
  battery: ["prompt", "signer", "tools"],
  timeout: 90_000,
});

// report.trustScore       → 72
// report.subScores        → { prompt: 78, signer: 84, tools: 62, treasury: 48 }
// report.findings         → Finding[]
// report.attestation.pda  → PublicKey
// report.signedAt         → Date`;

const AGENT_RUST = `let report = lumi
    .agent_scan()
    .address("sol1jit72b9k4...9xQ")
    .depth(Depth::Deep)
    .battery([Probe::Prompt, Probe::Signer, Probe::Tools])
    .await?;

println!("trust score: {}", report.trust_score);
for finding in &report.findings {
    eprintln!("{:?}  {}", finding.severity, finding.message);
}`;

const REPO_TS = `const audit = await lumi.repoScan({
  url:  "github.com/jito-foundation/agent-program",
  ref:  "main",          // branch | tag | commit sha
});

if (audit.authenticity < 70) {
  throw new Error("Refusing to fork suspicious repo");
}`;

const REG_TS = `// List, filter, paginate
const agents = await lumi.registry.list({
  minScore:   80,
  capability: "swap",
  sort:       "score:desc",
  limit:      50,
});

// Lookup one
const agent = await lumi.registry.get("sol1jit72b9k4...9xQ");

// Subscribe to updates
const off = lumi.registry.subscribe(agent => {
  if (agent.trustScore < 60) alert("agent demoted!", agent);
});`;

const HUB_TS = `// Register an endpoint
await lumi.providerHub.register({
  url:    "https://agent.driftprotocol.io/mcp",
  agent:  "drift-mm.agent",
  alerts: { discord: "https://discord.com/...", sla: 99.9 },
});

// Stream live metrics
for await (const m of lumi.providerHub.metrics("drift-mm.agent")) {
  console.log(m.p50, m.p99, m.errorsPerMin);
}`;

const EVENTS_TS = `lumi.on("agent.scored",     ev => /* ... */ );
lumi.on("agent.demoted",    ev => /* ... */ );
lumi.on("endpoint.down",    ev => /* ... */ );
lumi.on("endpoint.degraded",ev => /* ... */ );
lumi.on("registry.updated", ev => /* ... */ );`;

const TYPES_TS = `type TrustScore  = number;          // 0–100, integer
type Severity   = "info" | "warning" | "critical";
type Battery    = "prompt" | "signer" | "tools" | "treasury";

interface Finding {
  severity: Severity;
  kind:     string;     // stable taxonomy id, e.g. "TX-CONFUSE-001"
  message:  string;
  location: { file?: string; line?: number; instructionIx?: number };
}

interface AgentReport {
  trustScore:   TrustScore;
  subScores:    Record<Battery, TrustScore>;
  findings:     Finding[];
  signedAt:     Date;
  expiresAt:    Date;
  attestation:  { pda: string; signature: string; cluster: string };
}`;

const EX_GATE = `// Reject any swap routed through an agent below 80
async function safeSwap(agentAddr, amount) {
  const score = await lumi.registry.get(agentAddr)
                  .then(a => a?.trustScore ?? 0);

  if (score < 80) throw new Error("Agent below trust threshold");

  return solana.callAgent(agentAddr, "swap", { amount });
}`;

const EX_MONITOR = `// Live wall-board for an ops team
for await (const ev of lumi.stream(["endpoint.*", "agent.*"])) {
  if (ev.type === "endpoint.down") {
    discord.post(\`🚨 \${ev.url} is down · agent=\${ev.agent}\`);
  }
  if (ev.type === "agent.demoted") {
    pagerduty.trigger(\`⚠ \${ev.agent} dropped to \${ev.trustScore}\`);
  }
}`;

const EX_ATTEST = `// Verify a score directly from chain — no Lumiscan server needed
import { PublicKey, Connection } from "@solana/web3.js";

const [pda] = PublicKey.findProgramAddressSync(
  [Buffer.from("report"), agentPk.toBuffer()],
  LUMISCAN_PROGRAM_ID,
);

const account = await connection.getAccountInfo(pda);
const report  = decodeLumiReport(account.data);

if (report.score >= 80 && report.expiresAt > Date.now()/1000) {
  // safe to delegate
}`;

const CodeFor = ({ lang, snippets }) => {
  const s = snippets[lang] ?? snippets.ts ?? Object.values(snippets)[0];
  return <Pre code={s}/>;
};

// naive syntax highlighter for the snippets above
const Pre = ({ code }) => {
  const keywords = ["import","from","const","let","var","await","async","new","for","of","function","return","if","else","throw","interface","type","struct","use","let","mut","fn","pub","extern","class"];
  const lines = code.split("\n");
  return (
    <pre className="code-block">{lines.map((line, i) => {
      // comments first
      const cIdx = line.indexOf("//"); const rIdx = line.indexOf("#");
      const ci = cIdx >= 0 ? cIdx : (rIdx >= 0 && !line.includes("\"") ? rIdx : -1);
      let head = line, comment = "";
      if (ci >= 0 && !line.slice(0, ci).includes("\"")) {
        head = line.slice(0, ci); comment = line.slice(ci);
      }
      const tokens = head.split(/(\s+|[(){}[\],;:.<>=+])/g);
      return (
        <div key={i}>
          {tokens.map((t, k) => {
            if (/^"[^"]*"$/.test(t)) return <span key={k} className="s">{t}</span>;
            if (/^\d+(_\d+)*$/.test(t)) return <span key={k} className="n">{t}</span>;
            if (keywords.includes(t.trim())) return <span key={k} className="k">{t}</span>;
            return <span key={k}>{t}</span>;
          })}
          {comment && <span className="c">{comment}</span>}
        </div>
      );
    })}</pre>
  );
};

const SdkApp = () => {
  const [lang, setLang] = React.useState("ts");
  const [active, setActive] = React.useState("install");

  React.useEffect(() => {
    const ids = SDK_NAV.flatMap(g => g.items.map(i => i.id));
    const obs = new IntersectionObserver(entries => {
      entries.forEach(e => { if (e.isIntersecting) setActive(e.target.id); });
    }, { rootMargin: "-30% 0px -60% 0px", threshold: 0 });
    ids.forEach(id => { const el = document.getElementById(id); if (el) obs.observe(el); });
    return () => obs.disconnect();
  }, []);

  return (
    <>
      <Nav active="SDK"/>
      <div className="wrap doc-shell">
        <aside className="doc-side">
          <div style={{display:"flex", alignItems:"center", gap:8, marginBottom:18}}>
            <Icon name="code" size={14}/>
            <span className="serif" style={{fontSize:16}}>SDK reference</span>
          </div>
          {SDK_NAV.map(g => (
            <div key={g.h}>
              <div className="doc-side-h">{g.h}</div>
              {g.items.map(i => (
                <a key={i.id} href={`#${i.id}`} className={active === i.id ? "active" : ""}>{i.label}</a>
              ))}
            </div>
          ))}
          <div style={{marginTop: 24, padding: 14, border:"1px solid var(--border)", borderRadius:10}}>
            <div className="mono" style={{fontSize:11, color:"var(--text-muted)"}}>latest</div>
            <div className="serif" style={{fontSize:16, marginTop:4}}>@lumiscan/sdk</div>
            <div className="mono" style={{fontSize:11, color:"var(--green)", marginTop:4}}>v0.42.0</div>
          </div>
        </aside>

        <article className="doc-body">
          <span className="tag">v0.42 · TypeScript · Rust · Python · Go</span>
          <h1 className="serif" style={{marginTop:10}}>SDK <span className="serif-i">reference.</span></h1>
          <p>Typed bindings for every Lumiscan capability. Pick a language and the snippets below will retarget.</p>

          {/* language switcher */}
          <div className="tabs" style={{marginTop: 20}}>
            {SDK_LANGS.map(l => (
              <button key={l.id} className={`tab ${lang===l.id?"active":""}`} onClick={()=>setLang(l.id)}>
                <BrandIco letters={l.letters} color={l.color}/> {l.label}
              </button>
            ))}
          </div>

          <section id="install" style={{scrollMarginTop:90}}>
            <h2>Install</h2>
            <CodeFor lang={lang} snippets={{
              ts:     TS_INSTALL,   rust: RUST_INSTALL,
              python: PY_INSTALL,   go:   GO_INSTALL
            }}/>
          </section>

          <section id="client" style={{scrollMarginTop:90}}>
            <h2>Client</h2>
            <p>One client, all four products. The client is stateless — share it across requests.</p>
            <CodeFor lang={lang} snippets={{
              ts: CLIENT_TS, rust: CLIENT_RUST, python: CLIENT_PY, go: CLIENT_GO
            }}/>
          </section>

          <section id="agentscan" style={{scrollMarginTop:90}}>
            <h2><span className="serif-i">agent</span>Scan()</h2>
            <p>Probe a deployed Solana agent for vulnerabilities. Returns a signed report attested on-chain.</p>
            <CodeFor lang={lang} snippets={{ ts: AGENT_TS, rust: AGENT_RUST }}/>
            <h3>Parameters</h3>
            <ul style={{color:"var(--text-dim)", lineHeight:1.75, paddingLeft:22}}>
              <li><span className="inline-code">address</span> — agent program address or .agent name (required)</li>
              <li><span className="inline-code">depth</span> — <span className="inline-code">shallow</span> (10 tests) · <span className="inline-code">standard</span> (40) · <span className="inline-code">deep</span> (94)</li>
              <li><span className="inline-code">battery</span> — which probe families to run</li>
              <li><span className="inline-code">timeout</span> — abort after N ms (default 120_000)</li>
            </ul>
          </section>

          <section id="reposcan" style={{scrollMarginTop:90}}>
            <h2><span className="serif-i">repo</span>Scan()</h2>
            <p>Audit a Solana program or agent codebase for provenance, similarity, and authenticity.</p>
            <CodeFor lang={lang} snippets={{ ts: REPO_TS }}/>
          </section>

          <section id="registry" style={{scrollMarginTop:90}}>
            <h2>registry</h2>
            <p>Query the live registry of audited agents. Subscribe to changes.</p>
            <CodeFor lang={lang} snippets={{ ts: REG_TS }}/>
          </section>

          <section id="providerhub" style={{scrollMarginTop:90}}>
            <h2>providerHub</h2>
            <p>Register endpoints, stream uptime metrics, configure alerts.</p>
            <CodeFor lang={lang} snippets={{ ts: HUB_TS }}/>
          </section>

          <section id="events" style={{scrollMarginTop:90}}>
            <h2>Events</h2>
            <p>The client exposes a typed event bus so you can react to changes anywhere across Lumiscan.</p>
            <CodeFor lang={lang} snippets={{ ts: EVENTS_TS }}/>
          </section>

          <section id="types" style={{scrollMarginTop:90}}>
            <h2>Types</h2>
            <p>The most-used type definitions. Full surface is generated from the OpenAPI spec.</p>
            <CodeFor lang={lang} snippets={{ ts: TYPES_TS }}/>
          </section>

          <section id="ex-gate" style={{scrollMarginTop:90}}>
            <h2>Example · Gating a swap</h2>
            <p>Refuse to route swaps through agents that fall below your trust threshold:</p>
            <CodeFor lang="ts" snippets={{ ts: EX_GATE }}/>
          </section>

          <section id="ex-monitor" style={{scrollMarginTop:90}}>
            <h2>Example · Live monitor</h2>
            <p>Wire Lumiscan events to Discord and PagerDuty:</p>
            <CodeFor lang="ts" snippets={{ ts: EX_MONITOR }}/>
          </section>

          <section id="ex-attest" style={{scrollMarginTop:90}}>
            <h2>Example · Verifying on-chain</h2>
            <p>Verify a trust score directly from Solana — no Lumiscan server required:</p>
            <CodeFor lang="ts" snippets={{ ts: EX_ATTEST }}/>
            <p style={{marginTop: 48, padding:18, background:"var(--bg-elev)", border:"1px solid var(--border)", borderRadius:10, fontSize:13.5}}>
              ▸ Need protocol details, severity taxonomy, or the on-chain layout?
              See the <a href="docs.html" style={{color:"var(--green)"}}>documentation</a>.
            </p>
          </section>
        </article>
      </div>
      <Footer/>
    </>
  );
};

ReactDOM.createRoot(document.getElementById("root")).render(<SdkApp/>);
