;;; -*- lexical-binding: t; -*-
;;; minibuffer
(defvar jao-notmuch-minibuffer-string "")

(defvar jao-notmuch-minibuffer-queries
  `((:name "" :query "tag:new and not tag:draft" :face jao-themes-f00)
    (:name "I" :query "tag:new and tag:inbox" :face jao-themes-warning)
    (:name "W" :query "tag:new and tag:write" :face jao-themes-warning)
    (:name "J"
           :query
           ,(concat "tag:new and not "
                    "tag:\"/feeds|local|hacking|draft|inbox|prog|words|write/\"")
           :face default)
    (:name "h" :query "tag:new and tag:hacking and not tag:\"/emacs/\"")
    (:name "e" :query "tag:new and tag:\"/emacs/\"")
    (:name "l" :query "tag:new and tag:local")
    (:name "f" :query "tag:new and tag:feeds and not tag:\"/emacs/\"")))

(defvar jao-notmuch-mac-mail-badge nil
  "Name of Mac mail app showing, besides emacs")
(defvar jao-notmuch-mac-hammerspoon (jao-is-darwin))

(defun jao-notmuch-hammerspoon ()
  (jao-when-darwin
   (let ((s (substring-no-properties jao-notmuch-minibuffer-string)))
     (jao-mac-open "-g 'hammerspoon://menu?message=%s&key=notmuch'"
                   (url-hexify-string s)))))

(defun jao-notmuch--qstr (c)
  (propertize (format "%s%s" (plist-get c :name) (plist-get c :count))
              'face (or (plist-get c :face) 'jao-themes-dimm)))

(defun jao-notmuch-notify ()
  (interactive)
  (let* ((cnts (notmuch-hello-query-counts jao-notmuch-minibuffer-queries))
         (mc (jao-d-l
              (when jao-notmuch-mac-mail-badge
                (jao-mac-app-badge jao-notmuch-mac-mail-badge))
              0))
         (cnts (if mc (cons `(:name "" :count ,(format "[%s]" mc)) cnts) cnts)))
    (setq jao-notmuch-minibuffer-string (mapconcat #'jao-notmuch--qstr cnts " "))
    (when jao-notmuch-mac-hammerspoon (jao-notmuch-hammerspoon))
    (jao-minibuffer-refresh)))

(defun jao-notmuch-notify-and-update (&optional first agenda)
  (jao-notmuch-notify)
  (with-current-buffer "*notmuch-hello*"
    (notmuch-hello-update)
    (when first (jao-notmuch-hello-first))
    (when agenda (jao-notmuch-refresh-agenda))))

