;;; agent-chat-helper.el --- Send context to terminal AI agents -*- lexical-binding: t; -*-

(defun circ/agent-chat-helper--visible-vterm-buffers ()
  "Return a list of vterm buffers shown in the current frame's windows."
  (let (buffers)
    (dolist (window (window-list nil 'no-minibuffer))
      (let ((buffer (window-buffer window)))
        (when (and (buffer-live-p buffer)
                   (with-current-buffer buffer
                     (derived-mode-p 'vterm-mode))
                   (not (memq buffer buffers)))
          (push buffer buffers))))
    (nreverse buffers)))

(defun circ/agent-chat-helper--read-target-vterm ()
  "Return a vterm buffer to send to, prompting if there are several."
  (let ((buffers (circ/agent-chat-helper--visible-vterm-buffers)))
    (cond
     ((null buffers)
      (user-error "No vterm buffers visible in this frame"))
     ((null (cdr buffers))
      (car buffers))
     (t
      (let* ((names (mapcar #'buffer-name buffers))
             (choice (completing-read "Send to vterm: " names nil t)))
        (get-buffer choice))))))

(defun circ/agent-chat-helper--send-text (target text)
  "Insert TEXT into TARGET vterm buffer without submitting."
  (with-current-buffer target
    (vterm-insert text)))

(defun circ/agent-chat-helper--buffer-relative-path ()
  "Return the current buffer's file path relative to the project root."
  (unless buffer-file-name
    (user-error "Current buffer is not visiting a file"))
  (let* ((project (project-current t))
         (root (project-root project)))
    (file-relative-name buffer-file-name root)))

(defun circ/agent-chat-helper--region-header (path beg end)
  "Return a header of the form PATH:LINE or PATH:START-END for region BEG..END."
  (let* ((start-line (line-number-at-pos beg))
         (effective-end (if (and (> end beg)
                                 (save-excursion (goto-char end) (bolp)))
                            (1- end)
                          end))
         (end-line (line-number-at-pos effective-end)))
    (if (= start-line end-line)
        (format "%s:%d" path start-line)
      (format "%s:%d-%d" path start-line end-line))))

(defun circ/agent-chat-helper--send-region-with-header-for-path (path)
  "Send the active region to a vterm, prefixed by a header line built from PATH.
The region body is wrapped in triple-backtick fences."
  (let* ((beg (region-beginning))
         (end (region-end))
         (header (circ/agent-chat-helper--region-header path beg end))
         (text (buffer-substring-no-properties beg end))
         (body (if (string-suffix-p "\n" text) text (concat text "\n")))
         (target (circ/agent-chat-helper--read-target-vterm)))
    (circ/agent-chat-helper--send-text target
                                       (concat header "\n```\n" body "```"))))

(defun circ/agent-chat-helper-send-file-path ()
  "Send the current buffer's file path, relative to the project root, to a vterm."
  (interactive)
  (let ((relative-path (circ/agent-chat-helper--buffer-relative-path))
        (target (circ/agent-chat-helper--read-target-vterm)))
    (circ/agent-chat-helper--send-text target relative-path)))

(defun circ/agent-chat-helper-send-absolute-file-path ()
  "Send the current buffer's absolute file path to a vterm."
  (interactive)
  (unless buffer-file-name
    (user-error "Current buffer is not visiting a file"))
  (let ((target (circ/agent-chat-helper--read-target-vterm)))
    (circ/agent-chat-helper--send-text target buffer-file-name)))

(defun circ/agent-chat-helper-send-region ()
  "Send the active region to a vterm."
  (interactive)
  (unless (use-region-p)
    (user-error "No active region"))
  (let ((text (buffer-substring-no-properties (region-beginning) (region-end)))
        (target (circ/agent-chat-helper--read-target-vterm)))
    (circ/agent-chat-helper--send-text target text)
    (deactivate-mark)))

(defun circ/agent-chat-helper-send-region-with-header ()
  "Send the active region to a vterm, prefixed by a relative PATH:START-END header line."
  (interactive)
  (unless (use-region-p)
    (user-error "No active region"))
  (circ/agent-chat-helper--send-region-with-header-for-path
   (circ/agent-chat-helper--buffer-relative-path))
  (deactivate-mark))

(defun circ/agent-chat-helper-send-region-with-absolute-header ()
  "Send the active region to a vterm, prefixed by an absolute PATH:START-END header line."
  (interactive)
  (unless (use-region-p)
    (user-error "No active region"))
  (unless buffer-file-name
    (user-error "Current buffer is not visiting a file"))
  (circ/agent-chat-helper--send-region-with-header-for-path buffer-file-name)
  (deactivate-mark))

(provide 'agent-chat-helper)
;;; agent-chat-helper.el ends here
