;; gnus configuration -*- lexical-binding: t -*-

;;; features
(defvar jao-gnus-use-local-imap nil)
(defvar jao-gnus-use-leafnode nil)
(defvar jao-gnus-use-mailbox-imap nil)
(defvar jao-gnus-use-pm-imap nil)
(defvar jao-gnus-use-gmane nil)
(defvar jao-gnus-use-nnml nil)
(defvar jao-gnus-use-maildirs nil)
(defvar jao-notmuch-enabled nil)
(defvar jao-gnus-nnml-group-params nil)

;;; directories
(defun jao-gnus-dir (dir)
  (expand-file-name dir gnus-home-directory))

(setq smtpmail-queue-dir (jao-gnus-dir "Mail/queued-mail/"))

(setq mail-source-directory (jao-gnus-dir "Mail/")
      message-directory (jao-gnus-dir "Mail/"))

(setq gnus-default-directory (expand-file-name "~")
      gnus-startup-file (jao-gnus-dir "newsrc")
      gnus-agent-directory (jao-gnus-dir "News/agent")
      gnus-home-score-file (jao-gnus-dir "scores")
      gnus-article-save-directory (jao-gnus-dir "saved/")
      nntp-authinfo-file (jao-gnus-dir "authinfo")
      nnmail-message-id-cache-file (jao-gnus-dir "nnmail-cache")
      nndraft-directory (jao-gnus-dir "drafts")
      nnrss-directory (jao-gnus-dir "rss"))

(setq gnus-uncacheable-groups "^nnml")

