;; identity/tests/api.sx — the service facade end-to-end: login issues a
;; session + token, verify proves identity, revoke and logout take effect
;; immediately. Exercises session + token + registry through one door.

(define id-api-test-count 0)
(define id-api-test-pass 0)
(define id-api-test-fails (list))

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

(define ida-ev erlang-eval-ast)
(define idanm (fn (v) (get v :name)))

(identity-load-all!)

;; ── login + verify (happy path) ──────────────────────────────────

(id-api-test
  "login then verify is active"
  (idanm
    (ida-ev
      "Svc = identity:start(),\n       {ok, _Sid, Tok} = identity:login(Svc, alice, web, read),\n       case identity:verify(Svc, Tok) of\n         {active, _, _, _} -> active;\n         {inactive} -> inactive\n       end"))
  "active")

(id-api-test
  "verify returns the logged-in subject"
  (idanm
    (ida-ev
      "Svc = identity:start(),\n       {ok, _Sid, Tok} = identity:login(Svc, alice, web, read),\n       case identity:verify(Svc, Tok) of\n         {active, Subject, _, _} -> Subject\n       end"))
  "alice")

(id-api-test
  "verify returns the granted scope"
  (idanm
    (ida-ev
      "Svc = identity:start(),\n       {ok, _Sid, Tok} = identity:login(Svc, bob, cli, write),\n       case identity:verify(Svc, Tok) of\n         {active, _, _, Scope} -> Scope\n       end"))
  "write")

;; ── revoke is real through the facade ────────────────────────────

(id-api-test
  "revoked token verifies inactive immediately"
  (idanm
    (ida-ev
      "Svc = identity:start(),\n       {ok, _Sid, Tok} = identity:login(Svc, alice, web, read),\n       identity:revoke(Svc, Tok),\n       case identity:verify(Svc, Tok) of\n         {active, _, _, _} -> still_valid;\n         {inactive} -> inactive\n       end"))
  "inactive")

;; ── session lifecycle through the facade ─────────────────────────

(id-api-test
  "fresh session reports active"
  (idanm
    (ida-ev
      "Svc = identity:start(),\n       {ok, Sid, _Tok} = identity:login(Svc, alice, web, read),\n       identity:session_status(Svc, Sid)"))
  "active")

(id-api-test
  "logout makes the session gone"
  (idanm
    (ida-ev
      "Svc = identity:start(),\n       {ok, Sid, _Tok} = identity:login(Svc, alice, web, read),\n       identity:logout(Svc, Sid),\n       identity:session_status(Svc, Sid)"))
  "gone")

(id-api-test
  "status of an unknown session is gone"
  (idanm
    (ida-ev "Svc = identity:start(),\n       identity:session_status(Svc, 999)"))
  "gone")

;; ── independence: logins do not bleed into each other ────────────

(id-api-test
  "revoking one login leaves the other active"
  (idanm
    (ida-ev
      "Svc = identity:start(),\n       {ok, _S1, T1} = identity:login(Svc, alice, web, read),\n       {ok, _S2, T2} = identity:login(Svc, bob, cli, write),\n       identity:revoke(Svc, T1),\n       case identity:verify(Svc, T2) of\n         {active, Subject, _, _} -> Subject;\n         {inactive} -> inactive\n       end"))
  "bob")

(id-api-test
  "logging out one session leaves the other active"
  (idanm
    (ida-ev
      "Svc = identity:start(),\n       {ok, S1, _T1} = identity:login(Svc, alice, web, read),\n       {ok, S2, _T2} = identity:login(Svc, alice, cli, read),\n       identity:logout(Svc, S1),\n       identity:session_status(Svc, S2)"))
  "active")

;; ── coordinator deregisters on a session_expired notification ────
;; A live idle session fires its own `after` timeout and notifies its
;; owner (the coordinator), which then deregisters it — timeout-driven,
;; never swept. The owner-internal path can't be observed by driving the
;; scheduler idle from the test's main process, so we assert the handler
;; directly: the mailbox is FIFO, so the expiry notification is processed
;; before the following status query.

(id-api-test
  "session_expired notification deregisters the session"
  (idanm
    (ida-ev
      "Svc = identity:start(),\n       {ok, Sid, _Tok} = identity:login(Svc, alice, web, read, 50),\n       active = identity:session_status(Svc, Sid),\n       Svc ! {session_expired, Sid},\n       identity:session_status(Svc, Sid)"))
  "gone")

(define
  id-api-test-summary
  (str "api " id-api-test-pass "/" id-api-test-count))
