#!/usr/bin/env bb
;; ๐Ÿฆ† duck.bb - The duck inhabits all forms
;; One command: `just duck` or `bb duck.bb`
;; Shows Toad first, passes API keys, handles the rest

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

;;; ============================================================
;;; Toad-Supported API Keys (detect locally, pass to VM)
;;; ============================================================

(def TOAD_API_KEYS
  "API keys that Toad/ACP agents can use"
  [:OPENAI_API_KEY
   :ANTHROPIC_API_KEY
   :GOOGLE_API_KEY
   :MISTRAL_API_KEY
   :GROQ_API_KEY
   :TOGETHER_API_KEY
   :FIREWORKS_API_KEY
   :DEEPSEEK_API_KEY
   :XAI_API_KEY
   :COHERE_API_KEY
   :PERPLEXITY_API_KEY
   :REPLICATE_API_TOKEN
   :HUGGINGFACE_API_KEY
   :VOYAGE_API_KEY
   :ELEVENLABS_API_KEY
   :NGROK_AUTHTOKEN
   :VERS_API_KEY])

(defn detect-api-keys []
  "Detect which API keys are available locally"
  (->> TOAD_API_KEYS
       (map (fn [k] [k (System/getenv (name k))]))
       (filter (fn [[_ v]] (and v (not (str/blank? v)))))
       (into {})))

(defn format-env-exports [keys-map]
  "Format API keys as export statements for VM"
  (->> keys-map
       (map (fn [[k v]] (str "export " (name k) "='" v "'")))
       (str/join " && ")))

;;; ============================================================
;;; VM Discovery
;;; ============================================================

(def DUCK_DB_PATH 
  (str (System/getProperty "user.home") "/.effective-topos/bootstrap.duckdb"))

(defn get-default-vm []
  "Get the most recent VM from inventory"
  (let [result (shell {:out :string :err :string :continue true}
                      "duckdb" DUCK_DB_PATH "-json" "-c"
                      "SELECT vm_id FROM vm_inventory ORDER BY created_at DESC LIMIT 1")]
    (when (= 0 (:exit result))
      (-> (:out result)
          (json/parse-string true)
          first
          :vm_id))))

(defn get-vm-from-alias [alias]
  "Resolve alias to VM ID"
  (let [result (shell {:out :string :err :string :continue true}
                      "vers" "alias" alias)]
    (when (= 0 (:exit result))
      (str/trim (:out result)))))

(defn get-all-vms []
  "Get all VMs from inventory"
  (let [result (shell {:out :string :err :string :continue true}
                      "duckdb" DUCK_DB_PATH "-json" "-c"
                      "SELECT vm_id FROM vm_inventory")]
    (when (= 0 (:exit result))
      {:data (json/parse-string (:out result) true)})))

;;; ============================================================
;;; Toad Launcher
;;; ============================================================

