;;(setq fancy-splash-image "~/.config/doom/splash.png")

;; Clean up starting screen
(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-shortmenu)
(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-banner)
(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-footer)
(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-loaded)
(add-hook! '+doom-dashboard-mode-hook (hide-mode-line-mode 1) (hl-line-mode -1))
(setq-hook! '+doom-dashboard-mode-hook evil-normal-state-cursor (list nil))

;; Set name & e-mail
(setq user-full-name "opal"
      user-mail-address "ry.orlando@proton.me")

;; Theme & background color
(load-theme 'ef-eagle t)
(set-face-background 'default "#E8D8B0")

;; Lockfiles
(setq create-lockfiles nil)

;; Remove line numbers from specific modes
(dolist (mode '(org-mode-hook
                term-mode-hook
                shell-mode-hook
                eshell-mode-hook))
  (add-hook mode (lambda () (display-line-numbers-mode 0))))

;; Font configuration
(set-face-attribute 'default nil :font "Monospace" :height 200)
(set-face-attribute 'fixed-pitch nil :font "Monospace" :height 200)
(set-face-attribute 'variable-pitch nil :font "ETBembo" :height 200)

(defun opal/org-font-setup ()
  ;; Replace list hyphen with dot
  (font-lock-add-keywords 'org-mode
                          '(("^ *\\([-]\\) "
                             (0 (prog1 () (compose-region (match-beginning 1) (match-end 1)
                                                          "•"))))))

  ;; Set faces for heading levels
  (dolist (face '((org-level-1 . 1.2)
                  (org-level-2 . 1.1)
                  (org-level-3 . 1.05)
                  (org-level-4 . 1.0)
                  (org-level-5 . 1.1)
                  (org-level-6 . 1.1)
                  (org-level-7 . 1.1)
                  (org-level-8 . 1.1)))
    (set-face-attribute (car face) nil :font "ETBembo" :weight 'regular :height (cdr face)))

  ;; Set properties and scheduling faces to inherit variable-pitch and be smaller
  ;; Comment out these lines because mixed-pitch-mode will handle these.
  (set-face-attribute 'org-property-value nil :inherit 'variable-pitch :height 150)
  (set-face-attribute 'org-special-keyword nil :inherit 'variable-pitch :height 150)
  (set-face-attribute 'org-scheduled-today nil :inherit 'variable-pitch :height 150)
  (set-face-attribute 'org-drawer nil :inherit 'variable-pitch :height 150)
  (set-face-attribute 'org-date nil :inherit 'variable-pitch :height 150)

  ;; Ensure that all agenda items use fixed-pitch font
  (custom-set-faces
   '(org-agenda-date-today ((t (:inherit fixed-pitch :weight bold))))
   '(org-agenda-date ((t (:inherit fixed-pitch))))
   '(org-agenda-date-weekend ((t (:inherit fixed-pitch :weight bold))))
   '(org-agenda-done ((t (:inherit fixed-pitch :strike-through t))))
   '(org-agenda-dimmed-todo-face ((t (:inherit fixed-pitch))))
   '(org-agenda-structure ((t (:inherit fixed-pitch))))
   '(org-scheduled ((t (:inherit fixed-pitch))))
   '(org-scheduled-today ((t (:inherit fixed-pitch))))
   '(org-scheduled-previously ((t (:inherit fixed-pitch))))
   '(org-upcoming-deadline ((t (:inherit fixed-pitch))))
   '(org-deadline-announce ((t (:inherit fixed-pitch))))
   '(org-time-grid ((t (:inherit fixed-pitch)))))
  )

(defun opal/org-mode-setup ()
  (org-indent-mode)
  (visual-line-mode 1)
  (mixed-pitch-mode 1))

(use-package org
  :commands (org-capture org-agenda)
  :hook (org-mode . opal/org-mode-setup)
  :config
  (setq org-ellipsis " ▾")
  (setq org-agenda-start-with-log-mode t)
  (setq org-log-done 'time)
  (setq org-log-into-drawer t)
  (setq org-startup-folded t)
  (setq org-indent-indentation-per-level 2)
  (setq org-hide-emphasis-markers t)
  (setq org-agenda-files
        '("~/documents/org/agenda/todo.org"))

  (require 'org-habit)
  (add-to-list 'org-modules 'org-habit)
  (setq org-habit-graph-column 60)

  (setq org-todo-keywords
        '((sequence "NEXT(n)" "TODO(t)"  "|" "DONE(d!)")
          (sequence  "ACTIVE(a)" "PROJ(p)" "READY(r)" "HOLD(h)" "BACKLOG(b)" "|" "CANC(k@)")))

  (setq org-todo-keyword-faces
        '(("NEXT" . "red") ("TODO" . "orange") ("WAIT" . "yellow") ("DONE" . "green")))

  (setq org-refile-targets
        '(("archive.org" :maxlevel . 1)
          ("planner.org" :maxlevel . 1)))

  ;; Save Org buffers after refiling!
  (advice-add 'org-refile :after 'org-save-all-org-buffers)

  (add-hook 'org-mode-hook #'org-make-toc-mode)

  (setq org-agenda-custom-commands
        '(("d" "Custom Dashboard"
           ;; NEXT items for today
           ((tags "+TODO=\"NEXT\"+SCHEDULED=\"<+0d>\"|+DEADLINE=\"<+0d>\""
                  ((org-agenda-overriding-header "\nNEXT Items for Today\n")))  ; Show NEXT items scheduled or due today
            ;; TODO items for today
            (tags "+TODO=\"TODO\"+SCHEDULED=\"<+0d>\"|+DEADLINE=\"<+0d>\""
                  ((org-agenda-overriding-header "\nTODO Items for Today\n")))  ; Show TODO items scheduled or due today
            ;; DONE items for today
            (tags "+TODO=\"DONE\"+CLOSED>=\"<-3d>\""
                  ((org-agenda-overriding-header "\nDone Items for Today\n")))  ; Show DONE items closed today
            ;; Agenda for today
            (agenda ""
                    ((org-agenda-span 1)              ; Show only today
                     (org-agenda-start-day "0d")      ; Start from today
                     (org-agenda-show-all-dates t)    ; Ensure all dates are shown
                     (org-agenda-overriding-header "\nAgenda (Today)\n")))
            ;; Agenda for next 3 days (no time grid)
            (agenda ""
                    ((org-agenda-span 3)              ; Show the next 3 days
                     (org-agenda-start-day "+1d")     ; Start from tomorrow
                     (org-agenda-overriding-header "\nAgenda (Next 3 Days)\n")
                     (org-agenda-time-grid nil))))))) ; Remove time grid

  ;; Create capture templates
  (setq org-capture-templates
        `(("t" "Tasks")
          ("tw" "Work Task" entry (file+headline "~/documents/org/agenda/todo.org" "Work")
           "* TODO %?\n  %U\n  %i" :empty-lines 1)
          ("tp" "Personal Task" entry (file+headline "~/documents/org/agenda/todo.org" "Personal")
           "* TODO %?\n  %U\n  %i" :empty-lines 1)
          ("tb" "Backlog Task" entry (file+headline "~/documents/org/agenda/todo.org" "Backlog")
           "* BACKLOG %?\n  %U\n  %i" :empty-lines 1)))

  ;; Tell Org to stop indenting inside of org source blocks.
  (setq org-edit-src-content-indentation 0)

  ;; Set org agenda dir
  (setq org-directory "~/documents/org/")

  ;; Init org font setup
  (opal/org-font-setup))

(use-package org-bullets
  :after org
  :hook (org-mode . org-bullets-mode)
  :custom
  (org-bullets-bullet-list '("◉" "○" "●" "○" "●" "○" "●")))

(defun opal/org-mode-visual-fill ()
  (setq visual-fill-column-width 150
	visual-fill-column-center-text t)
  (visual-fill-column-mode 1))

(use-package visual-fill-column
  :hook (org-mode . opal/org-mode-visual-fill))

;; Load languages for babel code blocks.
(with-eval-after-load 'org
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((emacs-lisp . t)
     (lisp . t)
     (python . t)
     (sql . t)))

  (push '("conf-unix" . conf-unix) org-src-lang-modes))

(with-eval-after-load 'org
  (require 'org-tempo)
  (add-to-list 'org-structure-template-alist '("sh" . "src shell"))
  (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
  (add-to-list 'org-structure-template-alist '("cl" . "src lisp"))
  (add-to-list 'org-structure-template-alist '("sql" . "src sql"))
  (add-to-list 'org-structure-template-alist '("py" . "src python")))

;; Programming
(setq geiser-guile-binary "/usr/bin/guile3.0")

;; Playing youtube videos via mpv/yt-dlp/emms
(defun opal/play-yt-url-at-point ()
  "Play YT link under point with EMMS/MPV/yt-dlp."
  (interactive)
  (let ((url (thing-at-point 'url t)))
    (if url
        (emms-play-url url)
      (message "No URL found at point."))))

(global-set-key (kbd "C-c y") 'opal/play-yt-url-at-point)

;; Elfeed
(defun opal/elfeed-open-in-firefox ()
  "Open the current Elfeed entry link in Firefox."
  (interactive)
  (let ((link (elfeed-entry-link (elfeed-search-selected :single))))
    (if link
        (browse-url-firefox link)
      (message "No link to open."))))

(defun opal/elfeed-open-in-eww()
  "Open the current Elfeed entry link in eww."
  (interactive)
  (let ((link (elfeed-entry-link (elfeed-search-selected :single))))
    (if link
        (eww-browse-url link)
      (message "No link to open."))))

(defun opal/elfeed-mark-all-read ()
  "Marks all feeds in *elfeed-search* as read."
  (interactive)
  (elfeed-untag elfeed-search-entries 'unread)
  (elfeed-search-update :force)) ; redraw

(use-package elfeed
  :bind
  (("C-c e" . elfeed))
  :config
  ;; Ensure faces are set after elfeed has loaded
  (with-eval-after-load 'elfeed
    (set-face-attribute 'elfeed-search-filter-face nil :inherit 'variable-pitch :height 200)
    ;; Monospace fonts are necessary for text/column alignment in the *elfeed-search* buffer
    (set-face-attribute 'elfeed-search-title-face nil :inherit 'fixed-pitch :height 200)
    (set-face-attribute 'elfeed-search-feed-face nil :inherit 'fixed-pitch :height 200))

  ;; Set variable-pitch face for article fonts in the *elfeed-entry* buffer
  (add-hook 'elfeed-show-mode-hook
            (lambda () (buffer-face-set 'variable-pitch)))

  ;; Set default search filter
  (setq elfeed-search-filter "@2-weeks-ago +unread")

  ;; Update feeds automatically when entering Elfeed search mode
  (add-hook 'elfeed-search-mode-hook 'elfeed-update)

  ;; Evil keybindings for Elfeed
  (evil-define-key 'normal elfeed-search-mode-map
    "f" 'opal/elfeed-open-in-firefox ;; Open link in Firefox
    "e" 'opal/elfeed-open-in-eww ;; Open link in Firefox
    "r" 'opal/elfeed-mark-all-read   ;; Marks all feeds as read
    "gr" 'elfeed-update              ;; Refresh feeds
    "q" 'quit-window))               ;; Quit Elfeed

(setq create-lockfiles nil)

;; Make sure eww opens in it's own buffer
(after! eww
  (set-popup-rule! "^\\*eww\\*" :ignore t))

(after! osm
  (set-popup-rule! "^\\*osm\\*" :ignore t))

;; eww
(defun opal/eww-reddit-redirect(url)
  "Redirect reddit.com to custom URL."
  (replace-regexp-in-string "https://www.reddit.com" "https://eddrit.com" url))

(use-package eww
  :config
  (setq browse-url-browser-function 'eww-browse-url)

  ;; Set eww webpage title in the modeline bar instead of just *eww*
  (setq eww-auto-rename-buffer 'title)

  ;; Set privacy respecting proxies
  (setq reddit-proxy "https://eddrit.com")

  ;; Redirect reddit links to privacy respecting frontends.
  (setq eww-url-transformers '(eww-remove-tracking opal/eww-reddit-redirect))

  ;; Make sure eww opens in it's own buffer
  (after! eww
    (set-popup-rule! "^\\*eww\\*" :ignore t)))

;; Since I sometimes write notes in two languages, guess-language will allow for multiple language
;; spelling checks to be done in a single buffer.
(use-package guess-language
  :defer t
  :init (add-hook 'text-mode-hook #'guess-language-mode)
  :config
  (setq guess-language-langcodes '((en . ("en_US" "English"))
                                   (pt_BR . ("pt_BR" "Brazilian Portuguese")))
        guess-language-languages '(en pt_BR)
        guess-language-min-paragraph-length 45)
  :diminish guess-language-mode)

(setq geiser-guile-binary "/usr/bin/guile3.0")

(defun opal/nov-mode-setup ()
  "Configure fonts for nov.el."
  (variable-pitch-mode 1)          ; Enable variable-pitch-mode
  (visual-line-mode 1)             ; Enable line wrapping at word boundaries
  (setq visual-fill-column-width 150
        visual-fill-column-center-text t
        line-spacing 0.2)
  (visual-fill-column-mode 1))

(add-hook 'nov-mode-hook 'opal/nov-mode-setup)

(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))

(setq +lookup-dictionary-prefer-offline t)
(setq dictionary-server "dict.org")
