(ns ajet.chat.api.communities-integration-test
  (:require [clojure.test :refer [deftest testing is use-fixtures]]
            [ajet.chat.api.handlers.communities :as communities]
            [ajet.chat.shared.db :as db]
            [ajet.chat.test-helpers :as th]))

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

;;; ---------------------------------------------------------------------------
;;; Create community
;;; ---------------------------------------------------------------------------

(deftest create-community-success
  (let [user (th/create-user!)
        req  (th/mock-request {:method      :post
                               :user-id     (str (:id user))
                               :system      (th/test-system)
                               :body-params {:name "My Team" :slug "my-team"}})
        resp (communities/create-community req)
        body (th/response-body resp)]
    (is (= 201 (:status resp)))
    (is (= "My Team" (:name body)))
    (is (= "my-team" (:slug body)))))

(deftest create-community-bootstraps-owner-and-general-channel
  (testing "Creating a community adds creator as owner and bootstraps #general channel"
    (let [user    (th/create-user!)
          user-id (str (:id user))
          req     (th/mock-request {:method      :post
                                    :user-id     user-id
                                    :system      (th/test-system)
                                    :body-params {:name "Bootstrap Test" :slug "bootstrap-test"}})
          resp    (communities/create-community req)
          body    (th/response-body resp)
          comm-id (:id body)]

      (is (= 201 (:status resp)))

      ;; Creator should be an owner in community_members
      (let [membership (db/execute-one! th/*ds*
                         {:select [:*]
                          :from   [:community-members]
                          :where  [:and
                                   [:= :community-id [:cast comm-id :uuid]]
                                   [:= :user-id [:cast user-id :uuid]]]})]
        (is (some? membership) "Creator should be a community member")
        (is (= "owner" (:role membership)) "Creator should have owner role"))

      ;; #general channel should exist
      (let [channel (db/execute-one! th/*ds*
                      {:select [:*]
                       :from   [:channels]
                       :where  [:and
                                [:= :community-id [:cast comm-id :uuid]]
                                [:= :name "general"]]})]
        (is (some? channel) "#general channel should be created")
        (is (= "text" (:type channel)))
        (is (= "public" (:visibility channel)))

        ;; Creator should be a member of #general
        (let [ch-membership (db/execute-one! th/*ds*
                              {:select [:*]
                               :from   [:channel-members]
                               :where  [:and
                                        [:= :channel-id (:id channel)]
                                        [:= :user-id [:cast user-id :uuid]]]})]
          (is (some? ch-membership) "Creator should be a member of #general"))))))

(deftest create-community-missing-name-returns-422
  (let [user (th/create-user!)
        req  (th/mock-request {:method      :post
                               :user-id     (str (:id user))
                               :system      (th/test-system)
                               :body-params {:name "" :slug "test-slug"}})
        resp (th/with-exception-handler communities/create-community req)]
    (is (= 422 (:status resp)))))

(deftest create-community-invalid-slug-returns-422
  (let [user (th/create-user!)
        req  (th/mock-request {:method      :post
                               :user-id     (str (:id user))
                               :system      (th/test-system)
                               :body-params {:name "Test" :slug "INVALID"}})
        resp (th/with-exception-handler communities/create-community req)]
    (is (= 422 (:status resp)))))

(deftest create-community-duplicate-slug-returns-409
  (let [user (th/create-user!)]
    (th/create-community! {:slug "taken-slug"})
    (let [req  (th/mock-request {:method      :post
                                 :user-id     (str (:id user))
                                 :system      (th/test-system)
                                 :body-params {:name "Another" :slug "taken-slug"}})
          resp (th/with-exception-handler communities/create-community req)]
      (is (= 409 (:status resp))))))

(deftest create-community-unauthenticated-returns-403
  (let [req  (th/mock-request {:method      :post
                               :system      (th/test-system)
                               :body-params {:name "Test" :slug "test-slug"}})
        resp (th/with-exception-handler communities/create-community req)]
    (is (= 403 (:status resp)))))

;;; ---------------------------------------------------------------------------
;;; List communities
;;; ---------------------------------------------------------------------------

(deftest list-communities-returns-user-communities
  (let [user (th/create-user!)
        comm (th/create-community! {:name "Team A" :slug "team-aa"})
        _    (th/add-member! (:id comm) (:id user) {:role "member"})
        _    (th/create-community! {:name "Team B" :slug "team-bb"})  ;; user NOT a member
        req  (th/mock-request {:user-id (str (:id user))
                               :system  (th/test-system)})
        resp (communities/list-communities req)
        body (th/response-body resp)]
    (is (= 200 (:status resp)))
    (is (= 1 (count body)))
    (is (= "Team A" (:name (first body))))))

;;; ---------------------------------------------------------------------------
;;; Get community
;;; ---------------------------------------------------------------------------

(deftest get-community-member-success
  (let [user (th/create-user!)
        comm (th/create-community!)
        _    (th/add-member! (:id comm) (:id user))
        req  (th/mock-request {:user-id     (str (:id user))
                               :system      (th/test-system)
                               :path-params {:id (str (:id comm))}})
        resp (communities/get-community req)]
    (is (= 200 (:status resp)))))

(deftest get-community-non-member-returns-403
  (let [user (th/create-user!)
        comm (th/create-community!)
        req  (th/mock-request {:user-id     (str (:id user))
                               :system      (th/test-system)
                               :path-params {:id (str (:id comm))}})]
    (is (= 403 (:status (th/with-exception-handler communities/get-community req))))))

;;; ---------------------------------------------------------------------------
;;; Update community
;;; ---------------------------------------------------------------------------

(deftest update-community-owner-success
  (let [user (th/create-user!)
        comm (th/create-community!)
        _    (th/add-member! (:id comm) (:id user) {:role "owner"})
        req  (th/mock-request {:method      :put
                               :user-id     (str (:id user))
                               :system      (th/test-system)
                               :path-params {:id (str (:id comm))}
                               :body-params {:name "Updated Name"}})
        resp (communities/update-community req)
        body (th/response-body resp)]
    (is (= 200 (:status resp)))
    (is (= "Updated Name" (:name body)))))

;;; ---------------------------------------------------------------------------
;;; Delete community
;;; ---------------------------------------------------------------------------

(deftest delete-community-owner-success
  (let [user (th/create-user!)
        comm (th/create-community!)
        _    (th/add-member! (:id comm) (:id user) {:role "owner"})
        req  (th/mock-request {:method      :delete
                               :user-id     (str (:id user))
                               :system      (th/test-system)
                               :path-params {:id (str (:id comm))}})
        resp (communities/delete-community req)]
    (is (= 204 (:status resp)))))
