;; Echo server — minimal classic Erlang server. Receives {From, Msg}
;; and sends Msg back to From, then loops. `stop` ends the server.

(define er-echo-test-count 0)
(define er-echo-test-pass 0)
(define er-echo-test-fails (list))

(define
  er-echo-test
  (fn
    (name actual expected)
    (set! er-echo-test-count (+ er-echo-test-count 1))
    (if
      (= actual expected)
      (set! er-echo-test-pass (+ er-echo-test-pass 1))
      (append! er-echo-test-fails {:actual actual :expected expected :name name}))))

(define echo-ev erlang-eval-ast)

(define
  er-echo-server-src
  "EchoSrv = fun () ->
     Loop = fun () ->
       receive
         {From, Msg} -> From ! Msg, Loop();
         stop -> ok
       end
     end,
     Loop()
   end")

;; Single round-trip with an atom.
(er-echo-test
  "atom round-trip"
  (get
    (echo-ev
      (str
        er-echo-server-src
        ", Me = self(),
         Echo = spawn(EchoSrv),
         Echo ! {Me, hello},
         receive R -> Echo ! stop, R end"))
    :name)
  "hello")

;; Number round-trip.
(er-echo-test
  "number round-trip"
  (echo-ev
    (str
      er-echo-server-src
      ", Me = self(),
       Echo = spawn(EchoSrv),
       Echo ! {Me, 42},
       receive R -> Echo ! stop, R end"))
  42)

;; Tuple round-trip — pattern-match the reply to extract V.
(er-echo-test
  "tuple round-trip"
  (echo-ev
    (str
      er-echo-server-src
      ", Me = self(),
       Echo = spawn(EchoSrv),
       Echo ! {Me, {ok, 7}},
       receive {ok, V} -> Echo ! stop, V end"))
  7)

;; List round-trip.
(er-echo-test
  "list round-trip"
  (echo-ev
    (str
      er-echo-server-src
      ", Me = self(),
       Echo = spawn(EchoSrv),
       Echo ! {Me, [1, 2, 3]},
       receive [H | _] -> Echo ! stop, H end"))
  1)

;; Multiple sequential round-trips.
(er-echo-test
  "three round-trips"
  (echo-ev
    (str
      er-echo-server-src
      ", Me = self(),
       Echo = spawn(EchoSrv),
       Echo ! {Me, 10}, A = receive Ra -> Ra end,
       Echo ! {Me, 20}, B = receive Rb -> Rb end,
       Echo ! {Me, 30}, C = receive Rc -> Rc end,
       Echo ! stop,
       A + B + C"))
  60)

;; Two clients sharing one echo server. Each gets its own reply.
(er-echo-test
  "two clients"
  (get
    (echo-ev
      (str
        er-echo-server-src
        ", Me = self(),
         Echo = spawn(EchoSrv),
         Client = fun (Tag) ->
           spawn(fun () ->
             Echo ! {self(), Tag},
             receive R -> Me ! {got, R} end
           end)
         end,
         Client(a),
         Client(b),
         receive {got, _} -> ok end,
         receive {got, _} -> ok end,
         Echo ! stop,
         finished"))
    :name)
  "finished")

;; Echo via io trace — verify each message round-trips through.
(er-echo-test
  "trace 4 messages"
  (do
    (er-io-flush!)
    (echo-ev
      (str
        er-echo-server-src
        ", Me = self(),
         Echo = spawn(EchoSrv),
         Send = fun (V) -> Echo ! {Me, V}, receive R -> io:format(\"~p \", [R]) end end,
         Send(1), Send(2), Send(3), Send(4),
         Echo ! stop,
         done"))
    (er-io-buffer-content))
  "1 2 3 4 ")

(define
  er-echo-test-summary
  (str "echo " er-echo-test-pass "/" er-echo-test-count))