(def TOAD_BANNER
  "
๐Ÿธโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•๐Ÿธ
โ•‘                                                                             โ•‘
โ•‘   โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—                                        โ•‘
โ•‘   โ•šโ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—                                       โ•‘
โ•‘      โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘                                       โ•‘
โ•‘      โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘                                       โ•‘
โ•‘      โ–ˆโ–ˆโ•‘   โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•                                       โ•‘
โ•‘      โ•šโ•โ•    โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•  โ•šโ•โ•โ•šโ•โ•โ•โ•โ•โ•                                        โ•‘
โ•‘                                                                             โ•‘
โ•‘   ๐Ÿฆ† The duck inhabits the toad                                            โ•‘
โ•‘                                                                             โ•‘
๐Ÿธโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•๐Ÿธ
")

(defn show-toad-banner []
  (println TOAD_BANNER))

(defn start-toad-in-vm [vm-id api-keys]
  "Start Toad TUI in VM with API keys injected"
  (let [env-exports (when (seq api-keys) (format-env-exports api-keys))
        key-count (count api-keys)
        detected-names (str/join ", " (map name (keys api-keys)))]
    
    (show-toad-banner)
    (println (str "๐Ÿ”‘ Detected " key-count " API keys: " (if (seq detected-names) detected-names "none")))
    (println (str "๐Ÿ–ฅ๏ธ  VM: " vm-id))
    (println "")
    
    ;; Inject keys and start Toad
    (let [cmd (if (seq env-exports)
                (str env-exports " && toad 2>/dev/null || python -m textual run toad:app 2>/dev/null || nbb /app/entrypoint.cljs")
                "toad 2>/dev/null || python -m textual run toad:app 2>/dev/null || nbb /app/entrypoint.cljs")]
      (shell "vers" "execute" vm-id cmd))))

(defn connect-to-toad [vm-id api-keys]
  "Connect to VM with Toad as first experience"
  (let [env-exports (when (seq api-keys) (format-env-exports api-keys))
        key-count (count api-keys)]
    
    (show-toad-banner)
    (println (str "๐Ÿ”‘ Passing " key-count " API keys to VM"))
    (println (str "๐Ÿ–ฅ๏ธ  Connecting to: " vm-id))
    (println "")
    
    ;; Connect and inject env vars via execute first, then connect
    (when (seq env-exports)
      (shell {:continue true} "vers" "execute" vm-id 
             (str "cat >> /etc/environment << 'KEYS'\n"
                  (str/join "\n" (map (fn [[k v]] (str (name k) "=" v)) api-keys))
                  "\nKEYS")))
    (shell "vers" "connect" vm-id)))

;;; ============================================================
;;; Duckhole Server (web interface)
;;; ============================================================

(defn start-duckhole-server [port]
  "Start the duckhole web server locally"
  (println "๐Ÿฆ†๐Ÿ•ณ๏ธ Opening duckhole...")
  (load-file (str (fs/parent *file*) "/vers-duckhole.bb"))
  ;; Server starts via loaded file
  )

;;; ============================================================
;;; Chelsea Image Registration
;;; ============================================================

(def TOAD_IMAGE_NAME "toad-acp")
(def TOAD_IMAGE_SIZE 16384) ;; 16 GiB

(defn register-toad-image []
  "Register toad-acp as Chelsea custom image"
  (println "๐Ÿธ Registering Toad ACP image with Chelsea...")
  (let [api-url (or (System/getenv "VERS_API_URL") "https://api.vers.sh")
        api-key (System/getenv "VERS_API_KEY")
        body (json/generate-string
               {:image_name TOAD_IMAGE_NAME
                :source {:docker {:image_ref "bmorphism/toad-acp:latest"}}
                :size_mib TOAD_IMAGE_SIZE})]
    (if api-key
      (let [result (shell {:out :string :err :string :continue true}
                          "curl" "-sS" "-X" "POST"
                          (str api-url "/api/images/create")
                          "-H" (str "Authorization: Bearer " api-key)
                          "-H" "Content-Type: application/json"
                          "-d" body)]
        (if (= 0 (:exit result))
          (do
            (println "โœ… Image registration initiated")
            (println (:out result)))
          (println (str "โŒ Failed: " (:err result)))))
      (println "โŒ VERS_API_KEY not set"))))

(defn carnage! []
  "Delete ALL VMs - the duck consumes all"
  (println "")
  (println "  โ›ง โธธ ๊™ฎ  C A R N A G E  ๊™ฎ โธธ โ›ง")
  (println "  โ–‘โ–’โ–“โ–ˆ ๐’€ญ ๐’Œ‹ ๐’น ๐’€ฑ โ–ˆโ–“โ–’โ–‘")
  (println "")
  (println "  ยซ La terreur n'est autre chose que la justice,")
  (println "    prompte, sรฉvรจre, inflexible. ยป")
  (println "                          โ€” Robespierre, 1794")
  (println "")
  (let [vms (get-all-vms)
        glyphs ["เผ’" "เฟ‡" "แฏพ" "โŸ" "โŽˆ" "โŒฌ" "โฃ" "โš" "โœง" "โ‹"]]
    (if (seq (:data vms))
      (do
        (println (str "  โŒ– " (count (:data vms)) " VMs marked for dissolution..."))
        (println "")
        (doseq [[idx {:keys [vm_id]}] (map-indexed vector (:data vms))]
          (let [g (nth glyphs (mod idx (count glyphs)))]
            (println (str "  " g " โŸฟ " (subs vm_id 0 8) "โ€ฆ "))
            (shell {:continue true} "vers" "delete" vm_id)))
        (println "")
        (println "  โ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–šโ–žโ–š")
        (println "")
        (println "  ยซ Celui qui cherche ร  comprendre n'aura de cesse")
        (println "    de revenir aux sources, aussi souvent qu'il le faudra,")
        (println "    jusqu'ร  y boire sans soif. ยป")
        (println "                          โ€” Grothendieck, Rรฉcoltes et Semailles")
        (println "")
        (println "  ๊™ฎ Le vide fertile attend. ๊™ฎ")
        (println ""))
      (println "  โˆ… No VMs found. The void is already here."))))

(defn build-toad-image []
  "Build toad-acp Docker image using Apple container CLI"
  (println "๐Ÿธ Building Toad ACP image...")
  (let [dockerfile (str (fs/parent *file*) "/Duckerfile")
        context (str (fs/parent *file*))]
    ;; Try Apple container CLI first, fallback to docker
    (let [result (shell {:continue true} "container" "build" "--arch" "amd64" 
                        "-t" "toad-acp:latest" 
                        "-f" dockerfile context)]
      (if (= 0 (:exit result))
        (println "โœ… Image built with Apple container CLI")
        ;; Fallback to docker
        (do
          (println "Trying docker...")
          (shell "docker" "build" "--platform" "linux/amd64" 
                 "-t" "toad-acp:latest" 
                 "-f" dockerfile context))))))

;;; ============================================================
;;; Main: The Duck Decides Its Form
;;; ============================================================

(defn print-usage []
  (println "
๐Ÿฆ† duck - the duck inhabits all forms

Usage: just duck [command] [args...]

Commands:
  (no args)     Connect to default VM with Toad (passes API keys)
  <vm-id>       Connect to specific VM with Toad
  serve         Start local duckhole web server
  ngrok         Start duckhole with ngrok tunnel
  vms           List VMs visible through duckhole
  query <sql>   Query across the duckhole
  keys          Show detected API keys (redacted)
  build         Build toad-acp Docker image
  register      Register toad-acp with Chelsea
  carnage       Delete ALL VMs (careful!)
  
API Keys Detected:
")
  (let [keys (detect-api-keys)]
    (if (seq keys)
      (doseq [[k _] keys]
        (println (str "  โœ… " (name k))))
      (println "  (none found in environment)"))))

(defn -main [& args]
  (let [cmd (first args)
        api-keys (detect-api-keys)]
    (cond
      ;; No args: connect to default VM with Toad
      (nil? cmd)
      (if-let [vm-id (get-default-vm)]
        (connect-to-toad vm-id api-keys)
        (do
          (println "โŒ No VM found. Create one first:")
          (println "   vers run")
          (System/exit 1)))
      
      ;; Looks like a VM ID (UUID pattern)
      (re-matches #"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" cmd)
      (connect-to-toad cmd api-keys)
      
      ;; Looks like a short VM ID prefix - expand it
      (re-matches #"[0-9a-f]{6,12}" cmd)
      (if-let [full-id (first (filter #(str/starts-with? % cmd) 
                                       (map :vm_id (:data (get-all-vms)))))]
        (connect-to-toad full-id api-keys)
        (do
          (println (str "โŒ No VM found matching: " cmd))
          (System/exit 1)))
      
      ;; serve / hole
      (contains? #{"serve" "hole" "web"} cmd)
      (do
        (show-toad-banner)
        (shell "bb" (str (fs/parent *file*) "/vers-duckhole.bb") "--serve"))
      
      ;; ngrok / through
      (contains? #{"ngrok" "through" "tunnel"} cmd)
      (do
        (show-toad-banner)
        (shell "bb" (str (fs/parent *file*) "/vers-duckhole.bb") "--ngrok"))
      
      ;; vms
      (= cmd "vms")
      (shell "bb" (str (fs/parent *file*) "/vers-duckhole.bb") "--vms")
      
      ;; query
      (= cmd "query")
      (shell "bb" (str (fs/parent *file*) "/vers-duckhole.bb") "--query" (str/join " " (rest args)))
      
      ;; keys
      (= cmd "keys")
      (do
        (println "๐Ÿ”‘ Detected API Keys:")
        (if (seq api-keys)
          (doseq [[k v] api-keys]
            (println (str "  " (name k) ": " (subs v 0 (min 8 (count v))) "...")))
          (println "  (none found)")))
      
      ;; build
      (= cmd "build")
      (build-toad-image)
      
      ;; register
      (= cmd "register")
      (register-toad-image)
      
      ;; carnage
      (= cmd "carnage")
      (carnage!)
      
      ;; help
      (contains? #{"-h" "--help" "help"} cmd)
      (print-usage)
      
      ;; Unknown: treat as VM alias
      :else
      (if-let [vm-id (get-vm-from-alias cmd)]
        (connect-to-toad vm-id api-keys)
        (do
          (println (str "Unknown command or VM: " cmd))
          (print-usage)
          (System/exit 1))))))

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