(ns ajet-chat.e2e.tests.messaging-test
  "Workflow 3: Two users chatting in real time — message sending + SSE delivery."
  (:require [ajet-chat.e2e.config :as config]
            [ajet-chat.e2e.helpers :as h]
            [ajet-chat.e2e.setup :as setup]
            [promesa.core :as p]))

(defn- extract-channel-id
  "Extract the UUID from a sidebar-channel-UUID element ID."
  [element-id]
  (when element-id
    (.replace element-id "sidebar-channel-" "")))

(defn two-user-realtime-chat
  "Two users can exchange messages in real time via SSE."
  []
  (p/let [oauth-creds (setup/setup-gitea-and-provider!)
          browser     (h/launch-browser!)]
    (-> (p/let [;; Two separate browser contexts (isolated sessions)
                context-a (h/new-context! browser)
                page-a    (h/new-page! context-a)
                context-b (h/new-context! browser)
                page-b    (h/new-page! context-b)]
          (p/do
            ;; --- User A: Login and setup ---
            (setup/login-and-setup! page-a config/test-user-a "Chat Test" "chat-test")
            (h/wait-for-url page-a #"/app" {:timeout 15000})

            ;; --- User B: Login ---
            (setup/login-via-gitea! page-b config/test-user-b)
            (h/wait-for-url page-b #"/(app|setup)" {:timeout 30000})

            ;; User B joins User A's community via invite
            (p/let [url-b (h/page-url page-b)]
              (if (re-find #"/setup" url-b)
                (p/do
                  (setup/ensure-user-in-community! page-a page-b)
                  (h/goto page-b "/app")
                  (h/wait-for-url page-b #"/app" {:timeout 15000}))
                (p/do
                  (p/catch
                    (setup/ensure-user-in-community! page-a page-b)
                    (fn [_] nil))
                  (h/goto page-b "/app")
                  (h/wait-for-url page-b #"/app" {:timeout 15000}))))

            ;; Wait for both pages to be fully loaded with sidebar
            (h/wait-for-selector page-a "#sidebar" {:timeout 15000})
            (h/wait-for-selector page-b "#sidebar" {:timeout 15000})

            ;; Navigate User A to the first channel and extract channel UUID
            (p/let [ch-a (.waitForSelector page-a "[id^='sidebar-channel-']"
                                           #js {:timeout 10000})
                    ch-el-id (when ch-a (.getAttribute ch-a "id"))
                    channel-id (extract-channel-id ch-el-id)]
              (js/console.log "  [msg] Channel:" channel-id)
              (when ch-a (.click ch-a))
              (h/wait-ms 1000)

              ;; Navigate User B to the SAME channel
              (p/let [ch-b (.waitForSelector page-b (str "#sidebar-channel-" channel-id)
                                             #js {:timeout 10000})]
                (when ch-b (.click ch-b)))
              (h/wait-ms 1000)

              ;; Give SSE connections time to establish
              (h/wait-ms 5000)

              ;; --- User A sends a message ---
              (h/wait-for-selector page-a "#message-textarea" {:timeout 5000})
              (h/send-message! page-a channel-id "Hello from User A! The time is now.")

              ;; User A sees own message (delivered via SSE from NATS)
              (h/wait-for-text page-a "Hello from User A! The time is now." {:timeout 15000})
              (js/console.log "  [msg] User A sees own message")

              ;; User B receives via SSE
              (h/wait-for-text page-b "Hello from User A! The time is now." {:timeout 20000})
              (js/console.log "  [msg] User B sees User A's message via SSE")

              ;; --- User B replies ---
              (h/wait-for-selector page-b "#message-textarea" {:timeout 5000})
              (h/send-message! page-b channel-id "Reply from User B!")

              ;; User B sees own reply
              (h/wait-for-text page-b "Reply from User B!" {:timeout 15000})

              ;; User A receives the reply via SSE
              (h/wait-for-text page-a "Reply from User B!" {:timeout 20000})
              (js/console.log "  [msg] Both users see each other's messages"))))

        (p/catch (fn [err]
                   (js/console.error "messaging test error:" err)
                   (throw err)))
        (p/finally (fn []
                     (h/close-all! browser))))))

(defn message-shows-metadata
  "Messages display sender's username."
  []
  (p/let [oauth-creds (setup/setup-gitea-and-provider!)
          browser     (h/launch-browser!)
          context     (h/new-context! browser)
          page        (h/new-page! context)]
    (-> (p/do
          (setup/login-and-setup! page config/test-user-a "Msg Meta Test" "msg-meta")
          (h/wait-for-url page #"/app" {:timeout 15000})

          ;; Wait for Datastar SDK to load and SSE to establish
          (h/wait-ms 5000)

          ;; Navigate to a channel
          (p/let [ch-el (.waitForSelector page "[id^='sidebar-channel-']"
                                          #js {:timeout 10000})
                  ch-el-id (when ch-el (.getAttribute ch-el "id"))
                  channel-id (extract-channel-id ch-el-id)]
            (when ch-el (.click ch-el))
            (h/wait-ms 2000)

            ;; Wait for SSE to re-subscribe after navigation
            (h/wait-ms 3000)

            ;; Send a message via direct POST and check result
            (p/let [send-result (h/send-message! page channel-id "Test message with metadata")]
              (js/console.log "  [meta] Send result:" (js/JSON.stringify (clj->js send-result)))
              (js/console.log "  [meta] Channel:" channel-id))

            ;; Wait for message to appear via SSE
            (p/let [found (p/catch
                            (p/do
                              (h/wait-for-text page "Test message with metadata" {:timeout 15000})
                              true)
                            (fn [_]
                              ;; If SSE didn't deliver, try reloading
                              (js/console.log "  [meta] Message not found via SSE, reloading page...")
                              (p/let [_ (h/goto page "/app")
                                      _ (h/wait-for-url page #"/app" {:timeout 5000})
                                      _ (h/wait-ms 3000)]
                                (p/catch
                                  (p/do
                                    (h/wait-for-text page "Test message with metadata" {:timeout 10000})
                                    true)
                                  (fn [_] false)))))]
              (assert found "message text should be visible after send or reload"))

            ;; Verify message element exists with msg- prefix
            (p/let [msg-el (p/catch
                             (.waitForSelector page "[id^='msg-']" #js {:timeout 5000})
                             (fn [_] nil))]
              (assert (some? msg-el)
                      "message element should exist with msg- prefix"))))

        (p/catch (fn [err]
                   (p/do
                     (h/screenshot! page "message-meta-failure.png")
                     (throw err))))
        (p/finally (fn []
                     (h/close-all! browser))))))

(def tests
  [{:name "two-user-realtime-chat"
    :test-fn two-user-realtime-chat}
   {:name "message-shows-metadata"
    :test-fn message-shows-metadata}])
