;; GraphQL: executor — live execute against /api.execute-demo
(defcomp
  ()
  (~docs/page
    :title "GraphQL · Executor"
    (p
      (~tw :tokens "text-lg text-gray-600 mb-2")
      "The executor in "
      (code "lib/graphql-exec.sx")
      " walks the parsed AST, dispatches root fields to a resolver, "
      "and projects each result down to the selected fields.")
    (p
      (~tw :tokens "text-gray-500 mb-6")
      "The endpoint below uses a static seed dataset (users, posts, comments) "
      "and a resolver written in plain SX. The same bytecode runs the docs site test suite.")
    (~docs/section
      :title "Seed data"
      :id "seed"
      (p
        (~tw :tokens "text-gray-600 mb-3")
        "Three tables, hardcoded in the handler file. No database required — "
        "every query and mutation hits this in-memory store.")
      (~docs/code
        :src "(define gql-seed-users\n  (list\n    {:id 1 :name \"Alice\" :email \"alice@test.com\" :role \"admin\"}\n    {:id 2 :name \"Bob\"   :email \"bob@test.com\"   :role \"user\"}\n    {:id 3 :name \"Carol\" :email \"carol@test.com\" :role \"user\"}))\n\n(define gql-seed-posts\n  (list\n    {:id 101 :authorId 1 :title \"Hello, world\"   :body \"First post in SX GraphQL.\"}\n    {:id 102 :authorId 2 :title \"GraphQL in SX\"  :body \"Every op compiles to bytecode.\"}\n    {:id 103 :authorId 1 :title \"Quiet night\"    :body \"Just thinking about parsers.\"}))\n\n(define gql-seed-comments\n  (list\n    {:id 1001 :postId 101 :authorId 2 :text \"Nice one.\"}\n    {:id 1002 :postId 102 :authorId 3 :text \"Compiled to bytecode?!\"}\n    {:id 1003 :postId 102 :authorId 1 :text \"Yes — every op is CEK.\"}))"))
    (~docs/section
      :title "Resolver"
      :id "resolver"
      (p
        (~tw :tokens "text-gray-600 mb-3")
        "The resolver receives "
        (code "(field-name args-dict op-type)")
        " per root field. Return a scalar, a dict, or a list of dicts — "
        "the executor projects it down to the requested selection set.")
      (~docs/code
        :src "(define gql-seed-resolve\n  (fn (field-name args op-type)\n    (cond\n      ((= field-name \"user\")\n        (gql-find-by-id gql-seed-users (get args :id)))\n      ((= field-name \"users\") gql-seed-users)\n      ((= field-name \"post\")\n        (gql-find-by-id gql-seed-posts (get args :id)))\n      ((= field-name \"posts\")\n        (let ((author-id (get args :authorId)))\n          (if author-id\n            (gql-filter-by gql-seed-posts :authorId author-id)\n            gql-seed-posts)))\n      ((= field-name \"comments\")\n        (let ((post-id (get args :postId)))\n          (if post-id\n            (gql-filter-by gql-seed-comments :postId post-id)\n            gql-seed-comments)))\n      ((= field-name \"echo\") (get args :message))\n      ((= field-name \"createPost\")\n        {:id 999\n         :title (get args :title)\n         :body (get args :body)\n         :authorId (get args :authorId)})\n      ((= field-name \"likePost\")\n        {:id (get args :id) :liked true})\n      (true nil))))"))
    (~docs/section
      :title "Live endpoint"
      :id "endpoint"
      (p
        (~tw :tokens "text-gray-600 mb-3")
        "POST "
        (code "/sx/(applications.(graphql.(api.execute-demo)))")
        " with form fields "
        (code "query")
        " and optional "
        (code "variables")
        " (an SX dict literal like "
        (code "{:id 1}")
        ").")
      (~docs/code
        :src "(defhandler\n  gql-execute-demo\n  :path \"/sx/(applications.(graphql.(api.execute-demo)))\"\n  :method :post\n  :csrf false\n  :returns \"text\"\n  (&key query variables)\n  (let ((doc (gql-parse query))\n        (vars-dict (gql-parse-vars variables)))\n    (let ((result (gql-execute doc vars-dict gql-seed-resolve)))\n      (str\n        \"<pre>\" (escape (sx-serialize vars-dict)) \"</pre>\"\n        \"<pre>\" (escape (sx-serialize result)) \"</pre>\")))))"))
    (~docs/section
      :title "Try it"
      :id "try"
      (p
        (~tw :tokens "text-gray-600 mb-3")
        "The query is sent straight to the handler; the result is projected to your selection set.")
      (form
        (~tw :tokens "space-y-3")
        :hx-post "/sx/(applications.(graphql.(api.execute-demo)))"
        :hx-target "#exec-out"
        :hx-swap "innerHTML"
        (label
          (~tw :tokens "block text-sm font-medium text-gray-700")
          "Query")
        (textarea
          :name "query"
          :rows "7"
          (~tw
            :tokens "w-full font-mono text-sm p-3 border border-gray-300 rounded-lg")
          "query Q($id: ID!) {\n  post(id: $id) {\n    title\n    body\n    authorId\n  }\n}")
        (label
          (~tw :tokens "block text-sm font-medium text-gray-700")
          "Variables")
        (textarea
          :name "variables"
          :rows "2"
          (~tw
            :tokens "w-full font-mono text-sm p-3 border border-gray-300 rounded-lg")
          "{:id 102}")
        (button
          :type "submit"
          (~tw
            :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700")
          "Execute"))
      (div
        :id "exec-out"
        (~tw :tokens "mt-4")
        (span
          (~tw :tokens "text-gray-400 text-sm")
          "Variables + result will appear here.")))))
