(ns ajet.chat.api.handlers.notifications
  "Notification handlers: list, mark read, unread count.

   Notifications are created by message handlers (mentions, DMs, thread replies)
   and invite handlers. This namespace handles reading and managing them."
  (:require [ajet.chat.shared.db :as db]
            [ajet.chat.api.middleware :as mw]))

;;; ---------------------------------------------------------------------------
;;; Helpers
;;; ---------------------------------------------------------------------------

(defn- require-user! [request]
  (or (:user-id request)
      (throw (ex-info "Authentication required" {:type :ajet.chat/forbidden}))))

;;; ---------------------------------------------------------------------------
;;; Handlers
;;; ---------------------------------------------------------------------------

(defn list-notifications
  "GET /api/notifications?after=<uuid>&limit=N&unread=true
   Returns notifications for the authenticated user, newest first."
  [request]
  (let [user-id (require-user! request)
        ds      (get-in request [:system :ds])
        params  (:query-params request)
        after   (get params "after")
        limit   (min (or (some-> (get params "limit") parse-long) 50) 100)
        unread  (= "true" (get params "unread"))

        base-where [:= :user-id [:cast user-id :uuid]]
        where-clause (cond-> base-where
                       unread
                       (vector :and [:= :read false])

                       after
                       (vector :and
                         [:< :created-at
                          {:select [:created-at]
                           :from   [:notifications]
                           :where  [:= :id [:cast after :uuid]]}]))

        ;; Build the full where clause properly
        final-where (cond
                      (and unread after)
                      [:and
                       base-where
                       [:= :read false]
                       [:< :created-at
                        {:select [:created-at]
                         :from   [:notifications]
                         :where  [:= :id [:cast after :uuid]]}]]

                      unread
                      [:and base-where [:= :read false]]

                      after
                      [:and base-where
                       [:< :created-at
                        {:select [:created-at]
                         :from   [:notifications]
                         :where  [:= :id [:cast after :uuid]]}]]

                      :else base-where)

        notifications (db/execute! ds
                        {:select   [:*]
                         :from     [:notifications]
                         :where    final-where
                         :order-by [[:created-at :desc]]
                         :limit    limit})]
    (mw/json-response notifications)))

(defn mark-read
  "POST /api/notifications/read
   Marks specified notifications as read.
   Body: {\"notification_ids\": [\"uuid\", ...]}"
  [request]
  (let [user-id (require-user! request)
        ds      (get-in request [:system :ds])
        params  (:body-params request)
        ids     (:notification_ids params)]

    (when (or (nil? ids) (empty? ids))
      (throw (ex-info "notification_ids is required"
                      {:type :ajet.chat/validation-error})))

    (let [uuid-ids (mapv (fn [id] [:cast id :uuid]) ids)]
      (db/execute! ds
        {:update :notifications
         :set    {:read true}
         :where  [:and
                  [:= :user-id [:cast user-id :uuid]]
                  [:in :id uuid-ids]]}))

    (mw/json-response {:status "ok" :marked-read (count ids)})))

(defn unread-count
  "GET /api/notifications/unread-count
   Returns the count of unread notifications."
  [request]
  (let [user-id (require-user! request)
        ds      (get-in request [:system :ds])
        result  (db/execute-one! ds
                  {:select [[[:count :*] :count]]
                   :from   [:notifications]
                   :where  [:and
                            [:= :user-id [:cast user-id :uuid]]
                            [:= :read false]]})]
    (mw/json-response {:unread-count (:count result 0)})))
