;;; axis.el --- using sqlite to generate key/command usage statistics in emacs -*- lexical-binding: t; -*-

;; Package-Version: 0.0.0.20251109.4
;; Package-Revision: 0d747c293e65

;;; Commentary:


;;; Code:

(defgroup axis '()
  "Statistics of how you play Emacs."
  :group 'applications)

(defcustom axis-db-location
  (concat user-emacs-directory "axis-data.sqlite")
  "A path to axis-db, which is a sqlite database."
  :group 'axis
  :type 'string)

(defvar axis-db nil
  "SQLite database connection for command-key tracking.")

(defun axis-db-init ()
  "Initialize the SQLite database with performance optimizations."
  (setq axis-db (sqlite-open axis-db-location))
  ;; Apply performance PRAGMAs
  (sqlite-execute axis-db "PRAGMA journal_mode = WAL;")
  (sqlite-execute axis-db "PRAGMA synchronous = NORMAL;")
  (sqlite-execute axis-db "PRAGMA cache_size = 2000;")
  ;; Create table if it doesn't exist
  (sqlite-execute
   axis-db
   "CREATE TABLE IF NOT EXISTS command_keys (
       command TEXT,
       key TEXT,
       count INTEGER,
       PRIMARY KEY (command, key)
     );"))

(defun axis-db-close ()
  "Close the SQLite database connection."
  (when axis-db
    (sqlite-close axis-db)
    (setq axis-db nil)))

(defun axis-record-command-and-keys ()
  "Record the current command and keys into the database."
  (when (and (commandp this-command)
             (symbolp this-command))
    (let ((key-str (key-description (this-command-keys))))
      (sqlite-execute
       axis-db
       "INSERT INTO command_keys (command, key, count) VALUES (?, ?, 1)
        ON CONFLICT(command, key) DO UPDATE SET count = count + 1;"
       (list (symbol-name this-command) key-str)))))

;;;###autoload
(defun axis-show-command-summary ()
  "Display commands and their associated keys with usage counts."
  (interactive)
  (let ((data
         (sqlite-select
          axis-db
          "SELECT command, SUM(count) FROM command_keys GROUP BY command
           ORDER BY SUM(count) DESC;"))
        )
    (with-output-to-temp-buffer "*Axis Commands & Keys*"
      (princ "Command Usage Statistics:\n\n")
      (dolist (entry data)
        (princ (format "Command: %s - %d times\n" (car entry) (cadr entry)))
        ))))

;;;###autoload
(define-minor-mode axis-mode
  "Record statistics of input commands and keys."
  :init-value nil

  (if axis-mode
      (progn
        (unless axis-db (axis-db-init))
        (add-hook 'pre-command-hook 'axis-record-command-and-keys)
        (message "Axis mode enabled."))
    (progn
      (remove-hook 'pre-command-hook 'axis-record-command-and-keys)
      (axis-db-close)
      (message "Axis mode disabled."))))

(defun axis-turn-on-axis-mode ()
  (cl-letf (((symbol-function #'message) #'ignore))
   (axis-mode 1)))

(define-globalized-minor-mode global-axis-mode axis-mode axis-turn-on-axis-mode)

(provide axis-mode)
;;; axis.el ends here
