#!/usr/bin/env bb
;; Vers-Duckhole: Traversable connection through duck conversation spacetime
;; 🦆🕳️ Like a wormhole, but for ducks
;; Usage:
;;   ./vers-duckhole.bb --serve              # Open the duckhole locally
;;   ./vers-duckhole.bb --deploy <vm-id>     # Deploy duckhole to vers VM
;;   ./vers-duckhole.bb --ngrok              # Tunnel through the duckhole
;;   ./vers-duckhole.bb --query <sql>        # Query across the duckhole

(require '[babashka.process :refer [shell process]]
         '[clojure.string :as str]
         '[cheshire.core :as json]
         '[babashka.fs :as fs]
         '[org.httpkit.server :as http])

;;; ============================================================
;;; Configuration
;;; ============================================================

(def PORT (or (some-> (System/getenv "PORT") parse-long) 8080))

(def DUCK_PATHS
  {:bootstrap (str (System/getProperty "user.home") "/.effective-topos/bootstrap.duckdb")
   :claude-db (str (System/getProperty "user.home") "/.claude/interactions.duckdb")
   :claude (str (System/getProperty "user.home") "/.claude/history.jsonl")
   :codex (str (System/getProperty "user.home") "/.codex/history.jsonl")
   :duck (str (System/getProperty "user.home") "/.duck/history.jsonl")
   :postduck (str (System/getProperty "user.home") "/.postduck/history.jsonl")})

;;; ============================================================
;;; DuckDB Integration
;;; ============================================================

(defn duck-query [db sql]
  (let [result (shell {:out :string :err :string :continue true}
                      "duckdb" db "-json" "-c" sql)]
    (if (= 0 (:exit result))
      {:ok true :data (try (json/parse-string (:out result) true)
                           (catch Exception _ (:out result)))}
      {:ok false :error (:err result)})))

(defn get-conversation-history [source limit]
  (let [path (get DUCK_PATHS (keyword source))]
    (if (and path (fs/exists? path))
      (duck-query ":memory:"
        (str "SELECT * FROM read_ndjson('" path "', ignore_errors=true) LIMIT " limit))
      {:ok false :error (str "Source not found: " source)})))

(defn get-vm-inventory []
  (duck-query (:bootstrap DUCK_PATHS)
    "SELECT vm_id, image_name, codex_version, created_at FROM vm_inventory ORDER BY created_at DESC"))

(defn get-unified-interactions [limit]
  (if (fs/exists? (:claude-db DUCK_PATHS))
    (duck-query (:claude-db DUCK_PATHS)
      (str "SELECT source, role, content, timestamp FROM unified_interactions ORDER BY timestamp DESC LIMIT " limit))
    {:ok false :error "interactions.duckdb not found"}))

;;; ============================================================
;;; Vers CLI Integration
;;; ============================================================

(defn vers-execute [vm-id cmd]
  (let [result (shell {:out :string :err :string :continue true}
                      "vers" "execute" vm-id cmd)]
    (if (= 0 (:exit result))
      {:ok true :output (:out result)}
      {:ok false :error (:err result)})))

(defn vers-list-aliases []
  (let [result (shell {:out :string :err :string :continue true}
                      "vers" "alias")]
    (if (= 0 (:exit result))
      {:ok true :aliases (str/split-lines (:out result))}
      {:ok false :error (:err result)})))

(defn deploy-to-vm [vm-id]
  (println (str "🚀 Deploying duck-web-viewer to VM " vm-id "..."))
  
  ;; Install dependencies
  (println "📦 Installing dependencies...")
  (vers-execute vm-id "pacman -Syu --noconfirm nodejs npm curl python python-pip 2>/dev/null || apt-get update && apt-get install -y nodejs npm curl python3 python3-pip")
  (vers-execute vm-id "curl -LsSf https://astral.sh/uv/install.sh | sh")
  (vers-execute vm-id "npm install -g nbb ai-agent-skills")
  (vers-execute vm-id "~/.local/bin/uv pip install --system duckdb textual rich")
  
  ;; Copy viewer script
  (println "📄 Copying duck-web-viewer...")
  (let [script (slurp "duck-web-viewer.cljs")]
    (vers-execute vm-id (str "cat > /app/duck-web-viewer.cljs << 'EOF'\n" script "\nEOF")))
  
  ;; Start server
  (println "🌐 Starting server...")
  (vers-execute vm-id "nohup nbb /app/duck-web-viewer.cljs > /var/log/duck-viewer.log 2>&1 &")
  
  (println (str "✅ Deployed! Access via: ssh -L 8080:localhost:8080 " vm-id ".vm.vers.sh")))

;;; ============================================================
;;; HTTP Server (local)
;;; ============================================================

(defn html-wrap [title content]
  (str "<!DOCTYPE html>
<html>
<head>
  <title>" title "</title>
  <style>
    body { font-family: monospace; background: #0a0a0f; color: #e0e0e0; padding: 2rem; }
    h1 { color: #26d826; }
    h2 { color: #4ecdc4; }
    pre { background: #1a1a2e; padding: 1rem; border-radius: 4px; overflow-x: auto; }
    table { border-collapse: collapse; width: 100%; }
    th, td { border: 1px solid #333; padding: 0.5rem; text-align: left; }
    th { background: #1a1a2e; color: #26d826; }
    a { color: #4ecdc4; }
    .nav a { margin-right: 1rem; padding: 0.5rem 1rem; background: #1a1a2e; border-radius: 4px; text-decoration: none; }
    .entry { background: #16213e; margin: 0.5rem 0; padding: 1rem; border-radius: 4px; border-left: 3px solid #26d826; }
  </style>
</head>
<body>
  <div class='nav'>
    <a href='/'>Home</a>
    <a href='/conversations?source=claude'>Claude</a>
    <a href='/conversations?source=codex'>Codex</a>
    <a href='/vms'>VMs</a>
    <a href='/health'>Health</a>
  </div>
  " content "
</body></html>"))

(defn handler [{:keys [uri query-string]}]
  (let [params (when query-string
                 (->> (str/split query-string #"&")
                      (map #(str/split % #"="))
                      (into {})))]
    (cond
      (= uri "/")
      {:status 200
       :headers {"Content-Type" "text/html"}
       :body (html-wrap "Duck Viewer"
               "<h1>🦆 Duck Conversation Viewer</h1>
                <p>Vers CLI pathway to duck conversation history</p>
                <h2>Endpoints</h2>
                <ul>
                  <li><a href='/conversations?source=claude&limit=20'>Claude History</a></li>
                  <li><a href='/conversations?source=codex&limit=20'>Codex History</a></li>
                  <li><a href='/conversations?source=duck&limit=20'>Duck History</a></li>
                  <li><a href='/vms'>VM Inventory</a></li>
                  <li><a href='/unified?limit=20'>Unified Interactions</a></li>
                </ul>")}

      (= uri "/health")
      {:status 200
       :headers {"Content-Type" "application/json"}
       :body (json/generate-string
               {:status "ok"
                :duckdb (fs/exists? (:bootstrap DUCK_PATHS))
                :claude (fs/exists? (:claude DUCK_PATHS))
                :codex (fs/exists? (:codex DUCK_PATHS))
                :timestamp (str (java.time.Instant/now))})}

      (= uri "/conversations")
      (let [source (or (get params "source") "claude")
            limit (or (get params "limit") "20")
            result (get-conversation-history source limit)]
        {:status 200
         :headers {"Content-Type" "text/html"}
         :body (html-wrap (str source " History")
                 (if (:ok result)
                   (str "<h1>" source " History</h1>"
                        "<p>" (count (:data result)) " entries</p>"
                        (str/join "\n"
                          (map (fn [e]
                                 (str "<div class='entry'><pre>"
                                      (subs (pr-str e) 0 (min 500 (count (pr-str e))))
                                      "...</pre></div>"))
                               (:data result))))
                   (str "<pre>Error: " (:error result) "</pre>")))})

      (= uri "/vms")
      (let [result (get-vm-inventory)]
        {:status 200
         :headers {"Content-Type" "text/html"}
         :body (html-wrap "VMs"
                 (if (:ok result)
                   (str "<h1>VM Inventory</h1>"
                        "<table><tr><th>VM ID</th><th>Image</th><th>Codex</th></tr>"
                        (str/join "\n"
                          (map (fn [vm]
                                 (str "<tr><td>" (:vm_id vm) "</td>"
                                      "<td>" (:image_name vm) "</td>"
                                      "<td>" (:codex_version vm) "</td></tr>"))
                               (:data result)))
                        "</table>")
                   (str "<pre>Error: " (:error result) "</pre>")))})

      (= uri "/api/query")
      (let [sql (get params "sql")
            db (or (get params "db") ":memory:")
            result (duck-query db sql)]
        {:status 200
         :headers {"Content-Type" "application/json"}
         :body (json/generate-string result)})

      :else
      {:status 404 :body "Not Found"})))

(defn start-server []
  (println (str "🦆🕳️ Opening duckhole at http://localhost:" PORT))
  (http/run-server handler {:port PORT})
  (println "✅ Server running. Press Ctrl+C to stop.")
  @(promise))

;;; ============================================================
;;; Main
;;; ============================================================

(defn -main [& args]
  (let [cmd (first args)]
    (case cmd
      "--serve" (start-server)
      
      "--deploy" (if-let [vm-id (second args)]
                   (deploy-to-vm vm-id)
                   (println "Usage: --deploy <vm-id>"))
      
      "--ngrok" (do
                  (println "🔗 Starting with ngrok...")
                  (future (shell "ngrok" "http" (str PORT)))
                  (Thread/sleep 2000)
                  (start-server))
      
      "--query" (let [sql (str/join " " (rest args))
                      result (duck-query ":memory:" sql)]
                  (println (json/generate-string result {:pretty true})))
      
      "--vms" (let [result (get-vm-inventory)]
                (doseq [vm (:data result)]
                  (println (str (:vm_id vm) " | " (:image_name vm) " | " (:codex_version vm)))))
      
      (do
        (println "🦆🕳️ vers-duckhole - like a wormhole, but for ducks")
        (println)
        (println "Usage: vers-duckhole.bb [command]")
        (println)
        (println "Commands:")
        (println "  --serve           Open the duckhole locally")
        (println "  --deploy <vm-id>  Deploy duckhole to vers VM")
        (println "  --ngrok           Tunnel through the duckhole")
        (println "  --query <sql>     Query across the duckhole")
        (println "  --vms             List VMs visible through duckhole")))))

(apply -main *command-line-args*)