;; -*- lexical-binding: t -*-

;;; General configuration
(defvar jao-org-dir (expand-file-name "org" jao-doc-dir))

(use-package org
  :ensure t
  :demand t
  :custom ((org-export-backends '(ascii html latex texinfo)))
  :init
  (defalias 'jao-open-gnus-frame 'jao-afio-goto-mail)

  (setq org-adapt-indentation t
        org-catch-invisible-edits 'smart
        org-complete-tags-always-offer-all-agenda-tags t
        org-cycle-separator-lines 0 ;; no blank lines when all colapsed
        org-deadline-warning-days 14
        org-directory jao-org-dir
        org-default-notes-file (expand-file-name "inbox.org" org-directory)
        org-ellipsis " .." ;; ↴
        org-email-link-description-format "Email %c: %s"
        org-enforce-todo-dependencies t
        org-fast-tag-selection-single-key 'expert
        org-insert-heading-respect-content nil ;; for C-RET
        org-link-frame-setup
        '((gnus . (lambda (&optional x) (jao-open-gnus-frame)))
          (file . find-file-other-window))
        org-log-done nil
        org-modules '(bibtex info eww eshell git-link)
        org-odd-levels-only t
        org-outline-path-complete-in-steps nil
        org-persist-directory (expand-file-name "cache/org-persist"
                                                user-emacs-directory)
        org-refile-allow-creating-parent-nodes 'confirm
        org-refile-targets '((nil :maxlevel . 5)
                             (org-agenda-files :maxlevel . 5))
        org-refile-use-outline-path 'file
        org-return-follows-link t
        org-reverse-note-order t
        org-special-ctrl-a/e t
        org-src-fontify-natively t
        org-startup-folded t
        org-tag-alist nil
        org-tags-column -75
        org-todo-keywords
        '((sequence "TODO(t)" "STARTED(s!)" "|" "DONE(d!)")
          (sequence "REPLY(r)" "WAITING(w!)" "|" "DONE(d!)")
          (sequence "TOREAD(T)" "READING(R!)" "|" "READ(a!)")
          (sequence "|" "CANCELLED(x!)" "SOMEDAY(o!)" "DONE(d!)"))
        org-use-fast-todo-selection t
        org-use-speed-commands nil ;; t and then ? to see help
        org-gnus-prefer-web-links nil)
  :bind (:map org-mode-map ("<f3>" . org-shifttab)))

;;; Agenda
(defun jao-org-agenda-fmt-date (date)
  (org-agenda-format-date-aligned date))

(defun jao-org-agenda-title ()
  (let ((fill-column (window-width)))
    (with-temp-buffer
      (insert " agenda ")
      (center-line)
      (insert "\n\n")
      (buffer-substring-no-properties (point-min) (point-max)))))

(setq org-agenda-custom-commands
      '(("j" agenda "" ((org-agenda-overriding-header #'jao-org-agenda-title)
                        (org-agenda-ndays-to-span 14)))
        ("w" todo "WAITING" nil)
        ("W" agenda "" ((org-agenda-ndays 21))))
      org-agenda-files (mapcar (lambda (f)
                                 (expand-file-name f jao-org-dir))
                               '("inbox.org"))
      org-agenda-block-separator " "
      org-agenda-breadcrumbs-separator "•"
      org-agenda-current-time-string "•" ;; "*"
      org-agenda-format-date #'jao-org-agenda-fmt-date
      org-agenda-hide-tags-regexp ".*"
      org-agenda-include-diary t
      org-agenda-include-inactive-timestamps t
      org-agenda-inhibit-startup nil
      org-agenda-prefix-format
      '((agenda . " %i  %?-12t% s")
        (todo . " %i %-12:c")
        (tags . " %i %-12:c")
        (search . " %i %-12:c"))
      org-agenda-restore-windows-after-quit t
      org-agenda-show-all-dates t
      org-agenda-skip-deadline-if-done t
      org-agenda-skip-scheduled-if-done t
      org-agenda-skip-timestamp-if-done t
      org-agenda-skip-timestamp-if-deadline-is-shown t
      org-agenda-skip-scheduled-if-deadline-is-shown t
      org-agenda-span 14
      ;; org-agenda-start-on-weekday nil
      ;; ;; org-agenda-time-grid '((daily require-timed) () "" "·")
      ;; '((daily today require-timed)
      ;;   (800 1000 1200 1400 1600 1800 2000) "" "·")
      org-agenda-window-setup 'current-window)