(when jao-notmuch-enabled
  (jao-minibuffer-add-variable 'jao-notmuch-minibuffer-string -20))

;;; saved searches
(defvar jao-notmuch--new nil)
(defvar jao-notmuch--new-rx nil)
(defvar jao-notmuch--newa nil)

(defun jao-notmuch--tags-q (tags)
  (format "tag:\"/^(%s)$/\"" (mapconcat (lambda (s) (format "%s" s)) tags "|")))

(defun jao-notmuch--new (&rest tags)
  (cond ((listp jao-notmuch--new)
         (jao-notmuch--tags-q (append jao-notmuch--new tags)))
        (tags (concat jao-notmuch--new " OR " (jao-notmuch--tags-q tags)))
        (t jao-notmuch--new)))

(defun jao-notmuch--set-new-search (s)
  (setq jao-notmuch--new s
        jao-notmuch--new-rx (regexp-quote (jao-notmuch--new))
        jao-notmuch--newa (concat (jao-notmuch--new) " AND ")))

(defun jao-notmuch--q (d0 &optional k d1 qs st)
  (let* ((qs (when qs (mapconcat (lambda (q) (format "%s" q)) qs " AND ")))
         (q (or qs
                (concat (jao-notmuch--new)
                        (mapconcat (lambda (d) (when d (concat " AND tag:" d)))
                                   (list d0 d1))))))
    (list :name (concat d0 (when (and d1 (not (string= "" d1))) "/") d1)
          :key k :query q :search-type (or st 'tree)
          :sort-order 'oldest-first)))

(defun jao-notmuch--q-feed (q)
  (apply #'jao-notmuch--q (cons "feeds" q)))

(defun jao-notmuch-tree-widen-search ()
  (interactive)
  (when-let* ((query (notmuch-tree-get-query)))
    (let ((notmuch-show-process-crypto (notmuch-tree--message-process-crypto)))
      (notmuch-tree-close-message-window)
      (notmuch-tree (string-replace jao-notmuch--newa "" query)))))

(defun jao-notmuch--widen (s &optional extra)
  (let* ((q (plist-get s :query))
         (qs (string-replace jao-notmuch--newa "" q)))
    (plist-put (copy-sequence s) :query (concat qs extra))))

(defun jao-notmuch-widen-searches (searches &optional extra)
  (mapcar (lambda (s) (jao-notmuch--widen s extra)) searches))

(defun jao-notmuch-hello--insert-searches (searches title)
  (when-let* ((searches (notmuch-hello-query-counts searches)))
    (let* ((cnt (when title
                  (seq-reduce (lambda (c q)
                                (+ c (or (plist-get q :count) 0)))
                              searches
                              0)))
           (title (if title (format "[ %d %s ]\n\n" cnt title) "\n"))
           (notmuch-column-control 1.0))
      (widget-insert (propertize title 'face 'jao-themes-f00))
      (notmuch-hello-insert-buttons searches))))

(defun jao-notmuch--replace (lst s)
  (let ((name (plist-get s :name)))
    (set lst (seq-remove (lambda (s0) (string= name (plist-get s0 :name)))
                         (symbol-value lst)))
    (add-to-list lst s t)))

(defun jao-notmuch--def-searches (name searches &optional no-save)
  (declare (indent 1))
  (unless no-save
    (dolist (s searches)
      (jao-notmuch--replace 'jao-notmuch-widened-searches
                            (jao-notmuch--widen s))
      (jao-notmuch--replace 'notmuch-saved-searches s)))
  (add-to-list 'notmuch-hello-sections
               `(jao-notmuch-hello--insert-searches ,searches ,name)
               t))

(defvar jao-notmuch-widened-searches nil)

(defun jao-notmuch-init-searches (s &optional other)
  (jao-notmuch--set-new-search s)

  (setq notmuch-hello-sections nil
        notmuch-saved-searches nil
        jao-notmuch-widened-searches nil)

  (when other (jao-notmuch--def-searches (car other) (cdr other))))

(defun jao-notmuch-define-personal-searches ()
  (jao-notmuch--def-searches "inbox"
    `(,(jao-notmuch--q "inbox" "i")
      ,(jao-notmuch--q "write" "w")
      ,(jao-notmuch--q "drivel" "d")
      ,(jao-notmuch--q "trove" "t")
      ,(jao-notmuch--q "local" "x")))

  (jao-notmuch--def-searches "news"
    (mapcar 'jao-notmuch--q-feed
            '(("fn" "news")
              ("fd" "noticias")
              ("ff" "fun")
              ("fw" "words")
              ("fc" "computers")
              ("fp" "pens"))))

  (jao-notmuch--def-searches "hacking"
    `(,(jao-notmuch--q "hacking" "h")
      ,(jao-notmuch--q "prog" "p")
      ,@(mapcar 'jao-notmuch--q-feed
                '(("lc" "clojure")
                  ("le" "emacs")
                  ("lg" "geiser")
                  ("lh" "haskell")
                  ("ll" "lisp")
                  ("ln" "notmuch")
                  ("lr" "rust")
                  ("ls" "scheme")
                  ("lx" "xmobar")))))

  (jao-notmuch--def-searches "sci"
    (mapcar 'jao-notmuch--q-feed
            '(("sp" "philosophy")
              ("sm" "math")
              ("sp" "physics")
              ("ss" "sci")
              ("sg" "gr-qc")
              ("sq" "quant-ph")))))

(defun jao-notmuch-define-flag-searches ()
  (jao-notmuch--def-searches "flags"
    (jao-notmuch-widen-searches notmuch-saved-searches " AND tag:flagged")
    t)
  (jao-notmuch--def-searches nil
    `(,(jao-notmuch--q "flagged" "F" nil '("tag:flagged")))))

(defun jao-notmuch-define-summary-searches ()
  (jao-notmuch-define-flag-searches)

  (jao-notmuch--def-searches "today"
    `(,(jao-notmuch--q "new" "N" nil (list (jao-notmuch--new) "not tag:draft"))
      ,(jao-notmuch--q "drafts" "D" nil '("tag:draft") t)
      ,(jao-notmuch--q "sent" "S" nil '("date:1d.." "tag:sent") t)
      ,(jao-notmuch--q "today" "T" nil
                       '("date:24h.." "not tag:\"/(sent|feeds|spam|local)/\"")
                       t)))

  (jao-notmuch--def-searches "trove"
    `((:query "tag:trove" :name "trove" :search-type tree)
      (:query "tag:hacking" :name "hacking" :search-type tree)
      (:query "not tag:trove and not tag:hacking" :name "untroved"
              :search-type tree)
      (:query "tag:sent" :name "sent")))

  (jao-notmuch--def-searches nil
    '((:query "*" :name "messages" :search-type tree))))

(defun jao-notmuch-define-searches (s &optional other skip-jao)
  (jao-notmuch-init-searches s other)
  (unless skip-jao (jao-notmuch-define-personal-searches))
  (jao-notmuch-define-summary-searches)
  ;; (add-to-list 'notmuch-hello-sections 'notmuch-hello-insert-alltags t)

  (when (display-graphic-p)
    (add-to-list 'notmuch-hello-sections '(insert " "))))

(jao-notmuch-define-searches '(unread new))

(defun jao-notmuch-jump-search (&optional widen)
  (interactive "P")
  (let ((notmuch-saved-searches
         (if widen jao-notmuch-widened-searches notmuch-saved-searches)))
    (notmuch-jump-search)))

(defun jao-notmuch--searches-w/new (searches)
  (seq-filter (lambda (s)
                (string-match-p jao-notmuch--new-rx (plist-get s :query)))
              (notmuch-hello-query-counts searches)))

(defconst jao-notmuch--search-keys '("a" "s" "d" "f" "g" "h" "j" "k" "l"))

(defun jao-notmuch--index-searches (searches)
  (seq-map-indexed (lambda (q i)
                     (plist-put q :key (or (elt jao-notmuch--search-keys i)
                                           (format "%s" i))))
                   searches))

(defun jao-notmuch-jump ()
  "Jump to a saved, non-zero count search."
  (interactive)
  (if-let* ((searches (jao-notmuch--searches-w/new notmuch-saved-searches)))
      (if (= 2 (length searches))
          (let* ((q (seq-remove (lambda (q) (string= "new" (plist-get q :name)))
                                searches))
                 (q (car q))
                 (of (eq 'oldest-first (plist-get q :sort-order)))
                 (query (plist-get q :query)))
            (notmuch-tree query nil nil nil nil nil nil of t))
        (let ((notmuch-saved-searches (jao-notmuch--index-searches searches)))
          (notmuch-jump-search)))
    (jao-notmuch-jump-search t)))

;;; tags
(defvar jao-notmuch--shared-tags
  '("new" "unread" "flagged" "signed" "sent" "attachment" "forwarded" "inbox"
    "encrypted" "gmane" "gnus" "feeds" "rss" "mce" "trove" "prog" "emacs"))

(setq notmuch-archive-tags
      '("+trove" "-hacking" "-new" "-drivel" "-words" "-inbox")
      notmuch-show-mark-read-tags '("-new" "-unread")
      notmuch-tag-formats
      (let (;; (d `(:foreground ,(face-attribute 'jao-themes-dimm :foreground)))
            (e `(:foreground ,(face-attribute 'jao-themes-error :foreground))))
        `(("attachment" "⧺")
          ("bigml" "b")
          ("deleted" "⛒" (propertize tag 'face '(:underline nil ,@e)))
          ("feeds" "f")
          ("flagged" "✓")
          ("forwarded" "→")
          ("gmane" "g")
          ("jao")
          ("lists" "l")
          ("new" "·")
          ("replied" "↩" (propertize tag 'face '(:family "Fira Code")))
          ("sent" "↑")
          ("signed")
          ("unread")))
      notmuch-tag-deleted-formats
      '(("unread")
        ("new")
        ("flagged")
        ("deleted")
        (".*" (notmuch-apply-face tag 'notmuch-tag-deleted))))

(with-eval-after-load "notmuch-tag"
  (advice-add #'notmuch-read-tag-changes
              :filter-return (lambda (x) (mapcar #'string-trim x))))

;;; package
;; (add-to-list 'load-path "/usr/local/share/emacs/site-lisp/")
(jao-load-path "notmuch")

(use-package notmuch
  :init
  (setq notmuch-address-use-company t
        notmuch-address-command 'as-is
        notmuch-always-prompt-for-sender t
        notmuch-draft-folder "drafts"
        notmuch-draft-quoted-tags '("part")
        notmuch-fcc-dirs '((".*" . "sent -new -unread +sent +jao"))
        notmuch-maildir-use-notmuch-insert t)

  :custom ((notmuch-address-internal-completion '(sent nil)))

  :config

  (add-hook 'message-send-hook #'notmuch-mua-attachment-check)

  (when jao-notmuch-enabled
    (define-key message-mode-map (kbd "C-c C-d") #'notmuch-draft-postpone)
    (setq message-directory (file-name-as-directory jao-maildir)
          message-auto-save-directory "/tmp"
          mail-user-agent 'message-user-agent))

  :bind (:map notmuch-common-keymap
         (("E" . jao-notmuch-open-enclosure)
          ("B" . notmuch-show-resend-message)
          ("b" . jao-notmuch-browse-urls))))

(use-package jao-notmuch :demand t)

;;; hello
(defun jao-notmuch-refresh-agenda ()
  (interactive)
  (save-window-excursion (calendar) (jao-org-agenda)))

(defun jao-notmuch-hello-first ()
  (interactive)
  (let ((inhibit-message t))
    (goto-char (point-min))
    (widget-forward 1)))

(defun jao-notmuch-refresh-hello (&optional agenda)
  (interactive "P")
  (ignore-errors
    (when (and (string= "mail" (jao-afio-frame-name))
               (derived-mode-p 'notmuch-hello-mode))
      (when (not (string-blank-p jao-notmuch-minibuffer-string))
        (let ((notmuch-hello-auto-refresh nil)) (notmuch-hello)))
      (let ((jao-minibuffer-inhibit t))
        (when agenda (jao-notmuch-refresh-agenda)))
      (unless (widget-at) (jao-notmuch-hello-first))
      (jao-minibuffer-refresh))))

(defvar jao-notmuch-hello--sec-rx "^\\(\\[ [0-9]+\\|All tags:.+\\)")

(defun jao-notmuch-hello-next-section ()
  (interactive)
  (when (re-search-forward jao-notmuch-hello--sec-rx  nil t)
    (widget-forward 1)))

(defun jao-notmuch-hello-prev-section ()
  (interactive)
  (beginning-of-line)
  (unless (looking-at-p jao-notmuch-hello--sec-rx)
    (re-search-backward jao-notmuch-hello--sec-rx nil t))
  (when (re-search-backward jao-notmuch-hello--sec-rx  nil t)
    (end-of-line)
    (widget-forward 1)))

(defun jao-notmuch-hello-next ()
  (interactive)
  (if (widget-at)
      (widget-button-press (point))
    (jao-notmuch-hello-next-section)))

(use-package notmuch-hello
  :init
  (setq notmuch-column-control 1.0
        notmuch-hello-hide-tags nil
        notmuch-hello-thousands-separator ","
        notmuch-hello-auto-refresh t
        notmuch-show-all-tags-list nil
        notmuch-show-logo nil
        notmuch-show-empty-saved-searches nil)

  (add-to-list 'display-buffer-alist
               '("\\*notmuch-hello\\*"
                 (display-buffer-reuse-window)
                 (body-function . (lambda (w) (set-window-margins w 1)))))

  :hook ((notmuch-hello-refresh . jao-notmuch-notify))

  :config
  (when jao-notmuch-enabled
    (add-hook 'jao-afio-switch-hook #'jao-notmuch-refresh-hello))

  :bind (("s-j" . jao-notmuch-jump)
         :map notmuch-hello-mode-map
              (("a" . jao-notmuch-refresh-agenda)
               ("A" . jao-afio-open-mail)
               ("g" . jao-notmuch-refresh-hello)
               ("j" . jao-notmuch-jump-search)
               ("n" . jao-notmuch-hello-next)
               ("p" . widget-backward)
               ("SPC" . widget-button-press)
               ("/" . consult-notmuch)
               ("." . jao-notmuch-hello-first)
               ("[" . jao-notmuch-hello-prev-section)
               ("]" . jao-notmuch-hello-next-section))))

;;; show
(defun jao-notmuch-open-enclosure (add)
  (interactive "P")
  (with-current-notmuch-show-message
   (goto-char (point-min))
   (if (not (search-forward "Enclosure:" nil t))
       (user-error "No enclosure in message body")
     (re-search-forward "https?://" nil t)
     (if-let* ((url (thing-at-point-url-at-point)))
         (progn
           (message "%s %s ..." (if add "Adding" "Playing") url)
           (unless add (jao-mpc-clear))
           (jao-mpc-add-url url)
           (unless add (jao-mpc-play)))
       (error "Found an enclosure, but not a link!")))))

(defconst jao-mail-clean-rx
  (regexp-opt '("ElDiario.es - ElDiario.es: "
                "The Guardian: "
                "The Conversation – Articles (UK): "
                "gr-qc updates on arXiv.org: "
                "quant-ph updates on arXiv.org: "
                " via The Rust Programming Language Forum"
                "unofficial mirror of emacs-devel@gnu.org: "
                "Planet Scheme: ")))

(defun jao-mail-clean-address (args)
  (when-let* ((address (car args)))
    (list (thread-last (replace-regexp-in-string jao-mail-clean-rx "" address)
                       (replace-regexp-in-string "        " ", ")))))

(defun jao-notmuch-open-in-mac-mail ()
  (interactive)
  (jao-d-l
   (when-let* ((id (ignore-errors (notmuch-show-get-message-id))))
     (jao-mac-open "message://%%3C%s%%3E" (substring id 3)))
   (message "Only available in macs!")))

(use-package notmuch-show
  :init
  (setq gnus-blocked-images "."
        notmuch-message-headers
        '("Subject" "To" "Cc" "Date" "Reply-To" "List-Id" "X-RSS-Feed")
        notmuch-show-only-matching-messages t
        notmuch-show-part-button-default-action 'notmuch-show-view-part
        notmuch-wash-signature-lines-max 0
        notmuch-wash-wrap-lines-length 120
        notmuch-wash-citation-lines-prefix 120
        notmuch-wash-citation-lines-suffix 120
        notmuch-show-text/html-blocked-images "."
        notmuch-show-header-line nil ;; #'jao-notmuch-message-header-line
        jao-notmuch-header-line-format "[%N / %M / %T] %n / %m / %t")

  :config

  (advice-add 'notmuch-clean-address :filter-args #'jao-mail-clean-address)
  (add-hook 'notmuch-show-mode-hook (lambda () (setq fill-column 80)))

  :bind
  (:map notmuch-show-mode-map
        (("h" . jao-notmuch-goto-tree-buffer)
         ("r" . notmuch-show-reply)
         ("R" . notmuch-show-reply-sender)
         ("TAB" . jao-notmuch-show-next-button)
         ([backtab] . jao-notmuch-show-previous-button)
         ("RET" . jao-notmuch-show-ret)
         ("M" . jao-notmuch-open-in-mac-mail))))

;;; search
(use-package notmuch-search
  :init (setq notmuch-search-result-format
              '(("date" . "%12s ")
                ("count" . "%-7s ")
                ("authors" . "%-35s")
                ("subject" . " %-100s")
                ;; (jao-notmuch-format-tags . "  (%s)")
                )
              notmuch-search-buffer-name-format "*%s*"
              notmuch-saved-search-buffer-name-format "*%s*")
  :bind (:map notmuch-search-mode-map
         (("RET" . notmuch-tree-from-search-thread)
          ("M-RET" . notmuch-search-show-thread))))

;;; tree
(defun jao-notmuch-tree--forward (&optional prev)
  (interactive)
  (forward-line (if prev -1 1))
  (when prev (forward-char 2))
  (jao-notmuch-tree-scroll-or-next))

(defun jao-notmuch-tree--backward ()
  (interactive)
  (jao-notmuch-tree--forward t))

(defun jao-notmuch--via-url ()
  (when (window-live-p notmuch-tree-message-window)
    (with-selected-window notmuch-tree-message-window
      (jao-url-email-url))))

(defun jao-notmuch-browse-url (ext)
  (interactive "P")
  (when-let* ((url (or (jao-notmuch--via-url)
                       (car (last (jao-notmuch-message-urls))))))
    (if ext
        (funcall browse-url-secondary-browser-function url)
      (window-configuration-to-register ?H)
      (select-window notmuch-tree-message-window)
      (eww url))))

(defun jao-notmuch-from-eww (keep-eww-buffer)
  (interactive "P")
  (unless keep-eww-buffer (jao-eww-close))
  (jump-to-register ?H))

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

(defun jao-notmuch-adjust-tree-fonts (&optional family)
  (let ((fg (face-attribute 'jao-themes-dimm :foreground)))
    (dolist (f '(notmuch-tree-match-tree-face
                 notmuch-tree-no-match-tree-face))
      (if family
          (set-face-attribute f nil :family family :foreground fg)
        (set-face-attribute f nil :foreground fg)))))

(use-package notmuch-tree
  :init
  (setq notmuch-tree-result-format
        `(("date" . "%12s  ")
          ("authors" . "%-25s")
          ;; (jao-notmuch-format-author . 25)
          (jao-notmuch-format-msg-ticks . ,jao-mails-regexp)
          (jao-notmuch-format-tree-and-subject . "%>-85s")
          ;; (jao-notmuch-format-tags . "  (%s)")
          )
        notmuch-unthreaded-result-format notmuch-search-result-format
        consult-notmuch-result-format
        `((jao-notmuch-format-msg-ticks . ,jao-mails-regexp)
          ("date" . "%12s  ")
          (jao-notmuch-format-authors . 99)
          ("subject" . " %-100s")
          (jao-notmuch-format-tags . "  (%s)"))
        notmuch-tree-thread-symbols
        '((prefix . "─") (top . "─") (top-tee . "┬")
          (vertical . "│") (vertical-tee . "├") (bottom . "╰")
          (arrow . ""))
        ;; notmuch-tree-thread-symbols
        ;; '((prefix . " ") (top . " ") (top-tee . " ")
        ;;   (vertical . " ") (vertical-tee . " ") (bottom . " ")
        ;;   (arrow . ""))
        notmuch-tree-outline-enabled t
        notmuch-tree-outline-visibility 'hide-others
        notmuch-tree-outline-auto-close t
        notmuch-tree-outline-open-on-next t)
  :config

  (when (display-graphic-p)
    (jao-notmuch-adjust-tree-fonts
     (when (string-prefix-p "Hack" jao-themes-default-face) "Source Code Pro")))

  (defun jao-notmuch-before-tree (&rest _args)
    (window-configuration-to-register ?G)
    (when (string= (buffer-name) "*notmuch-hello*")
      (when (< (frame-width) 230) (delete-other-windows))
      (split-window-right 40)
      (other-window 1)))

  (defun jao-notmuch-after-tree-quit (&optional _both)
    (when (not (derived-mode-p 'notmuch-tree-mode 'notmuch-hello-mode))
      (jump-to-register ?G)
      (jao-notmuch-notify-and-update t t)))

  (defvar jao-notmuch--visits 0)

  (defun jao-notmuch-tree--sentinel (proc)
    (when (eq (process-status proc) 'exit)
      (let ((inhibit-read-only t))
        (save-excursion
          (goto-char (point-max))
          (when (re-search-backward "^End of search results." nil t)
            (delete-line))))
      (jao-notmuch-thread-info-mode)))

  (add-hook 'notmuch-tree-process-exit-functions #'jao-notmuch-tree--sentinel)

  (defun jao-notmuch-use-two-panes ()
    (interactive)
    (advice-add 'notmuch-tree :before #'jao-notmuch-before-tree)
    (advice-add 'notmuch-tree-quit :after #'jao-notmuch-after-tree-quit))

  (defun jao-notmuch-use-one-pane ()
    (interactive)
    (jao-afio-add-frame-parameters mail (width . 120) (height . 75))
    (advice-remove 'notmuch-tree #'jao-notmuch-before-tree)
    (advice-remove 'notmuch-tree-quit #'jao-notmuch-after-tree-quit))

  (when jao-notmuch-enabled
    ;; (jao-d-l (jao-notmuch-use-one-pane) (jao-notmuch-use-two-panes))
    (jao-notmuch-use-two-panes)
    )

  :bind (:map notmuch-tree-mode-map
              (("b" . jao-notmuch-browse-urls)
               ("d" . jao-notmuch-tree-toggle-delete)
               ("D" . jao-notmuch-tree-toggle-delete-thread)
               ("E" . jao-notmuch-open-enclosure)
               ("h" . jao-notmuch-goto-message-buffer)
               ("i" . jao-notmuch-toggle-images)
               ("k" . jao-notmuch-tree-read-thread)
               ("K" . jao-notmuch-tree-mark-all-read)
               ("N" . jao-notmuch-tree--forward)
               ("M" . jao-notmuch-open-in-mac-mail)
               ("O" . notmuch-tree-toggle-order)
               ("o" . jao-notmuch-tree-widen-search)
               ("P" . jao-notmuch-tree--backward)
               ("r" . notmuch-tree-reply)
               ("R" . notmuch-tree-reply-sender)
               ("s" . jao-notmuch-tree-toggle-spam)
               ("u" . jao-notmuch-tree-toggle-flag)
               ("v" . notmuch-tree-scroll-message-window)
               ("V" . notmuch-tree-scroll-message-window-back)
               ("x" . jao-notmuch-arXiv-capture)
               ("<" . jao-notmuch-tree-beginning-of-buffer)
               (">" . jao-notmuch-tree-end-of-buffer)
               ("\\" . notmuch-tree-view-raw-message)
               ("." . jao-notmuch-toggle-mime-parts)
               (";" . bbdb-mua-display-sender)
               ("=" . jao-notmuch-tree-toggle-message)
               ("RET" . jao-notmuch-tree-show-or-scroll)
               ("SPC" . jao-notmuch-tree-scroll-or-next)
               ("M-g" . jao-notmuch-browse-url)
               ("M-u" . jao-notmuch-tree-reset-tags))))

;;; browse-url
(defvar jao-notmuch-url-rx "^notmuch:\\(/+\\|id:\\)\\(.+\\)")

(defun jao-notmuch-open-url (url &rest _)
  (and (string-match jao-notmuch-url-rx url)
       (notmuch-show (concat "id:" (match-string 2 url)))))

(add-to-list 'browse-url-handlers
             (cons jao-notmuch-url-rx 'jao-notmuch-open-url))

;;; org mode
(defvar jao-org-notmuch-last-subject nil)
(defun jao-org-notmuch-last-subject () jao-org-notmuch-last-subject)

(defun jao-notmuch--add-tags (tags)
  (if (derived-mode-p 'notmuch-show-mode)
      (notmuch-show-add-tag tags)
    (notmuch-tree-add-tag tags)))

(defun org-notmuch-store-link ()
  "Store a link to a notmuch mail message."
  (cl-case major-mode
    ((notmuch-show-mode notmuch-tree-mode)
     ;; Store link to the current message
     (let* ((id (notmuch-show-get-message-id))
            (link (concat "notmuch:" id))
            (subj (notmuch-show-get-subject))
            (description (format "Mail: %s" subj)))
       (setq jao-org-notmuch-last-subject subj)
       (when (y-or-n-p "Archive message? ")
         (jao-notmuch--add-tags '("+trove")))
       (when (y-or-n-p "Flag message? ")
         (jao-notmuch--add-tags '("+flagged")))
       (org-link-store-props :type "notmuch"
                             :link link
                             :description description)))
    (notmuch-search-mode
     ;; Store link to the thread on the current line
     (let* ((id (notmuch-search-find-thread-id))
            (link (concat "notmuch:" id))
            (subj (notmuch-search-find-subject))
            (description (format "Mail: %s" subj)))
       (setq jao-org-notmuch-last-subject subj)
       (org-link-store-props
        :type "notmuch"
        :link link
        :description description)))))

(with-eval-after-load "org"
  (org-link-set-parameters "notmuch"
                           :follow 'notmuch-show
                           :store 'org-notmuch-store-link))
;;; arXiv
(use-package org-capture
  :config
  (when jao-notmuch-enabled
    (add-to-list 'org-capture-templates
                 '("X" "arXiv" entry (file "notes/physics/arxiv.org")
                   "* %(jao-org-notmuch-last-subject)\n %i"
                   :immediate-finish t)
                 t)
    (org-capture-upgrade-templates org-capture-templates)))

(defun jao-notmuch-arXiv-capture ()
  (interactive)
  (save-window-excursion
    (jao-notmuch-goto-message-buffer)
    (save-excursion
      (goto-char (point-min))
      (re-search-forward "\\[ text/html \\]")
      (forward-paragraph)
      (setq-local transient-mark-mode 'lambda)
      (set-mark (point))
      (goto-char (point-max))
      (org-capture nil "X"))))

;;; html renderer

;; we can use the default defined in jao-custom-ewww
;; (when jao-notmuch-enabled (setq mm-text-html-renderer 'shr))

;;; consult
(jao-when-linux
 (jao-load-path "consult-notmuch")
 (require 'consult-notmuch)
 (setq consult-notmuch-newest-first t)
 (consult-customize consult-notmuch :preview-key 'any)

 (defvar jao-consult-notmuch-history nil)

 (defvar jao-mailbox-folders '("bigml" "jao"))

 (defun jao-consult-notmuch-folder (&optional tree folder)
   (interactive "P")
   (let* ((folder (if folder
                      (file-name-as-directory folder)
                    (completing-read "Group: "
                                     jao-mailbox-folders
                                     nil nil nil
                                     jao-consult-notmuch-history
                                     ".")))
          (folder (replace-regexp-in-string "/\\(.\\)" ".\\1" folder))
          (init (read-string "Initial query: "))
          (init (format "folder:/%s/ %s" folder init)))
     (if tree (consult-notmuch-tree init) (consult-notmuch init))))

 (with-eval-after-load "notmuch-hello"
   (define-key notmuch-hello-mode-map "f" #'jao-consult-notmuch-folder)))
;;; org
(when jao-notmuch-enabled
  (require 'jao-notmuch)
  (jao-notmuch-org-links))

;;; recoll
(jao-when-linux
 (defun jao-notmuch-open-file (fname &optional _page)
   (with-temp-buffer
     (insert-file-contents-literally fname)
     (goto-char (point-min))
     (and (re-search-forward "^Message-ID: <\\([^>]+\\)>$" nil t)
          (notmuch-show (concat "id:" (match-string 1))))))

 (when jao-notmuch-enabled
   (with-eval-after-load "org"
     (org-link-set-parameters "message" :follow #'jao-notmuch-open-file))

   (with-eval-after-load "consult-recoll"
     (add-to-list 'consult-recoll-open-fns
                  '("message/rfc822" . jao-notmuch-open-file)))))

;;; .
(provide 'jao-custom-notmuch)
