;;; proof-netspace-client.lsp — query the proof netspace server.
;;;
;;; Three passes:
;;;
;;;   1. Verify each of five EML theorems per-proof (PROVEN / UNKNOWN).
;;;   2. Fetch the whole envelope — the server's full solution space
;;;      ships back in one round-trip as (envelope (h1 h2 ...)).
;;;   3. Merge our own envelope back + one synthetic hash. Server
;;;      reports (merged 1) proving the synthetic was the only new
;;;      entry and the rest were already known.
;;;
;;; Two nodes can chain (envelope) + (merge ...) in either direction
;;; until both hold the union of what either knew.
;;;
;;; Usage (start the server first):
;;;   python3 lumbda.py --fast examples/proof-netspace-client.lsp
;;;   ./c/lumbda examples/proof-netspace-client.lsp
;;;   ./asm/lumbda < examples/proof-netspace-client.lsp

(define *host* "127.0.0.1")
(define *port* 9086)

;;; ─── Canonical serializer (matches server) ─────────────────

(define (atom->string v)
  (cond
    ((number? v) (number->string v))
    ((symbol? v) (symbol->string v))
    ((null? v)   "()")
    ((pair? v)   (string-append "(" (list->str v) ")"))
    (else        "?")))

(define (list->str lst)
  (cond
    ((null? lst) "")
    ((null? (cdr lst)) (atom->string (car lst)))
    (else (string-append (atom->string (car lst)) " "
                         (list->str (cdr lst))))))

;;; ─── One-shot TCP round-trip ───────────────────────────────

(define (request str)
  (let ((sock (tcp-connect *host* *port*)))
    (if sock
        (begin
          (tcp-send sock str)
          (let ((resp (tcp-recv sock 65536)))
            (tcp-close sock)
            (if resp resp "NO-RESPONSE")))
        "NO-CONNECT")))

;;; ─── Per-proof verification ────────────────────────────────

(define (ask lhs rhs)
  (request (string-append "(" (atom->string lhs) " "
                              (atom->string rhs) ")")))

(define (probe name lhs rhs)
  (let ((t0 (current-time-ms)))
    (let ((resp (ask lhs rhs)))
      (let ((t1 (current-time-ms)))
        (display name) (display ": ")
        (display (- t1 t0)) (display " ms   ")
        (display resp)))))

;;; ─── Envelope teleport ─────────────────────────────────────

(define (count-items form n)
  ;; Return length of a list form; used to count hashes in envelope.
  (if (pair? form) (count-items (cdr form) (+ n 1)) n))

(define (parse-envelope resp)
  ;; resp = "(envelope (h1 h2 ...))\n" — return the inner list.
  (let ((form (read-from-string resp)))
    (if (and (pair? form) (eqv? (car form) 'envelope) (pair? (cdr form)))
        (car (cdr form))
        '())))

(define (hashes->string lst acc)
  (if (null? lst) acc
      (hashes->string (cdr lst)
                      (string-append acc (number->string (car lst)) " "))))

(define (fetch-envelope)
  (let ((t0 (current-time-ms)))
    (let ((resp (request "(envelope)")))
      (let ((t1 (current-time-ms)))
        (display "envelope     : ") (display (- t1 t0)) (display " ms   ")
        (let ((hashes (parse-envelope resp)))
          (display (count-items hashes 0))
          (display " hashes teleported") (newline)
          hashes)))))

(define (merge-envelope hashes synthetic)
  ;; Send the server its own envelope back plus one synthetic hash.
  ;; Expected reply: (merged 1) — only the synthetic was new.
  (let ((t0 (current-time-ms)))
    (let ((payload (string-append "(merge ("
                                  (hashes->string hashes "")
                                  (number->string synthetic) "))")))
      (let ((resp (request payload)))
        (let ((t1 (current-time-ms)))
          (display "merge        : ") (display (- t1 t0)) (display " ms   ")
          (display resp))))))

;;; ─── Run ───────────────────────────────────────────────────

(display "querying proof netspace at ") (display *host*) (display ":")
(display *port*) (newline)
(newline)

(probe "eml_is_exp   "  '(eml ?x 1)  '(exp ?x))
(probe "eml_is_e     "  '(eml 1 1)   '(exp 1))
(probe "eml_is_ln    "  '(eml 1 (eml (eml 1 ?x) 1))  '(ln ?x))
(probe "eml_is_zero  "  '(eml 1 (eml (eml 1 1) 1))   0)
(probe "eml_is_sub   "  '(eml (ln ?a) (exp ?b))      '(- ?a ?b))
(newline)

(define env (fetch-envelope))
(merge-envelope env 999999999)
(newline)

(display "done") (newline)
