;; ---------------------------------------------------------------------------
;; Runners page
;; ---------------------------------------------------------------------------
(defcomp ()
  (~docs/page :title "Test Runners"
    (div (~tw :tokens "space-y-8")

      (div (~tw :tokens "space-y-4")
        (p (~tw :tokens "text-lg text-stone-600")
          "Three runners execute the same test specs on different hosts. Each injects the five platform functions and any per-spec extensions, then evaluates the SX source directly.")
        (p (~tw :tokens "text-stone-600")
          "All runners produce "
          (a :href "https://testanything.org/" (~tw :tokens "text-violet-700 underline") "TAP")
          " output and accept module names as arguments."))

      ;; Node.js runner
      (div (~tw :tokens "space-y-3")
        (h2 (~tw :tokens "text-2xl font-semibold text-stone-800") "Node.js: run.js")
        (div (~tw :tokens "rounded-lg border border-stone-200 bg-white p-5 space-y-3")
          (h3 (~tw :tokens "text-sm font-medium text-stone-500 uppercase tracking-wide") "Usage")
          (~docs/code :src
            (highlight "# Run all specs\nnode shared/sx/tests/run.js\n\n# Run specific specs\nnode shared/sx/tests/run.js eval parser\n\n# Legacy mode (monolithic test.sx)\nnode shared/sx/tests/run.js --legacy" "bash")))
        (p (~tw :tokens "text-stone-600 text-sm")
          "Uses "
          (code (~tw :tokens "text-violet-700 text-sm") "sx-browser.js")
          " as the evaluator. Router tests use bootstrapped functions from "
          (code (~tw :tokens "text-violet-700 text-sm") "Sx.splitPathSegments")
          " etc. Render tests use "
          (code (~tw :tokens "text-violet-700 text-sm") "Sx.renderToHtml")
          "."))

      ;; Python runner
      (div (~tw :tokens "space-y-3")
        (h2 (~tw :tokens "text-2xl font-semibold text-stone-800") "Python: run.py")
        (div (~tw :tokens "rounded-lg border border-stone-200 bg-white p-5 space-y-3")
          (h3 (~tw :tokens "text-sm font-medium text-stone-500 uppercase tracking-wide") "Usage")
          (~docs/code :src
            (highlight "# Run all specs\npython shared/sx/tests/run.py\n\n# Run specific specs\npython shared/sx/tests/run.py eval parser\n\n# Legacy mode (monolithic test.sx)\npython shared/sx/tests/run.py --legacy" "bash")))
        (p (~tw :tokens "text-stone-600 text-sm")
          "Uses the hand-written Python evaluator ("
          (code (~tw :tokens "text-violet-700 text-sm") "evaluator.py")
          "). Router tests import bootstrapped functions from "
          (code (~tw :tokens "text-violet-700 text-sm") "sx_ref.py")
          " because the hand-written evaluator's "
          (code (~tw :tokens "text-violet-700 text-sm") "set!")
          " doesn't propagate across lambda closure copies."))

      ;; Browser runner
      (div (~tw :tokens "space-y-3")
        (h2 (~tw :tokens "text-2xl font-semibold text-stone-800") "Browser: sx-test-runner.js")
        (p (~tw :tokens "text-stone-600")
          "Runs in the browser on each test page. The spec source is embedded in a hidden textarea; the runner parses and evaluates it using the same "
          (code (~tw :tokens "text-violet-700 text-sm") "sx-browser.js")
          " that renders the page itself.")
        (p (~tw :tokens "text-stone-600")
          "This is the strongest proof of cross-host parity — the browser evaluator that users depend on is the same one running the tests."))

      ;; Platform functions table
      (div (~tw :tokens "space-y-3")
        (h2 (~tw :tokens "text-2xl font-semibold text-stone-800") "Platform functions")
        (div (~tw :tokens "overflow-x-auto rounded border border-stone-200")
          (table (~tw :tokens "w-full text-left text-sm")
            (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
              (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Function")
              (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Scope")
              (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Purpose")))
            (tbody
              (tr (~tw :tokens "border-b border-stone-100")
                (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "try-call")
                (td (~tw :tokens "px-3 py-2") "All specs")
                (td (~tw :tokens "px-3 py-2 text-stone-700") "Call a thunk, catch errors, return result dict"))
              (tr (~tw :tokens "border-b border-stone-100")
                (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "report-pass")
                (td (~tw :tokens "px-3 py-2") "All specs")
                (td (~tw :tokens "px-3 py-2 text-stone-700") "Report a passing test"))
              (tr (~tw :tokens "border-b border-stone-100")
                (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "report-fail")
                (td (~tw :tokens "px-3 py-2") "All specs")
                (td (~tw :tokens "px-3 py-2 text-stone-700") "Report a failing test with error message"))
              (tr (~tw :tokens "border-b border-stone-100")
                (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "push-suite")
                (td (~tw :tokens "px-3 py-2") "All specs")
                (td (~tw :tokens "px-3 py-2 text-stone-700") "Push suite name onto context stack"))
              (tr (~tw :tokens "border-b border-stone-100")
                (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "pop-suite")
                (td (~tw :tokens "px-3 py-2") "All specs")
                (td (~tw :tokens "px-3 py-2 text-stone-700") "Pop suite name from context stack"))
              (tr (~tw :tokens "border-b border-stone-100")
                (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "sx-parse")
                (td (~tw :tokens "px-3 py-2") "Parser")
                (td (~tw :tokens "px-3 py-2 text-stone-700") "Parse SX source to AST"))
              (tr (~tw :tokens "border-b border-stone-100")
                (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "sx-serialize")
                (td (~tw :tokens "px-3 py-2") "Parser")
                (td (~tw :tokens "px-3 py-2 text-stone-700") "Serialize AST back to SX source text"))
              (tr (~tw :tokens "border-b border-stone-100")
                (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "render-html")
                (td (~tw :tokens "px-3 py-2") "Renderer")
                (td (~tw :tokens "px-3 py-2 text-stone-700") "Parse SX source and render to HTML string"))))))

      ;; Adding a new host
      (div (~tw :tokens "rounded-lg border border-blue-200 bg-blue-50 p-5 space-y-3")
        (h2 (~tw :tokens "text-lg font-semibold text-blue-900") "Adding a new host")
        (ol (~tw :tokens "list-decimal list-inside text-blue-800 space-y-2 text-sm")
          (li "Implement the 5 platform functions in your target language")
          (li "Load " (code (~tw :tokens "text-sm") "test-framework.sx") " — it defines deftest/defsuite macros")
          (li "Load the spec file(s) — the evaluator runs the tests automatically")
          (li "Add per-spec platform functions if testing parser or renderer")
          (li "Compare TAP output across hosts — divergences reveal platform-specific semantics"))))))
