"""
Claude Code CLI adapter — runs the ``claude`` CLI as a subprocess.
"""

import subprocess
from typing import Optional

from markitect.llm.adapter import LLMAdapter
from markitect.llm.models import RunConfig, LLMResponse
from markitect.llm.config import LLMConfig
from markitect.llm._token_estimator import estimate_tokens
from markitect.llm.exceptions import (
    LLMSubprocessError,
    LLMTimeoutError,
)


class ClaudeCodeAdapter(LLMAdapter):
    """LLM adapter that shells out to the ``claude`` CLI with ``--print``.

    The compiled prompt is piped via **stdin** to avoid shell argument
    length limits (compiled prompts can exceed 30 KB).
    """

    def __init__(
        self,
        cli_path: str = "claude",
        model: Optional[str] = None,
        config: Optional[LLMConfig] = None,
    ):
        self._config = config or LLMConfig(provider="claude-code")
        self._cli_path = cli_path or self._config.claude_cli_path
        self._model = model

    # ── LLMAdapter interface ────────────────────────────────────────

    def execute_prompt(self, prompt: str, config: RunConfig) -> LLMResponse:
        cmd = [self._cli_path, "--print"]
        if self._model:
            cmd.extend(["--model", self._model])

        timeout = config.timeout_seconds or self._config.timeout_seconds

        try:
            result = subprocess.run(
                cmd,
                input=prompt,
                capture_output=True,
                text=True,
                timeout=timeout,
            )
        except subprocess.TimeoutExpired as exc:
            raise LLMTimeoutError(
                f"claude CLI timed out after {timeout}s",
                cause=exc,
            ) from exc

        if result.returncode != 0:
            raise LLMSubprocessError(
                f"claude CLI exited with code {result.returncode}",
                return_code=result.returncode,
                stderr=result.stderr,
            )

        content = result.stdout
        prompt_tokens = estimate_tokens(prompt)
        completion_tokens = estimate_tokens(content)

        return LLMResponse(
            content=content,
            model=self._model or "claude-code-cli",
            usage={
                "prompt_tokens": prompt_tokens,
                "completion_tokens": completion_tokens,
                "total_tokens": prompt_tokens + completion_tokens,
            },
            finish_reason="stop",
            metadata={
                "provider": "claude-code",
                "cli_path": self._cli_path,
            },
        )

    def validate_config(self, config: RunConfig) -> bool:
        try:
            result = subprocess.run(
                [self._cli_path, "--version"],
                capture_output=True,
                text=True,
                timeout=10,
            )
            return result.returncode == 0
        except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
            return False
