import { pageMeta } from "../../meta"
import { CodeBlock } from "../../highlight"

// Pure content page — no React interactivity (TOC/copy/search are the layout enhancer +
// the Nira island), so ship zero framework JS and avoid hydrating the inline-script DOM.
export const hydrate = false

export const meta = pageMeta(
  "Nifra — Deployment",
  "One Nifra app, one command per target — Bun, Node (Docker), Deno Deploy, Cloudflare Pages, Vercel Edge.",
)

const SCAFFOLD = `# Scaffold the multi-target site with a chosen default deploy target:
bun create nifra my-app --deploy vercel     # or: bun | node | deno | cf-pages
# add --framework to pick the UI too (react default):
bun create nifra my-app --framework svelte --deploy vercel

cd my-app && bun install
bun run dev       # local preview
bun run build     # builds for the chosen target
bun run deploy    # runs that target's deploy CLI (you stay logged-in to the vendor)

# Or add --ci github to also emit a deploy-on-push GitHub Actions workflow:
bun create nifra my-app --deploy cf-pages --ci github
#   → .github/workflows/deploy.yml (builds on every push/PR, deploys on push to main)`

const CF = `// _worker.ts — the edge SSR entry
import { toFetchHandler } from "@nifrajs/core"
import { createWebApp } from "@nifrajs/web"
import { reactAdapter } from "@nifrajs/web-react"
import { clientEntry, manifest } from "./server-manifest"  // generated by buildServer

const app = createWebApp({ adapter: reactAdapter, manifest, clientEntry })
export default toFetchHandler(app)   // a Workers/Pages fetch handler

// build.ts — buildClient (→ /assets) + buildServer (edge conditions → _worker.js)
import { buildClient, buildServer } from "@nifrajs/web/build"`

export default function Deployment() {
  return (
    <div className="prose">
      <h1 className="page">Deployment</h1>
      <p className="lead">
        <code>app.fetch(request)</code> is a pure Web-standard handler, so the same app runs
        anywhere. Pick a runtime; the code doesn't change.
      </p>

      <h2>One command per target</h2>
      <p>
        <code>create-nifra</code>'s <code>site</code> template ships every target's build + server entry
        and config. Pass <code>--deploy &lt;target&gt;</code> to make one the default — it points{" "}
        <code>build</code>/<code>deploy</code> at that target and fills in your project name. The
        per-target <code>build:*</code>/<code>deploy:*</code> scripts stay, so you can switch any time.
      </p>
      <CodeBlock code={SCAFFOLD} />
      <table>
        <thead>
          <tr>
            <th>target</th>
            <th>build →</th>
            <th>deploy</th>
            <th>config scaffolded</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>Bun (flagship)</td>
            <td>
              <code>dist-bun/</code>
            </td>
            <td>
              <code>bun run start</code> (any host)
            </td>
            <td>—</td>
          </tr>
          <tr>
            <td>Node</td>
            <td>
              <code>dist-node/</code>
            </td>
            <td>
              <code>docker build … && docker run</code>
            </td>
            <td>
              <code>Dockerfile</code> + <code>.dockerignore</code>
            </td>
          </tr>
          <tr>
            <td>Deno Deploy</td>
            <td>
              <code>dist-deno/</code>
            </td>
            <td>
              <code>deployctl deploy</code>
            </td>
            <td>
              <code>deno.json</code>
            </td>
          </tr>
          <tr>
            <td>Cloudflare Pages</td>
            <td>
              <code>dist/</code>
            </td>
            <td>
              <code>wrangler pages deploy</code>
            </td>
            <td>
              <code>wrangler.toml</code>
            </td>
          </tr>
          <tr>
            <td>Vercel Edge</td>
            <td>
              <code>.vercel/output/</code>
            </td>
            <td>
              <code>vercel deploy --prebuilt</code>
            </td>
            <td>Build Output API v3</td>
          </tr>
        </tbody>
      </table>
      <p>
        Nifra never runs the deploy or enters your cloud credentials — it scaffolds the config + a{" "}
        <code>deploy</code> script that shells out to the vendor CLI you've already authed.
      </p>

      <h2>CI: deploy on push</h2>
      <p>
        Add <code>--ci github</code> to emit a <code>.github/workflows/deploy.yml</code> tuned to the
        chosen target — it builds on every push/PR and deploys on a push to <code>main</code>.{" "}
        <b>cf-pages</b> uses <code>cloudflare/wrangler-action</code>, <b>vercel</b> the prebuilt{" "}
        <code>vercel deploy</code>, <b>deno</b> <code>deployctl</code> (OIDC). The workflow's header
        comment lists the exact repo secrets to set (e.g. <code>CLOUDFLARE_API_TOKEN</code>,{" "}
        <code>VERCEL_TOKEN</code>). Self-hosted <b>bun</b>/<b>node</b> have no universal push-to-deploy,
        so their workflow builds + uploads the bundle as an artifact and leaves a clearly-marked,
        host-specific deploy step for you to fill in (Fly, a registry push, SSH, …).
      </p>

      <h2>Bun (its home)</h2>
      <p>
        <code>app.listen(3000)</code> — the native Bun server. Sits at the raw <code>Bun.serve</code>{" "}
        ceiling (see <a href="/benchmarks">benchmarks</a>).
      </p>
      <p>
        <strong>Every core:</strong> Bun is single-threaded per process — for multi-core boxes,
        spawn one process per core, each binding the same port with{" "}
        <code>app.listen(PORT, {"{ reusePort: true }"})</code>; the kernel load-balances connections
        across them (Linux balances ~evenly). A supervisor that spawns + restarts workers is ~20
        lines — see <code>examples/cluster.ts</code>. Anything shared across workers (rate limits,
        sessions, pub/sub) needs a shared store, as in any multi-instance deploy.
      </p>

      <h2>Node &amp; Deno</h2>
      <ul>
        <li>
          <code>@nifrajs/node</code> — <code>serve(app, {"{ port }"})</code> bridges to <code>node:http</code>.
        </li>
        <li>
          <code>@nifrajs/deno</code> — serves <code>app.fetch</code> on <code>Deno.serve</code>.
        </li>
      </ul>
      <p>
        Self-hosting (no CDN in front)? Hand <code>@nifrajs/node</code>'s <code>serve</code> a{" "}
        <code>static</code> mount and it serves the client bundle from disk — traversal-guarded,
        content-typed, with an immutable cache — before the app runs, leaving the SSR fast path
        untouched: <code>serve(app, {'{ port, static: { dir: new URL("./assets/", import.meta.url) } }'})</code>.
        On Cloudflare/Vercel the platform serves assets, so you don't need it there.
      </p>

      <h2>Cloudflare Workers / Pages (the edge)</h2>
      <p>
        <code>buildServer</code> bundles with edge conditions (<code>workerd</code>,{" "}
        <code>edge-light</code>) into a <code>_worker.js</code>; <code>toFetchHandler(app)</code> is
        the handler. For Pages, a <code>_routes.json</code> serves the client bundle statically.
        SSR verified on real workerd — <b>this very site runs there</b>.
      </p>
      <CodeBlock code={CF} />
      <p>
        Deploy: <code>wrangler pages deploy dist</code> (Pages) or <code>wrangler deploy</code>{" "}
        (Workers). Deno Deploy and Vercel Edge reuse the same build with their conditions.
      </p>
    </div>
  )
}
