;;; ai-code-claude-code.el --- Thin wrapper for Claude Code CLI  -*- lexical-binding: t; -*-

;; Author: Kang Tu, Yoav Orot
;; SPDX-License-Identifier: Apache-2.0

;;; Commentary:
;;
;; Thin wrapper that reuses `ai-code-backends-infra' to run Claude Code CLI.
;; Provides interactive commands and aliases for the AI Code suite.
;; This is an alternative to the external claude-code.el package, using the
;; same terminal infrastructure as other backends (codex, gemini, grok, etc.).
;;
;;; Code:

(require 'ai-code-backends)
(require 'ai-code-backends-infra)
(require 'ai-code-mcp-agent)

(defvar ghostel-full-redraw)

(defgroup ai-code-claude-code nil
  "Claude Code CLI integration via `ai-code-backends-infra'."
  :group 'tools
  :prefix "ai-code-claude-code-")

(defcustom ai-code-claude-code-program "claude"
  "Path to the Claude Code CLI executable."
  :type 'string
  :group 'ai-code-claude-code)

(defcustom ai-code-claude-code-program-switches nil
  "Command line switches to pass to Claude Code CLI on startup."
  :type '(repeat string)
  :group 'ai-code-claude-code)

(defcustom ai-code-claude-code-no-flicker nil
  "Enable experimental flicker-free terminal renderer in Claude Code.
When non-nil, set CLAUDE_CODE_NO_FLICKER=1 which uses full-screen
redraw rendering.  This can break vterm scrollback because the
screen-clearing sequences overwrite the scrollback buffer.  Leave
nil unless you specifically need flicker-free rendering and do not
rely on scrolling back through terminal history."
  :type 'boolean
  :group 'ai-code-claude-code)

(defcustom ai-code-claude-code-multiline-input-sequence "\e\r"
  "Terminal sequence used for multiline input in Claude Code sessions.
This mirrors the newline sequence Claude Code expects from `/terminal-setup'."
  :type 'string
  :group 'ai-code-claude-code)

(defconst ai-code-claude-code--session-prefix "claude"
  "Session prefix used in Claude Code CLI buffer names.")

(defvar ai-code-claude-code--processes (make-hash-table :test 'equal)
  "Hash table mapping Claude Code session keys to processes.")

;;;###autoload
(defun ai-code-claude-code (&optional arg)
  "Start Claude Code using `ai-code-backends-infra' logic.
With prefix ARG, prompt for CLI args using
`ai-code-claude-code-program-switches' as the default input."
  (interactive "P")
  (ai-code-backends-infra--start-cli-session
   (list :program ai-code-claude-code-program
         :switches ai-code-claude-code-program-switches
         :label "Claude Code"
         :process-table ai-code-claude-code--processes
         :session-prefix ai-code-claude-code--session-prefix
         :escape-function #'ai-code-claude-code-send-escape
         :env-vars (append (list "TERM_PROGRAM=emacs"
                                 "FORCE_CODE_TERMINAL=true")
                           (when ai-code-claude-code-no-flicker
                             (list "CLAUDE_CODE_NO_FLICKER=1")))
         :multiline-input-sequence ai-code-claude-code-multiline-input-sequence
         :prepare-launch
         (lambda (working-dir argv)
           (let* ((mcp-launch
                   (ai-code-mcp-agent-prepare-launch 'claude-code
                                                     working-dir
                                                     argv))
                  (mcp-post-start-fn (plist-get mcp-launch :post-start-fn)))
             (list
              :argv (plist-get mcp-launch :argv)
              :env-vars (plist-get mcp-launch :env-vars)
              :cleanup-fn (plist-get mcp-launch :cleanup-fn)
              :post-start-fn
              ;; Preserve backend-specific rendering behavior while letting MCP
              ;; attach its own session metadata after the terminal is created.
              (lambda (buffer process instance-name)
                (with-current-buffer buffer
                  (if (eq ai-code-backends-infra-terminal-backend 'vterm)
                      (setq-local ai-code-backends-infra-strip-alternate-screen t)
                    (setq-local ai-code-backends-infra-strip-alternate-screen nil))
                  (when (eq ai-code-backends-infra-terminal-backend 'ghostel)
                    (setq-local ghostel-full-redraw t)))
                (when mcp-post-start-fn
                  (funcall mcp-post-start-fn buffer process instance-name)))))))
   arg))

;;;###autoload
(defun ai-code-claude-code-switch-to-buffer (&optional force-prompt)
  "Switch to the Claude Code CLI buffer.
When FORCE-PROMPT is non-nil, prompt to select a session."
  (interactive "P")
  (ai-code-backends-infra--cli-switch-to-buffer
   "Claude Code" ai-code-claude-code--session-prefix force-prompt))

;;;###autoload
(defun ai-code-claude-code-send-command (line)
  "Send LINE to Claude Code CLI."
  (interactive "sClaude Code> ")
  (ai-code-backends-infra--cli-send-command
   "Claude Code" ai-code-claude-code--session-prefix line))

;;;###autoload
(defun ai-code-claude-code-send-escape ()
  "Send escape key to Claude Code CLI."
  (interactive)
  (ai-code-backends-infra--terminal-send-escape))

;;;###autoload
(defun ai-code-claude-code-resume (&optional arg)
  "Resume a previous Claude Code CLI session.
With prefix ARG, prompt for additional CLI args."
  (interactive "P")
  (let ((ai-code-claude-code-program-switches
         (append ai-code-claude-code-program-switches '("--resume"))))
    (ai-code-claude-code arg)))

(provide 'ai-code-claude-code)

;;; ai-code-claude-code.el ends here