;;; private config
(require 'jao-gnus-private nil t)

;;; looks
;;;; verbosity
(setq gnus-verbose 4)
;;;; geometry
(defvar jao-gnus-use-three-panes (not jao-notmuch-enabled))
(defvar jao-gnus-groups-width 50)
(defvar jao-gnus-wide-width 190)

(setq gnus-use-trees nil
      gnus-generate-tree-function 'gnus-generate-horizontal-tree
      gnus-tree-minimize-window nil)

(setq calendar-left-margin 6)

(defun jao-gnus-use-three-panes ()
  (let ((side-bar `(vertical 1.0
                             ("inbox.org" 0.4)
                             ("*Org Agenda*" 1.0)
                             ("*Calendar*" ,(jao-d-l 9 8))))
        (wide-len jao-gnus-wide-width)
        (groups-len jao-gnus-groups-width)
        (summary-len (- jao-gnus-wide-width jao-gnus-groups-width)))
    (gnus-add-configuration
     `(article
       (horizontal 1.0
                   (vertical ,groups-len (group 1.0))
                   (vertical ,summary-len
                             (summary 0.25 point)
                             (article 1.0))
                   ,side-bar)))

    (gnus-add-configuration
     `(group (horizontal 1.0 (group ,wide-len point) ,side-bar)))

    (gnus-add-configuration
     `(message (horizontal 1.0 (message ,wide-len point) ,side-bar)))

    (gnus-add-configuration
     `(reply-yank (horizontal 1.0 (message ,wide-len point) ,side-bar)))

    (gnus-add-configuration
     `(summary
       (horizontal 1.0
                   (vertical ,groups-len (group 1.0))
                   (vertical ,summary-len (summary 1.0 point))
                   ,side-bar)))

    (gnus-add-configuration
     `(reply
       (horizontal 1.0
                   (message ,(- wide-len 100) point)
                   (article 100)
                   ,side-bar)))))

(defun jao-gnus-use-two-panes ()
  (let ((groups-len jao-gnus-groups-width)
        (summary-len (- jao-gnus-wide-width jao-gnus-groups-width))
        (msg-edit '(horizontal 1.0
                               (message 1.0 point)
                               (vertical 0.5
                                         ("*Org Agenda*" 0.5)
                                         ("inbox.org" 1.0)))))
    (gnus-add-configuration
     `(article
       (horizontal 1.0
                   (vertical ,groups-len (group 1.0))
                   (vertical 1.0
                             (summary 0.25 point)
                             (article 1.0)))))

    (gnus-add-configuration
     `(group (horizontal 1.0
                         (group 0.5 point)
                         (vertical 1.0
                                   ("*Org Agenda*" 1.0)
                                   ("*Calendar*" 9)))))

    (gnus-add-configuration
     `(summary
       (horizontal 1.0
                   (vertical ,groups-len (group 1.0))
                   (vertical 1.0 (summary 1.0 point)))))

    (gnus-add-configuration `(message ,msg-edit))

    (gnus-add-configuration `(forward ,msg-edit))

    (gnus-add-configuration `(reply-yank ,msg-edit))

    (gnus-add-configuration
     `(reply (horizontal 1.0 (message 0.5 point) (article 1.0))))))

(if jao-gnus-use-three-panes
    (jao-gnus-use-three-panes)
  (jao-gnus-use-two-panes))

;;;; no blue icon
(advice-add 'gnus-mode-line-buffer-identification :override #'identity)
(setq gnus-mode-line-image-cache nil)

;;; search
(setq gnus-search-use-parsed-queries nil
      gnus-search-notmuch-raw-queries-p t
      gnus-permanently-visible-groups "^nnselect:.*"
      gnus-search-ignored-newsgroups "nndraft.*\\|nnselect.*")

(use-package jao-recoll
  :if (jao-is-linux))

;; (add-to-list 'gnus-parameters '("^nnselect:.*" (nnselect-rescan . t)))

;;; news
(defvar jao-gnus-leafnode-spool "/var/spool/news/")
(setq gnus-select-method
      (cond
       (jao-gnus-use-leafnode
        `(nntp "localhost"
               (gnus-search-engine gnus-search-recoll
                                   (remove-prefix ,jao-gnus-leafnode-spool)
                                   (separator "/"))))
       (jao-gnus-use-gmane '(nntp "news.gmane.io"))
       (t '(nnnil ""))))

(setq gnus-secondary-select-methods '())

(setq nnheader-read-timeout 0.02
      gnus-save-newsrc-file nil) ; .newsrc only needed by other newsreaders

;; leafnode articles group parameters
(defvar jao-gnus-image-groups '("xkcd"))

(defvar jao-gnus-leafnode-group-params
  `((,(format "gwene\\..*%s.*" (regexp-opt jao-gnus-image-groups))
     (mm-html-inhibit-images nil)
     (mm-html-blocked-images nil))
    ("\\(gmane\\|gwene\\)\\..*"
     (jao-gnus--archiving-group "nnml:feeds.trove")
     (posting-style (address "jao@gnu.org")))))

(when jao-gnus-use-leafnode
  (dolist (p jao-gnus-leafnode-group-params)
    (add-to-list 'gnus-parameters p t)))

;;; mail
;;;; nnmail
(setq nnmail-treat-duplicates 'delete
      nnmail-scan-directory-mail-source-once nil
      nnmail-cache-accepted-message-ids t
      nnmail-message-id-cache-length 100000
      nnmail-split-fancy-with-parent-ignore-groups nil
      nnmail-use-long-file-names t
      nnmail-crosspost t
      nnmail-resplit-incoming t
      nnmail-mail-splitting-decodes t
      nnmail-split-methods 'nnmail-split-fancy)

;;;; nnml
(setq gnus-message-archive-group nil
      nnml-get-new-mail t
      nnml-directory message-directory)

(defvar jao-local-mail-sources
  (append (mapcar (lambda (f)
                    `(maildir :path ,(expand-file-name f jao-maildir)))
                  '("local/" "feeds/"))
          (jao-when-darwin '((file :path "/var/mail/jao")))))

(defun jao-pm-label-mail-sources (pwd &rest labels)
  (mapcar (lambda (b)
            `(imap :server "127.0.0.1" :port 1143
                   :user "jaor@pm.me" :password ,pwd
                   :stream starttls :predicate "1:*"
                   :fetchflag "\\Deleted \\Seen"
                   :mailbox ,(concat "Labels/#" b)))
          (or labels '("inbox" "drivel" "hacking" "bills" "prog" "words"))))

(defun jao-pm-folder-mail-sources (pwd &rest folders)
  (mapcar (lambda (b)
            `(imap :server "127.0.0.1" :port 1143
                   :user "jaor@pm.me" :password ,pwd
                   :stream starttls :predicate ""
                   :fetchflag ""
                   :mailbox ,(if b (concat "Folders/" b) "INBOX")))
          (or folders '(nil "drivel" "hacking" "bills" "prog" "words"))))

(setq mail-sources '((file :path "/var/mail/jao"))
      ;; (let* ((pwd (auth-source-pick-first-password :host "proton-bridge"))
      ;;        (ims (jao-pm-label-mail-sources pwd)))
      ;;   (append jao-local-mail-sources ims))
      )

(when jao-gnus-use-nnml
  (let ((prefix (expand-file-name "gnus/" jao-maildir)))
    (add-to-list
     ;; `(nnml "" ,(jao-recoll-gnus-search-engine (jao-gnus-dir "Mail/")))
     'gnus-secondary-select-methods
     `(nnml "" (gnus-search-engine gnus-search-jao-notmuch
                                   (remove-prefix ,prefix))))))

(when jao-gnus-use-nnml
  (dolist (p jao-gnus-nnml-group-params)
    (add-to-list 'gnus-parameters p t)))

;;;; imap
(setq nnimap-quirks nil)

(when jao-gnus-use-local-imap
  (add-to-list 'gnus-secondary-select-methods
               `(nnimap "" (nnimap-address "localhost"))))

(when jao-gnus-use-pm-imap
  (add-to-list 'gnus-secondary-select-methods
               '(nnimap "pm"
                        (nnimap-address "127.0.0.1")
                        (nnimap-stream network)
                        (nnimap-server-port 1143))))

(when jao-gnus-use-mailbox-imap
  (add-to-list 'gnus-secondary-select-methods
               '(nnimap "mailbox" (nnimap-address "imap.mailbox.org"))))

;;; groups
(setq gnus-group-line-format
      " %m%S%p%3y%P%* %~(pad-right 25)G %B\n"
      ;; " %m%S%p%P:%~(pad-right 35)c %3y %B\n"
      ;; " %m%S%p%3y%P%* %~(pad-right 30)C %B\n"
      ;; gnus-topic-line-format "%i[ %(%{%n%}%) -- %A ]%v\n"
      gnus-face-2 'jao-themes-f11
      gnus-topic-line-format "%i %2{%~(pad-right 8)n ┄┄ %A%v%}\n"
      gnus-group-uncollapsed-levels 2
      gnus-auto-select-subject 'unread
      gnus-large-newsgroup 2000)

(add-hook 'gnus-select-group-hook 'gnus-group-set-timestamp)
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

;;; rss
(setq nnrss-use-local t ;; M-x nnrss-generate-download-script
      nnrss-ignore-article-fields '(category
                                    dc:creator
                                    dc:date
                                    enclosure
                                    guid
                                    link
                                    media:content
                                    media:thumbnail
                                    media:title
                                    post-id
                                    pubDate
                                    slash:comments))

(add-to-list 'gnus-parameters `(,(format "nnrss:%s.*"
                                         (regexp-opt jao-gnus-image-groups t))
                                (mm-html-inhibit-images nil)
                                (mm-html-blocked-images nil)))
;;; summary
;;;; configuration
(setq gnus-summary-ignore-duplicates t
      gnus-suppress-duplicates t
      ;; gnus-summary-ignored-from-addresses jao-mails-regexp
      gnus-process-mark-toggle t
      gnus-auto-select-next 'almost-quietly)

;;;; threading
(setq gnus-face-1 'jao-gnus-face-tree
      gnus-show-threads t
      gnus-thread-hide-subtree t
      gnus-build-sparse-threads nil
      gnus-refer-thread-use-search t
      gnus-summary-make-false-root 'adopt
      gnus-summary-gather-subject-limit nil ;; 120
      gnus-summary-thread-gathering-function #'gnus-gather-threads-by-references
      gnus-sort-gathered-threads-function 'gnus-thread-sort-by-date
      gnus-thread-sort-functions '(gnus-thread-sort-by-date))

(defun jao-fix-protonmail-references (header)
  (let ((references (mail-header-references header)))
    (setf (mail-header-references header)
          (mapconcat #'(lambda (x)
                         (if (string-match-p "protonmail.internalid" x) "" x))
                     (gnus-split-references references)
                     " "))
    header))

(setq gnus-alter-header-function 'jao-fix-protonmail-references)

;;;; search on enter nnselect
(defun jao-gnus--maybe-reselect (&rest _i)
  (when (string-match-p "^nnselect" (or (gnus-group-name-at-point) ""))
    (save-excursion (gnus-group-get-new-news-this-group))))

(advice-add 'gnus-group-select-group :before #'jao-gnus--maybe-reselect)

;;;; summary line
(setq gnus-not-empty-thread-mark ?↓) ; ↓) ?·
(setq jao-gnus--summary-line-fmt
      (concat "%%U %%*%%R %%uj "
              "[ %%~(max-right 23)~(pad-right 23)uf "
              " %%I%%~(pad-left 2)t ] %%s"
              "%%-%s="
              "%%~(max-right 8)~(pad-left 8)&user-date;"
              "\n"))

(defun jao-gnus--set-summary-line (&optional w)
  (let* ((d (if jao-gnus-use-three-panes
                (+ jao-gnus-groups-width 11)
              (+ jao-gnus-groups-width 12)))
         (w (or w (if jao-gnus-use-three-panes (window-width) (frame-width))))
         (w (- w d)))
    (setq gnus-summary-line-format (format jao-gnus--summary-line-fmt w))))

(add-hook 'gnus-select-group-hook 'jao-gnus--set-summary-line)

(add-to-list 'nnmail-extra-headers 'Cc)
(add-to-list 'nnmail-extra-headers 'BCc)

(use-package gnus-sum
  :config
  (add-to-list 'gnus-extra-headers 'Cc)
  (add-to-list 'gnus-extra-headers 'BCc))


(defun gnus-user-format-function-j (headers)
  (let ((to (gnus-extra-header 'To headers)))
    (if (string-match jao-mails-regexp to)
        (if (string-match "," to) "¬" "»") ;; "~" "=")
      (if (or (string-match jao-mails-regexp
                            (gnus-extra-header 'Cc headers))
              (string-match jao-mails-regexp
                            (gnus-extra-header 'BCc headers)))
          "¬" ;; "~"
        " "))))

(defconst jao-gnus--news-rx
  (concat (regexp-opt '("ElDiaro.es "
                        "ElDiario.es - ElDiario.es: "
                        "The Guardian: "
                        "Aeon | a world of ideas: "
                        "Planet Debian: "
                        " via The Rust Programming Language Forum"))
          "\\|The Conversation – Articles (.+): "
          "\\|unofficial mirror of [^:]+: "
          "\\|[gq].+ updates on arXiv.org: "))

(defun gnus-user-format-function-f (headers)
  (let* ((from (gnus-header-from headers))
         (from (gnus-summary-extract-address-component from))
         (from (replace-regexp-in-string jao-gnus--news-rx "" from)))
    from))

(setq gnus-user-date-format-alist
      '(((gnus-seconds-today) . "%H:%M")
        ((+ 86400 (gnus-seconds-today)) . "'%H:%M")
        ;; (604800 . "%a %H:%M") ;; that's one week
        ((gnus-seconds-month) . "%a %d")
        ((gnus-seconds-year) . "%b %d")
        (t . "%b '%y")))

;;;; moving messages around
(defvar-local jao-gnus--spam-group nil)
(defvar-local jao-gnus--archiving-group nil)
(defvar-local jao-gnus--archive-as-copy-p nil)

(defvar jao-gnus--last-move nil)
(defun jao-gnus-move-hook (a headers c to d)
  (setq jao-gnus--last-move (cons to (mail-header-id headers))))
(defun jao-gnus-goto-last-moved ()
  (interactive)
  (when jao-gnus--last-move
    (when (eq major-mode 'gnus-summary-mode) (gnus-summary-exit))
    (gnus-group-goto-group (car jao-gnus--last-move))
    (gnus-group-select-group)
    (gnus-summary-goto-article (cdr jao-gnus--last-move) nil t)))
(add-hook 'gnus-summary-article-move-hook 'jao-gnus-move-hook)

(defun jao-gnus-archive (follow)
  (interactive "P")
  (if jao-gnus--archiving-group
      (progn
        (if (or jao-gnus--archive-as-copy-p
                (not (gnus-check-backend-function
                      'request-move-article gnus-newsgroup-name)))
            (gnus-summary-copy-article nil jao-gnus--archiving-group)
          (gnus-summary-move-article nil jao-gnus--archiving-group))
        (when follow (jao-gnus-goto-last-moved)))
    (gnus-summary-mark-as-read)
    (gnus-summary-delete-article)))

(defun jao-gnus-archive-tickingly ()
  (interactive)
  (gnus-summary-tick-article)
  (jao-gnus-archive)
  (when jao-gnus--archive-as-copy-p
    (gnus-summary-mark-as-read)))

(defun jao-gnus-show-tickled ()
  (interactive)
  (gnus-summary-limit-to-marks "!"))

(make-variable-buffer-local
 (defvar jao-gnus--trash-group nil))

(defun jao-gnus-trash ()
  (interactive)
  (gnus-summary-mark-as-read)
  (if jao-gnus--trash-group
      (gnus-summary-move-article nil jao-gnus--trash-group)
    (gnus-summary-delete-article)))

(defun jao-gnus-move-to-spam ()
  (interactive)
  (gnus-summary-mark-as-read)
  (gnus-summary-move-article nil jao-gnus--spam-group))

(define-key gnus-summary-mode-map "Ba" 'jao-gnus-archive)
(define-key gnus-summary-mode-map "BA" 'jao-gnus-archive-tickingly)
(define-key gnus-summary-mode-map "Bl" 'jao-gnus-goto-last-moved)

(define-key gnus-summary-mode-map (kbd "B DEL") 'jao-gnus-trash)
(define-key gnus-summary-mode-map (kbd "B <backspace>") 'jao-gnus-trash)
(define-key gnus-summary-mode-map "Bs" 'jao-gnus-move-to-spam)
(define-key gnus-summary-mode-map "/!" 'jao-gnus-show-tickled)
(define-key gnus-summary-mode-map [f7] 'gnus-summary-force-verify-and-decrypt)

;;;; saving emails
(setq gnus-default-article-saver 'gnus-summary-save-article-mail)
(defvar jao-gnus-file-save-directory (expand-file-name "~/tmp"))
(defun jao-gnus-file-save (newsgroup headers &optional last-file)
  (expand-file-name (format "%s.eml" (mail-header-subject headers))
                    jao-gnus-file-save-directory))
(setq gnus-mail-save-name 'jao-gnus-file-save)

;;;; arXiv capture
(use-package org-capture
  :config
  (add-to-list 'org-capture-templates
               '("x" "arXiv" entry (file "notes/physics/arxiv.org")
                 "* %(jao-gnus-subject)\n\n  %i\n\n  %(jao-gnus-org-url)"
                 :immediate-finish t)
               t)
  (add-to-list 'org-capture-templates
               '("X" "arXiv" entry (file "notes/physics/arxiv.org")
                 "* %(jao-gnus-subject)\n\n%(jao-gnus-org-paragraph \"%i\")"
                 :immediate-finish t)
               t)
  (org-capture-upgrade-templates org-capture-templates))

(defvar jao-gnus-org-url nil)
(defun jao-gnus-org-url () jao-gnus-org-url)
(defun jao-gnus-org-paragraph (x)
  (with-temp-buffer
    (insert "  " (string-trim (or x "")) "\n  ")
    (goto-char 0)
    (fill-paragraph)
    (goto-char (point-max))
    (open-rectangle 0 (point))
    (concat (buffer-string) "\n  " (or jao-gnus-org-url ""))))
(defvar jao-gnus-subject nil)
(defun jao-gnus-subject () jao-gnus-subject)

(defun jao-gnus-arXiv-capture ()
  (interactive)
  (unless (derived-mode-p '(gnus-summary-mode)) (gnus-article-show-summary))
  (setq jao-gnus-subject (gnus-summary-article-subject))
  (gnus-summary-select-article-buffer)
  (gnus-article-goto-part 0)
  (let ((transient-mark-mode t))
    (set-mark (point))
    (forward-paragraph)
    (or (and (save-excursion
               (when (re-search-forward "^Link" nil t)
                 (beginning-of-line)
                 (setq jao-gnus-org-url (org-eww-url-below-point))))
             (org-capture nil "X"))
        (and (save-excursion
               (when (re-search-forward "^URL: " nil t)
                 (setq jao-gnus-org-url (thing-at-point-url-at-point))))
             (org-capture nil "x"))))
  (gnus-article-show-summary))

;;; article
;;;; config, headers
(setq mail-source-delete-incoming t)
(setq gnus-gcc-mark-as-read t)
(setq gnus-treat-display-smileys nil)
(setq gnus-treat-fill-long-lines nil)
(setq gnus-treat-fill-article 120)
(setq gnus-treat-fold-headers nil)
(setq gnus-treat-strip-leading-blank-lines t)
(setq gnus-article-auto-eval-lisp-snippets nil)
(setq gnus-posting-styles '((".*" (name "Jose A. Ortega Ruiz"))))
(setq gnus-single-article-buffer nil)
(setq gnus-article-update-lapsed-header 60)
(setq gnus-article-update-date-headers 60)
(setq gnus-article-truncate-lines t)

(with-eval-after-load "gnus-art"
  (setq gnus-visible-headers
        (concat
         gnus-visible-headers
         "\\|^List-[iI][Dd]:\\|^X-Newsreader:\\|^X-Mailer:"
         "\\|^User-Agent:\\|^X-User-Agent:\\|^X-RSS-Feed:")))

;;;; html and images
(setq  gnus-button-url 'browse-url-generic
       gnus-inhibit-images t
       mm-discouraged-alternatives nil ;; '("text/html" "text/richtext")
       mm-inline-large-images 'resize)

(defvar-local jao-gnus--images nil)

(defun jao-gnus--init-images ()
  (with-current-buffer gnus-article-buffer
    (setq jao-gnus--images nil)))

(add-hook 'gnus-select-article-hook #'jao-gnus--init-images)

(defun jao-gnus-browse-html ()
  (interactive)
  (let ((browse-url-browser-function jao-browse-url-external-function)
        (browse-url-handlers nil)
        (browse-url-default-handlers nil))
    (gnus-article-browse-html-article)))

(defun jao-gnus-show-images ()
  (interactive)
  (if window-system
      (save-window-excursion
        (gnus-summary-select-article-buffer)
        (save-excursion
          (if (and jao-afio-use-w3m (fboundp 'w3m-toggle-inline-images))
              (w3m-toggle-inline-images)
            (setq jao-gnus--images (not jao-gnus--images))
            (if jao-gnus--images
                (gnus-article-show-images)
              (gnus-article-remove-images)))))
    (jao-gnus-browse-html)))

;;;; format from:

(defvar jao-gnus--from-rx
  (concat "From: \\\"?\\( *" jao-gnus--news-rx "\\)"))

(defun jao-gnus-format-from ()
  (save-excursion
    (goto-char (point-min))
    (when (re-search-forward jao-gnus--from-rx nil t)
      (replace-match "" nil nil nil 1))))

(add-hook 'gnus-part-display-hook 'jao-gnus-format-from)

;;;; follow links and enclosures
(defun jao-gnus-follow-link (&optional external)
  (interactive "P")
  (when (eq major-mode 'gnus-summary-mode)
    (gnus-summary-select-article-buffer))
  (save-excursion
    (when-let* ((url (jao-url-email-url)))
      (cond (external (jao-browse-with-external-browser))
            ((featurep 'jao-custom-eww) (eww url))
            (t (browse-url url))))))

(defun jao-gnus-from-eww (keep-eww-buffer)
  (interactive "P")
  (unless keep-eww-buffer (jao-eww-close))
  (jao-afio-goto-mail)
  (gnus-article-show-summary))

(with-eval-after-load 'eww
  (define-key eww-mode-map (kbd "h") #'jao-gnus-from-eww))

(defun jao-gnus-open-enclosure ()
  (interactive)
  (save-window-excursion
    (gnus-summary-select-article-buffer)
    (save-excursion
      (goto-char (point-min))
      (let ((offset (or (and (search-forward-regexp "^Enclosure: ?" nil t) 2)
                        (and (search-forward-regexp "^Enclosure$" nil t) -2))))
        (when offset (forward-char offset))
        (if-let ((url (jao-url-around-point)))
            (jao-mpc-add-or-play-url url)
          (error "No enclosure found"))))))

;;;; delayed messages
(require 'gnus-util)
(gnus-delay-initialize)
(setq gnus-delay-default-delay "3h")
(eval-after-load "message"
  '(setq message-draft-headers (remove 'Date message-draft-headers)))

;;; daemon and exit
(setq gnus-interactive-exit t)
(defun jao-quit-gnus () (gnus-group-exit) t)
(add-hook 'kill-emacs-query-functions #'jao-quit-gnus)

;; daemon config
(setq mail-user-agent 'gnus-user-agent)
(setq gnus-asynchronous t)
(setq gnus-use-article-prefetch nil)
(setq gnus-save-killed-list nil)
(setq gnus-check-new-newsgroups nil)

(require 'gnus-demon)

(defun jao-gnus--scan ()
  (let ((inhibit-message t))
    (gnus-demon-scan-news)
    (jao-shell-exec "notmuch-gnus-tags.sh")
    (when-let* ((a (get-buffer "*Org Agenda*")))
      (with-current-buffer a (org-agenda-redo-all)))
    (jao-gnus--notify)))

(defun jao-gnus--scan-local-mail ()
  (let ((inhibit-message nil))
    (message "Scanning local news in demon...")
    (let ((mail-sources jao-local-mail-sources))
      (gnus-demon-scan-news))
    (jao-gnus--notify)))

(defun jao-gnus-add-demon ()
  (interactive)
  (message "Adding scan demon for Gnus...")
  (gnus-demon-add-handler 'jao-gnus--scan 5 1))

(defun jao-gnus-remove-demon ()
  (interactive)
  (message "Removing scan demon for Gnus...")
  (gnus-demon-remove-handler 'jao-gnus--scan))

(jao-gnus-add-demon)
(gnus-demon-init)

;; this is, in theory, not needed; but at some point in the way to emacs
;; version 31 this idle timers have ceased to work after a sleep/awake cycle
(jao-when-linux (add-to-list 'jao-sleep-awake-functions #'jao-gnus-add-demon))

;;; add-ons
;;;; notifications
;;;;; minibuffer
(defvar jao-gnus--notify-strs ())

(defun jao-gnus--xbar-echo ()
  (let* ((total (cdr (assoc "Gnus" gnus-topic-unreads)))
         (jao (cdr (assoc "jao" gnus-topic-unreads)))
         (str (concat (when (> total 0) (format "%d" total))
                      " "
                      (when (> jao 0) (format "J%d" jao)))))
    (jao-shell-exec
     (format "echo '%s | color=#8b3626 | size=11' >/tmp/xbar" str))))

(defvar jao-gnus-group-notifications
  '(("Gnus" "" jao-themes-dimm)
    ("jao" "J" jao-themes-warning)
    ("news" "N" jao-themes-dimm)
    ("prog" "P" jao-themes-dimm)
    ("sci" "S" jao-themes-dimm)))

(defun jao-gnus--notify-group-str (p)
  (let* ((n (cdr p))
         (f (cdr (assoc (car p) jao-gnus-group-notifications))))
    (when (and f (> n 0))
      `(:propertize ,(format "%s%d " (car f) n) face ,(cadr f)))))

(defun jao-gnus--notify ()
  (setq jao-gnus--notify-strs
        (seq-keep 'jao-gnus--notify-group-str gnus-topic-unreads))
  (jao-when-darwin (jao-gnus--xbar-echo))
  (jao-minibuffer-refresh))

(with-eval-after-load "jao-minibuffer"
  (jao-minibuffer-add-variable 'jao-gnus--notify-strs -20))

(add-hook 'gnus-started-hook #'jao-gnus--notify)
;; (add-hook 'gnus-summary-exit-hook #'jao-gnus--notify)
(add-hook 'gnus-after-getting-new-news-hook #'jao-gnus--notify)

;;;;; agenda and other updates on summary exit
(let ((exit-count 0))
  (defun jao-gnus--on-summary-exit ()
    (when (> (setq exit-count (+ 1 exit-count)) 20)
      (setq exit-count 0)
      (jao-org-agenda))
    (jao-gnus--notify)))

(add-hook 'gnus-summary-exit-hook #'jao-gnus--on-summary-exit)
(add-hook 'gnus-exit-group-hook #'jao-gnus--notify)

;;;; open mail file in gnus
(defun jao-gnus-file-to-group (file &optional maildir newsdir m-server n-server)
  "Compute the Gnus group name from the given file name.
  IN: /home/jao/.emacs.d/gnus/Mail/jao.trove/32, /home/jao/.emacs.d/gnus/Mail/
  OUT: nnml:jao.trove "
  (let* ((maildir (or maildir message-directory))
         (newsdir (or newsdir jao-gnus-leafnode-spool))
         (m-server (or m-server "nnml"))
         (n-server (or n-server "nntp+localhost"))
         (nntp (and newsdir (string-match-p newsdir file)))
         (g (directory-file-name (file-name-directory file)))
         (g (replace-regexp-in-string (file-name-as-directory maildir) "" g))
         (g (replace-regexp-in-string (file-name-as-directory newsdir) "" g))
         (g (cond (nntp (concat n-server ":" g))
                  ((file-name-directory g)
                   (replace-regexp-in-string "^\\([^/]+\\)/"
                                             (concat m-server ":\\1/")
                                             (file-name-directory g) t))
                  (t (concat m-server ":" g))))
         (g (replace-regexp-in-string "/" "." g))
         (g (replace-regexp-in-string "[/.]$" "" g)))
    (cond ((string-match ":$" g) (concat g "inbox"))
          (nntp g)
          (t (replace-regexp-in-string ":\\." ":" g)))))

(defun jao-gnus-goto-file (filename &optional _page)
  (let ((group (jao-gnus-file-to-group filename))
        (id (file-name-nondirectory filename)))
    (if (and group id)
        (org-gnus-follow-link group id)
      (message "Couldn't get relevant info for switching to Gnus."))))

;;;; afio
(defun jao-gnus--on-afio-switch ()
  (when (derived-mode-p 'gnus-group-mode)
    (jao-gnus--notify)
    (let ((no (or (gnus-group-unread (gnus-group-group-name)) 0)))
      (unless (> no 0) (gnus-group-first-unread-group)))))

(add-hook 'jao-afio-switch-hook #'jao-gnus--on-afio-switch)

(defun jao-gnus-refresh-workspace ()
  (interactive)
  (save-window-excursion (calendar) (jao-org-agenda)))

;;;; gnus-icalendar
(require 'ol-gnus)
(use-package gnus-icalendar
  :demand t
  :init (setq gnus-icalendar-org-capture-file
              (expand-file-name "inbox.org" org-directory)
              gnus-icalendar-org-capture-headline '("Appointments"))
  :config (gnus-icalendar-org-setup))

;;;; bbdb
(with-eval-after-load "bbdb"
  ;; (bbdb-initialize 'gnus 'message 'pgp)
  (bbdb-mua-auto-update-init 'gnus)
  (with-eval-after-load "gnus-sum"
    (define-key gnus-summary-mode-map ":" 'bbdb-mua-annotate-sender)
    (define-key gnus-summary-mode-map ";" 'bbdb-mua-annotate-recipients)))

;;;; randomsig
(with-eval-after-load "randomsig"
  (with-eval-after-load "gnus-sum"
    (define-key gnus-summary-save-map "-" 'gnus/randomsig-summary-read-sig)))

;;;; recoll
(unless jao-notmuch-enabled
  (with-eval-after-load "org"
    (org-link-set-parameters "message" :follow #'jao-gnus-goto-file))
  (with-eval-after-load "consult-recoll"
    (add-to-list 'consult-recoll-open-fns
                 '("message/rfc822" . jao-gnus-goto-file))))
;;;; notmuch
(use-package jao-notmuch-gnus
  :demand t
  :init
  (jao-when-darwin
   (setq jao-notmuch-gnus-mail-directory
         (expand-file-name "gnus" jao-maildir))))

(jao-load-path "consult-notmuch")

(use-package consult-notmuch
  :ensure t
  :bind (:map gnus-group-mode-map ("/" . #'jao-gnus-consult-notmuch)))

;;; keyboard shortcuts
(define-key gnus-article-mode-map "i" 'jao-gnus-show-images)
(define-key gnus-summary-mode-map "i" 'jao-gnus-show-images)
(define-key gnus-article-mode-map "\M-g" 'jao-gnus-follow-link)
(define-key gnus-summary-mode-map "\M-g" 'jao-gnus-follow-link)
(define-key gnus-summary-mode-map "v" 'scroll-other-window)
(define-key gnus-summary-mode-map "V" 'scroll-other-window-down)
(define-key gnus-summary-mode-map "X" 'jao-gnus-arXiv-capture)
(define-key gnus-summary-mode-map "e" 'jao-gnus-open-enclosure)
(define-key gnus-summary-mode-map "\C-l" nil)
(define-key gnus-group-mode-map "a" 'jao-gnus-refresh-workspace)

(jao-when-darwin
 (define-key gnus-group-mode-map "O" 'jao-mac-open-nnw))
