;;; mu4e.el ---  Mu-based mua for emacs -*- lexical-binding: t -*-

;; Copyright (C) 2025-2026 Dirk-Jan C. Binnema

;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>

;; This file is not part of GNU Emacs.

;; SPDX-License-Identifier: GPL-3.0-or-later

;; mu4e is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; mu4e is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with mu4e.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:
;;;
;;; Define a "transient" menu for some mu4e functionality.

;;; Code:
(require 'mu4e-bookmarks)
(require 'mu4e-compose)
(require 'mu4e-draft)
(require 'mu4e-headers)
(require 'mu4e-helpers)

(require 'gnus-ml)

(require 'transient)

;; Helpers.


(declare-function mu4e "mu4e")

(defun mu4e--toggle-description(name val)
  "Return a string for a transient toggle with NAME.
Show On/Off based on value VAL."
  (concat name " "
          (propertize (if val "On " "Off")
                      'face 'transient-value)))

(defmacro mu4e--define-toggle-suffix (name symbol &optional toggle-func)
  "Define a transient suffix to toggle some value.
Show the suffix with NAME. SYMBOL is the symbol for the value to
toggle.

TOGGLE-FUNC is the function to do the toggling. If nil, a simple
toggle-function is created."
  (let* ((symname (symbol-name symbol))
         (ifname (intern (format "mu4e--suffix-toggle-%s" symname)))
         (docstring (format "Toggle the value of `%s'" symname))
         (toggle-func (or toggle-func
                          `(lambda ()
                             (interactive)
                             (setq ,symbol (not ,symbol))))))
    `(progn
       (transient-define-suffix ,ifname () ,docstring
         :transient t
         :if (lambda () (boundp (quote ,symbol)))
         :description (lambda () (mu4e--toggle-description ,name ,symbol))
         (interactive)
         (call-interactively ,toggle-func)))))

;; Transients

(transient-define-prefix mu4e--prefix-docs-links()
  "Mu4e documentation menu."
  [["Documentation"
    ("A" "About mu4e"          mu4e-about)
    ("N" "News"                mu4e-news)
    ("I" "Ideas"               mu4e-ideas)
    ("H" "Manual"              mu4e-display-manual)
    ("o" "Online manual" (lambda ()  (interactive)
                           (browse-url "https://www.djcbsoftware.nl/code/mu/mu4e/")))]
   ["Links"
    ("h" "Mu homepage"  (lambda () (interactive)
                          (browse-url "https://www.djcbsoftware.nl/code/mu/")))
    ("m" "Mu4e homepage" (lambda () (interactive)
                           (browse-url "https://www.djcbsoftware.nl/code/mu/")))
    ("r" "Mu repository" (lambda ()  (interactive)
                           (browse-url "https://github.com/djcb/mu/")))
    ("o" "Mu Issues"     (lambda ()  (interactive)
                           (browse-url "https://github.com/djcb/mu/issues")))]])

(mu4e--define-toggle-suffix "Debug client" mu4e-debug #'mu4e-toggle-logging)
(mu4e--define-toggle-suffix "Debug server" mu4e-mu-debug)
(mu4e--define-toggle-suffix "Report render-time" mu4e-headers-report-render-time)
(mu4e--define-toggle-suffix "Temp-file optimization" mu4e-mu-allow-temp-file)

(transient-define-prefix mu4e--prefix-debug-tweaks()
  "Mu4e debugging and tweaks menu."
  [["Debug"
    ("$" mu4e--suffix-toggle-mu4e-debug)
    ("r" mu4e--suffix-toggle-mu4e-headers-report-render-time)
    ("L" "Toggle logging" mu4e-toggle-logging)
    ("l" "Log buffer" mu4e-show-log)]
   ["Info"
    ("," "Message sexp"   mu4e-sexp-at-point
     :inapt-if-not (lambda () (mu4e-message-at-point 'nowarn)))
    ("a" "Analyze query" mu4e-analyze-last-query)
    ("c" "Known contacts"  mu4e-contacts-info)]
   ["Server (needs restart)"
    ("d" mu4e--suffix-toggle-mu4e-mu-debug)
    ("t" mu4e--suffix-toggle-mu4e-mu-allow-temp-file)]])

(mu4e--define-toggle-suffix "format=flowed" mu4e-compose-format-flowed)
(mu4e--define-toggle-suffix "Forward as MIME" message-forward-as-mime)

;; (transient-define-suffix mu4e--suffix-message-forward-show-mml (args)
;;   "Show MML when forwarding?
;; See `message-forward-show-mml' for details."
;;   :transient t
;;   :description (lambda ()
;;                  (let ((val (pcase message-forward-as-mime
;;                               ('nil "Off")
;;                               ('best "Best")
;;                               (_    "On")))))
;;                  (concat "Show MML "
;;                          (propertize  val 'face 'transient-value)))
;;   ;;:choices '("On" "Off" "Best")

;;   )

;;(setq message-forward-as-mime 'best)

;;(mu4e--define-toggle-suffix "Show MML"  message-forward-show-mml)

(transient-define-prefix mu4e--prefix-compose-options()
  "Mu4e debugging menu."
  [["Formatting"
    ("f" mu4e--suffix-toggle-mu4e-compose-format-flowed)]
   ["Forwarding"
    ("m" mu4e--suffix-toggle-message-forward-as-mime)
    ;; handle 'best'
    ;;("M" mu4e--suffix-toggle-message-forward-show-mml)
    ]])

(transient-define-prefix mu4e--prefix-mailing-list()
  "Mu4e documentation menu."
  [[
    :description
    (lambda ()
      (let* ((msg (mu4e-message-at-point 'no-error))
             (ml (plist-get msg :list)))
        (format "Mailing list %s" (or ml ""))))
    ("s" "subscribe"   gnus-mailing-list-subscribe)
    ("u" "unsubscribe" gnus-mailing-list-unsubscribe)
    ("h" "help"        gnus-mailing-list-help)
    ;;("a" "archive")
]])



;;;###autoload(autoload 'mu4e-transient-menu "mu4e-transient" nil t)
(transient-define-prefix mu4e-transient-menu()
  "Mu4e main menu."
  [["Main"
    ("M" "Main screen"         mu4e)
    ("U" "Update mail"         mu4e-update-mail-and-index)
    (";" "Change context"      mu4e-context-switch
     :inapt-if-nil mu4e-contexts
     :description
     (lambda ()
       (let ((ctx (mu4e-context-current)))
         (format "Context %s"
                 (if ctx (propertize (mu4e-context-name ctx)
                                     'face 'transient-value) "")))))
    ("d" "Docs & links"        mu4e--prefix-docs-links)
    ("D" "Debug/tweaks..."     mu4e--prefix-debug-tweaks)
    ("M-q" "Quit"              mu4e-quit)]
   ["Search"
    ("b" "Bookmark"            mu4e-search-bookmark)
    ("j" "Maildir"             mu4e-search-maildir)
    ("c" "Choose query"        mu4e-search-query)
    ("s" "Search"              mu4e-search)]
   ["Composition"
    ("C" "New message"         mu4e-compose-new)
    ("R" "Reply"               mu4e-compose-reply :if mu4e-message-p)
    ("W" "Reply-to-all"        mu4e-compose-wide-reply :if mu4e-message-p)
    ("F" "Forward"             mu4e-compose-forward :if mu4e-message-p)
    ;; only draft messages can be edited
    ("E" "Edit draft"          mu4e-compose-edit
     :if mu4e-message-p
     :inapt-if-not (lambda ()
                     (member 'draft
                             (mu4e-message-field
                              (mu4e-message-at-point 'nowarn) :flags))))
    ;; you can only supersede your own messages
    ("S" "Supersede"           mu4e-compose-supersede
     :if mu4e-message-p
     :inapt-if-not mu4e--message-is-yours-p)
    ("X" "Resend"          mu4e-compose-resend :if mu4e-message-p)
    ("o" "Options..."      mu4e--prefix-compose-options)]
   ["" ;; composition that requires an existing message
    :if           (lambda ()
                    (memq major-mode '(mu4e-headers-mode mu4e-view-mode)))
    :inapt-if-not (lambda ()
                    (mu4e-message-at-point 'nowarn))
    ]
   ["View"
    :if (lambda () (eq major-mode 'mu4e-view-mode))
    ("m" "Mailing list..."  mu4e--prefix-mailing-list)]])

(provide 'mu4e-transient)
;;; mu4e-transient.el ends here