(defun jao-org-agenda ()
  (interactive)
  (org-agenda nil "j")
  (jao-org-agenda-hook))

(defun jao-org-agenda-hook (&optional w)
  (when-let* ((w (or w (get-buffer-window "*Org Agenda*"))))
    (set-window-margins w 2 1)
    (with-current-buffer (window-buffer w)
      (setq-local cursor-in-non-selected-windows nil
                  line-spacing 0.2))))

;; (add-to-list 'display-buffer-alist
;;              '((major-mode . org-agenda-mode)
;;                (display-buffer-reuse-window)
;;                (window-parameters (mode-line-format . none))
;;                (body-function . jao-org-agenda-hook)))

;; (add-to-list 'display-buffer-alist
;;              '("inbox\\.org"
;;                (display-buffer-reuse-window)
;;                (window-parameters (mode-line-format . none))))

;;; Capture templates
(jao-when-darwin
 (defun jao-org--safari-tmpl (&optional prefix)
   (format "%s%s \n %%?"
           (or prefix "* TOREAD ")
           (org-mac-link-safari-get-frontmost-url)))

 (defun jao-org--safari-note-tmpl () (jao-org--safari-tmpl "- "))

 (defun jao-org--mail-tmpl ()
   (format "* TODO %s \n %%?" (org-mac-link-mail-get-links))))

