import subprocess
import os
import json
from typing import Optional
import structlog

from .base_executor import BaseExecutor, ExecutorResult
from app.configs import settings

logger = structlog.get_logger()


class ClaudeExecutor(BaseExecutor):
    """
    Claude Code 执行器
    通过 Claude API (anthropic) 或 claude CLI 执行编程任务
    """

    name = "claude"

    def __init__(self, repo_path: str):
        super().__init__(repo_path)
        self._setup_client()

    def _setup_client(self):
        try:
            import anthropic
            self.client = anthropic.Anthropic(api_key=settings.anthropic_api_key)
            self.model = "claude-opus-4-5"
            self.logger.info("Claude client initialized", model=self.model)
        except ImportError:
            self.client = None
            self.logger.warning("anthropic package not installed")

    def run(self, task: str, context: Optional[dict] = None) -> ExecutorResult:
        self.logger.info("Claude executor running task", task=task[:100])

        # 优先尝试 claude CLI（Claude Code）
        if self._has_claude_cli():
            return self._run_via_cli(task, context)

        # 回退到 API
        if self.client:
            return self._run_via_api(task, context)

        return ExecutorResult(
            success=False,
            output="",
            error="Claude executor: neither CLI nor API client available",
        )

    def _has_claude_cli(self) -> bool:
        try:
            result = subprocess.run(
                ["claude", "--version"],
                capture_output=True,
                text=True,
                timeout=5,
            )
            return result.returncode == 0
        except (FileNotFoundError, subprocess.TimeoutExpired):
            return False

    def _run_via_cli(self, task: str, context: Optional[dict] = None) -> ExecutorResult:
        context_prompt = self._build_context_prompt(context)
        full_prompt = f"{context_prompt}\n\n{task}" if context_prompt else task

        try:
            result = subprocess.run(
                ["claude", "--print", full_prompt],
                capture_output=True,
                text=True,
                timeout=300,
                cwd=self.repo_path,
                env={**os.environ, "ANTHROPIC_API_KEY": settings.anthropic_api_key},
            )
            success = result.returncode == 0
            return ExecutorResult(
                success=success,
                output=result.stdout,
                error=result.stderr,
                exit_code=result.returncode,
            )
        except subprocess.TimeoutExpired:
            return ExecutorResult(success=False, output="", error="Claude CLI timeout (300s)")
        except Exception as e:
            return ExecutorResult(success=False, output="", error=str(e))

    def _run_via_api(self, task: str, context: Optional[dict] = None) -> ExecutorResult:
        context_prompt = self._build_context_prompt(context)
        system = (
            "You are an expert software engineer. You write clean, tested, production-quality code. "
            "When given a task, implement it fully. Output only the code changes needed."
        )
        messages = []
        if context_prompt:
            messages.append({"role": "user", "content": context_prompt})
            messages.append({"role": "assistant", "content": "Understood. I have the context."})
        messages.append({"role": "user", "content": task})

        try:
            response = self.client.messages.create(
                model=self.model,
                max_tokens=8096,
                system=system,
                messages=messages,
            )
            output = response.content[0].text
            return ExecutorResult(success=True, output=output)
        except Exception as e:
            return ExecutorResult(success=False, output="", error=str(e))

    def health_check(self) -> bool:
        return self._has_claude_cli() or (self.client is not None and bool(settings.anthropic_api_key))
