;;; jabber-test-csi.el --- Tests for jabber-csi  -*- lexical-binding: t; -*-

;;; Commentary:

;; XEP-0352 Client State Indication.

;;; Code:

(require 'ert)
(require 'jabber-csi)

;;; Group 1: State detection

(ert-deftest jabber-test-csi-focused-p-returns-bool ()
  "focused-p returns non-nil or nil without error."
  (should (or (jabber-csi--focused-p)
              (not (jabber-csi--focused-p)))))

;;; Group 2: Send logic

(ert-deftest jabber-test-csi-send-active-when-focused ()
  "Sends active element when focused."
  (let ((sent nil)
        (jabber-csi-enable t)
        (jabber-csi--last-state nil)
        (jabber-connections '(fake-jc)))
    (cl-letf (((symbol-function 'jabber-csi--focused-p)
               (lambda () t))
              ((symbol-function 'jabber-send-sexp-if-connected)
               (lambda (_jc sexp) (setq sent sexp))))
      (jabber-csi--send-state)
      (should sent)
      (should (eq (car sent) 'active))
      (should (eq jabber-csi--last-state 'active)))))

(ert-deftest jabber-test-csi-send-inactive-when-unfocused ()
  "Sends inactive element when unfocused."
  (let ((sent nil)
        (jabber-csi-enable t)
        (jabber-csi--last-state nil)
        (jabber-connections '(fake-jc)))
    (cl-letf (((symbol-function 'jabber-csi--focused-p)
               (lambda () nil))
              ((symbol-function 'jabber-send-sexp-if-connected)
               (lambda (_jc sexp) (setq sent sexp))))
      (jabber-csi--send-state)
      (should sent)
      (should (eq (car sent) 'inactive))
      (should (eq jabber-csi--last-state 'inactive)))))

(ert-deftest jabber-test-csi-no-duplicate-send ()
  "Does not resend the same state."
  (let ((send-count 0)
        (jabber-csi-enable t)
        (jabber-csi--last-state 'active)
        (jabber-connections '(fake-jc)))
    (cl-letf (((symbol-function 'jabber-csi--focused-p)
               (lambda () t))
              ((symbol-function 'jabber-send-sexp-if-connected)
               (lambda (_jc _sexp) (cl-incf send-count))))
      (jabber-csi--send-state)
      (should (= send-count 0)))))

(ert-deftest jabber-test-csi-disabled-sends-nothing ()
  "Sends nothing when jabber-csi-enable is nil."
  (let ((sent nil)
        (jabber-csi-enable nil)
        (jabber-csi--last-state nil)
        (jabber-connections '(fake-jc)))
    (cl-letf (((symbol-function 'jabber-csi--focused-p)
               (lambda () t))
              ((symbol-function 'jabber-send-sexp-if-connected)
               (lambda (_jc sexp) (setq sent sexp))))
      (jabber-csi--send-state)
      (should-not sent))))

(ert-deftest jabber-test-csi-on-connect-resets-state ()
  "on-connect resets last-state and sends current state."
  (let ((jabber-csi-enable t)
        (jabber-csi--last-state 'active)
        (jabber-csi--timer nil)
        (jabber-connections '(fake-jc)))
    (cl-letf (((symbol-function 'jabber-csi--focused-p)
               (lambda () t))
              ((symbol-function 'jabber-send-sexp-if-connected)
               #'ignore))
      (jabber-csi--on-connect 'fake-jc)
      (should (eq jabber-csi--last-state 'active)))))

;;; Group 3: Debounce

(ert-deftest jabber-test-csi-debounce-coalesces ()
  "Rapid focus-changed calls produce only one pending timer."
  (let ((jabber-csi--timer nil))
    (cl-letf (((symbol-function 'jabber-csi--focused-p)
               (lambda () t))
              ((symbol-function 'jabber-send-sexp-if-connected)
               #'ignore))
      (jabber-csi--focus-changed)
      (jabber-csi--focus-changed)
      (jabber-csi--focus-changed)
      (should (timerp jabber-csi--timer))
      (jabber-csi--stop-timer))))

(ert-deftest jabber-test-csi-disconnect-cleanup ()
  "on-disconnect cancels pending timer and resets state."
  (let ((jabber-csi--timer (run-with-timer 10 nil #'ignore))
        (jabber-csi--last-state 'active))
    (jabber-csi--on-disconnect)
    (should-not jabber-csi--timer)
    (should-not jabber-csi--last-state)))

(provide 'jabber-test-csi)

;;; jabber-test-csi.el ends here