(defun jao-org--set-tmpl (k tmpl)
  (setf (alist-get k org-capture-templates nil nil #'string=) tmpl))

(defun jao-org-capture-templates (target)
  (jao-org--set-tmpl "t"
                     `("todo" entry (file+headline ,target "Tasks")
                       "* TODO %?\n  %i%a" :prepend t))
  (jao-org--set-tmpl "i"
                     `("inbox note" entry (file+headline ,target "Notes")
                       "* %a\n  %i%?(added on: %u)" :prepend t))
  (jao-org--set-tmpl "a"
                     `("appointment" entry (file+olp ,target "Appointments")
                       "* %^T %?\n  %a" :time-prompt t))
  (jao-when-darwin
   (jao-org--set-tmpl "s"
                      `("safari" entry (file+headline ,target "Tasks")
                        (function jao-org--safari-tmpl)
                        :after-finalize jao-org-after-capture-hook))

   (jao-org--set-tmpl "S"
                      '("safari note" plain (file jao-org-notes-create)
                        (function jao-org--safari-note-tmpl)
                        :after-finalize jao-org-after-capture-hook))
   (jao-org--set-tmpl "m"
                      `("mail" entry (file+headline ,target "Tasks")
                        (function jao-org--mail-tmpl)
                        :after-finalize jao-org-after-capture-hook)))
  (org-capture-upgrade-templates org-capture-templates))

(with-eval-after-load "org-capture" (jao-org-capture-templates "inbox.org"))

;;; MIME and file apps
(setq org-file-apps
      (jao-d-l
       '((remote . emacs)
         (system . "open %s")
         (t . emacs))
       '((system . mailcap)
         (".*\\.djvu" . system)
         (t . emacs))))

;;; Appearance
(use-package org-appear
  :disabled t
  :ensure t
  :init (setq org-appear-autolinks nil
              org-appear-delay 0.0
              org-appear-manual-linger t)
  :hook (org-mode . org-appear-mode))

;;; Images
;; #+caption: Image caption.
;;  #+attr_org: :width 100
;;  [[file:path/to/image.png]]

(setq org-startup-indented nil
      org-pretty-entities nil
      org-hide-emphasis-markers t
      org-hide-leading-stars t
      org-startup-with-inline-images t
      org-cycle-inline-images-display t
      org-display-remote-inline-images 'download ;; 'skip 'cache
      org-image-actual-width '(500))

;;; LaTeX
(use-package org-fragtog
  :after org
  :ensure t
  :demand t
  :hook ((org-mode . org-fragtog-mode)))

(setq org-format-latex-options
      `(:foreground default
                    :background
                    ,(if (jao-colors-scheme-dark-p) "black" "white")
                    :scale 1.25
                    :html-foreground "black"
                    :html-background "Transparent"
                    :html-scale 1.0
                    :matchers ("begin" "$1" "$" "$$" "\\(" "\\["))
      org-preview-latex-image-directory
      (expand-file-name "~/.emacs.d/cache/ltximg/")
      org-latex-hyperref-template nil
      org-highlight-latex-and-related '(latex script entities))

(require 'ox-latex)

;;; Export (org)
(require 'ox-org)

;;; Export (minted and pandoc)
(setq org-latex-listings 'minted
      org-latex-packages-alist '(("" "minted"))
      org-latex-pdf-process
      '("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
        "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"))

;;; Babel and literate programming
(setq org-src-window-setup 'other-window) ;; current-window
(require 'org-tempo nil t) ;; <s TAB for 9.2 and later

;; (use-package ob-prolog
;;   :ensure t
;;   :after org)

(org-babel-do-load-languages
 'org-babel-load-languages
 '((calc . t)
   (clojure . t)
   (emacs-lisp .t)
   (gnuplot .t)
   (haskell . t)
   (makefile . t)
   (ocaml . t)
   (org . t)
   (python . t)
   (scheme .t)
   (shell . t)
   (C . t)
   ;; (prolog . t)
   ))

(jao-define-attached-buffer "\\*Org Src\\( .*\\)?\\*" 0.5)

;;; Org cliplink (link from clipboard)
(use-package org-cliplink
  :ensure t
  :bind (:map org-mode-map ("C-c C-f" . org-cliplink))
  :config
  (add-to-list 'org-capture-templates
               '("k" "Cliplink capture task" entry
                 (file+headline "inbox.org" "Todo")
                 "* TODO %(org-cliplink-capture) %?" :prepend t)
               t))

;;; Notes
(use-package jao-org-notes
  :commands (jao-org-notes-setup)
  :config
  (defun jao-org-notes-note-p ()
    (string-prefix-p jao-org-notes-dir (buffer-file-name)))

  (defun jao-org-notes-recoll ()
    "Use consult-recoll to search notes."
    (interactive)
    (consult-recoll (format "dir:%s " jao-org-notes-dir)))

  (jao-transient-major-mode org
    ["Notes"
     ("c" "open or create note" jao-org-notes-create)
     ("/" "find and open note" jao-org-notes-open)
     ("\\" "find and open note by tags" jao-org-notes-consult-tags)]
    ["Extended search"
     ("g" "ripgrep notes" jao-org-notes-consult-ripgrep)
     ("r" "recoll notes" jao-org-notes-recoll)]
    ["Current note" :if jao-org-notes-note-p
     ("i" "insert link" jao-org-notes-insert-link)
     ("t" "insert tags" jao-org-notes-insert-tags)
     ("v" "show backlinks" jao-org-notes-backlinks)]))

(jao-org-notes-setup "n")

;;; Links
(require 'ol-eshell nil t)
;; (require 'ol-bbdb nil t)
(require 'ol-info nil t)
(setq org-link-abbrev-alist '(("jao.io" "https://jao.io/")))

(defun jao-org-link-at-point (&optional copy)
  (when (thing-at-point-looking-at "\\[\\[\\([^]]+\\)\\]\\[[^]]+\\]\\]")
    (when copy (kill-ring-save (match-beginning 1) (match-end 1)))
    (match-string-no-properties 1)))

(defun jao-org-copy-link-at-point ()
  (interactive)
  (message "%s" (or (jao-org-link-at-point t) "No link at point")))

(defun jao-org-insert-link (url title)
  (insert (format "[[%s][%s]]" url title)))

(defun jao-insert-eww-link ()
  "Look for last eww buffer and insert an org link to it."
  (interactive)
  (when-let* ((b (car (jao-eww-session-eww-buffers))))
    (let ((lnk (with-current-buffer b
                 (format "[[%s][%s]]"
                         (eww-current-url)
                         (jao-eww-buffer-title)))))
      (insert lnk))))

(use-package jao-org-links
  :commands jao-org-links-setup
  :bind (("C-c T" . jao-org-insert-doc)))

(jao-org-links-setup jao-sink-dir)

(with-eval-after-load "pdf-view"
  (define-key pdf-view-mode-map (kbd "C-c o") #'jao-org-pdf-goto-org)
  (define-key pdf-view-mode-map (kbd "C-c O") #'jao-org-pdf-goto-org*))

(with-eval-after-load "doc-view"
  (define-key doc-view-mode-map (kbd "C-c o") #'jao-org-pdf-goto-org)
  (define-key doc-view-mode-map (kbd "C-c O") #'jao-org-pdf-goto-org*))

;;;; mac links
(jao-when-darwin
 (use-package org-mac-link
   :ensure t
   :bind (:map org-mode-map
               ("C-c l m" . org-mac-link-mail-insert-link)
               ("C-c l M" . org-mac-link-mail-insert-selected)
               ("C-c l s" . org-mac-link-safari-insert-frontmost-url))))

;;; eldoc
(defun jao-org-eldoc--hook ()
  (set (make-local-variable 'eldoc-documentation-function)
       'jao-org-link-at-point)
  (eldoc-mode))
(add-hook 'org-mode-hook 'jao-org-eldoc--hook)

;;; savedoc
(defun jao-org--show-if-hidden ()
  (when (outline-invisible-p)
    (save-excursion
      (outline-previous-visible-heading 1)
      (org-show-subtree))))
(add-hook 'org-mode-hook 'jao-org--show-if-hidden t)

;;; jao-org-focus and words
(use-package jao-org-focus
  :commands (jao-org-focus org-focus-mode)
  :after org
  :config
  (with-eval-after-load "jao-custom-completion"
    (defvar jao-org-focus-consult-buffer-source
      `(:name "Focus buffers"
              :category jao-org-focus-buffers
              :action switch-to-buffer
              :hidden t
              :narrow ,(cons ?o "focus")
              :history jao-org-focus--focused-history
              :items ,(lambda () (mapcar 'buffer-name (jao-org-focus-list t)))))
    (jao-consult-add-buffer-source 'jao-org-focus-consult-buffer-source))
  :bind ((:map org-mode-map (("C-M-o" . jao-org-focus)))
         (:map org-focus-mode-map (("\C-cW" . jao-words-show-stats)))))

(use-package jao-words
  :commands (jao-words-show-stats))

;;; Keybindings
(define-key mode-specific-map [?a] 'org-agenda)
(define-key org-mode-map "\C-cv" 'jao-org-copy-link-at-point)
(define-key org-mode-map [(control ?c) tab] 'org-force-cycle-archived)
(define-key org-mode-map [(f7)] 'org-archive-to-archive-sibling)
(define-key org-mode-map "\C-cE" 'jao-insert-eww-link)
(define-key org-mode-map "\C-cW" 'jao-insert-eww-link)
(define-key org-mode-map "\C-c'" 'org-edit-src-code)
(define-key org-mode-map (kbd "C-c O") 'org-toggle-narrow-to-subtree)
(define-key org-mode-map (kbd "C-x C-n") 'org-next-link)
(define-key org-mode-map (kbd "C-x C-p") 'org-previous-link)
(global-set-key "\C-cr" 'org-capture)
(global-set-key "\C-c\C-l" 'org-store-link)
;; (global-set-key "\C-cL" 'org-insert-link-global)
(global-set-key "\C-cO" 'org-open-at-point-global)

(jao-transient-major-mode+ org
  ["Links"
   ("le" "insert current eww link" jao-insert-eww-link :if jao-is-linux)
   ("lm" "insert mac link" org-mac-link-get-link :if jao-is-darwin)
   ("lf" "insert link from clipboard" org-cliplink)
   ("lc" "copy link at point" jao-org-copy-link-at-point)])

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