(ns ajet.chat.e2e.messaging-flow-e2e-test
  "E2E tests for the messaging flow through the full stack.
   Requires: docker compose -f docker-compose.test.yml --profile e2e up -d

   These tests create data directly in the DB (same PG instance the services use),
   then exercise the HTTP API through the auth-gw proxy.

   Since OAuth login can't be automated in E2E without mocking, we create a
   session directly in the DB and use the session cookie for authenticated requests."
  (:require [clojure.test :refer [deftest testing is use-fixtures]]
            [clojure.data.json :as json]
            [babashka.http-client :as http]
            [ajet.chat.shared.db :as db]
            [ajet.chat.auth-gw.auth :as auth]
            [ajet.chat.test-helpers :as th]))

(def ^:private base-url (or (System/getenv "AJET_TEST_BASE_URL") "http://localhost:3100"))

(use-fixtures :once th/with-db-suite)
(use-fixtures :each th/with-clean-db)

(defn- authed-request
  "Make an authenticated HTTP request through the auth-gw.
   Creates a session token directly in the DB and passes it as a cookie."
  [method path user-id & [{:keys [body]}]]
  (let [token  (auth/create-session! th/*ds* user-id 30)
        cookie (str "ajet_session=" token)
        opts   (cond-> {:throw            false
                        :follow-redirects false
                        :headers          {"Cookie"       cookie
                                           "Content-Type" "application/json"}}
                 body (assoc :body (json/write-str body)))]
    (case method
      :get    (http/get    (str base-url path) opts)
      :post   (http/post   (str base-url path) opts)
      :put    (http/put    (str base-url path) opts)
      :delete (http/delete (str base-url path) opts))))

(defn- parse-body [resp]
  (when (and (:body resp) (not (clojure.string/blank? (:body resp))))
    (json/read-str (:body resp) :key-fn keyword)))

;;; ---------------------------------------------------------------------------
;;; Community CRUD
;;; ---------------------------------------------------------------------------

(deftest create-community-via-http
  (let [user (th/create-user!)
        resp (authed-request :post "/api/communities" (:id user)
               {:body {:name "E2E Team" :slug "e2e-team"}})
        body (parse-body resp)]
    (is (= 201 (:status resp)))
    (is (= "E2E Team" (:name body)))))

;;; ---------------------------------------------------------------------------
;;; Channel CRUD
;;; ---------------------------------------------------------------------------

(deftest create-channel-via-http
  (let [user (th/create-user!)
        comm (th/create-community! {:slug "ch-test"})
        _    (th/add-member! (:id comm) (:id user) {:role "admin"})
        resp (authed-request :post (str "/api/communities/" (:id comm) "/channels")
               (:id user) {:body {:name "dev-channel"}})
        body (parse-body resp)]
    (is (= 201 (:status resp)))
    (is (= "dev-channel" (:name body)))))

;;; ---------------------------------------------------------------------------
;;; Message CRUD
;;; ---------------------------------------------------------------------------

(deftest send-message-via-http
  (let [user (th/create-user!)
        comm (th/create-community! {:slug "msg-test"})
        _    (th/add-member! (:id comm) (:id user) {:role "owner"})
        ch   (th/create-channel! (:id comm) {:name "general"})
        _    (th/join-channel! (:id ch) (:id user))
        resp (authed-request :post (str "/api/channels/" (:id ch) "/messages")
               (:id user) {:body {:body_md "Hello from E2E!"}})
        body (parse-body resp)]
    (is (= 201 (:status resp)))
    (is (= "Hello from E2E!" (:body-md body)))))

(deftest list-messages-via-http
  (let [user (th/create-user!)
        comm (th/create-community! {:slug "list-msg"})
        _    (th/add-member! (:id comm) (:id user) {:role "owner"})
        ch   (th/create-channel! (:id comm))
        _    (th/join-channel! (:id ch) (:id user))
        _    (th/create-message! (:id ch) (:id user) {:body-md "msg1"})
        _    (th/create-message! (:id ch) (:id user) {:body-md "msg2"})
        resp (authed-request :get (str "/api/channels/" (:id ch) "/messages") (:id user))
        body (parse-body resp)]
    (is (= 200 (:status resp)))
    (is (= 2 (count body)))))

(deftest delete-message-via-http
  (let [user (th/create-user!)
        comm (th/create-community! {:slug "del-msg"})
        _    (th/add-member! (:id comm) (:id user) {:role "owner"})
        ch   (th/create-channel! (:id comm))
        _    (th/join-channel! (:id ch) (:id user))
        msg  (th/create-message! (:id ch) (:id user) {:body-md "delete me"})
        resp (authed-request :delete (str "/api/messages/" (:id msg)) (:id user))]
    (is (= 204 (:status resp)))))
