"""
AI CLI Adapter - 统一接口适配不同 AI CLI (Claude/Gemini/Codex/OpenCode)
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from pathlib import Path
from typing import Literal


@dataclass
class CodeExecutionResult:
    """代码执行结果"""

    success: bool
    message: str
    files_created: list[str] = field(default_factory=list)
    output: str = ""
    error: str | None = None
    exit_code: int = 0


class AICLIAdapter(ABC):
    """AI CLI 适配器抽象基类"""

    @property
    @abstractmethod
    def cli_name(self) -> str:
        """CLI 命令名称，如 'claude', 'gemini'"""
        pass

    @property
    @abstractmethod
    def requires_workspace(self) -> bool:
        """是否需要工作目录"""
        pass

    @property
    def provider(self) -> Literal["claude", "gemini", "codex", "opencode"]:
        """AI 提供商标识"""
        return self.cli_name

    @abstractmethod
    def build_command(self, prompt: str, workspace: Path | None) -> list[str]:
        """构建 CLI 命令"""
        pass

    @abstractmethod
    def parse_output(self, output: str) -> CodeExecutionResult:
        """解析 CLI 输出"""
        pass

    @abstractmethod
    def is_installed(self) -> bool:
        """检查 CLI 是否已安装"""
        pass


class ClaudeAdapter(AICLIAdapter):
    """Claude CLI 适配器"""

    cli_name = "claude"
    requires_workspace = True

    def build_command(self, prompt: str, workspace: Path | None) -> list[str]:
        cmd = ["claude", "-p", prompt]
        if workspace:
            cmd.extend(["--output-format", "stream-json"])
        cmd.append("--dangerously-skip-permissions")
        return cmd

    def parse_output(self, output: str) -> CodeExecutionResult:
        # Claude CLI 输出可能是纯文本或 JSON
        # 简化处理：直接返回输出
        if not output.strip():
            return CodeExecutionResult(
                success=False,
                message="No output from Claude CLI",
                output=output,
            )
        return CodeExecutionResult(
            success=True,
            message="Execution completed",
            output=output,
        )

    def is_installed(self) -> bool:
        import shutil

        return shutil.which("claude") is not None


class GeminiAdapter(AICLIAdapter):
    """Gemini CLI 适配器"""

    cli_name = "gemini"
    requires_workspace = False

    def build_command(self, prompt: str, workspace: Path | None) -> list[str]:
        cmd = ["gemini", "-p", prompt]
        return cmd

    def parse_output(self, output: str) -> CodeExecutionResult:
        if not output.strip():
            return CodeExecutionResult(
                success=False,
                message="No output from Gemini CLI",
                output=output,
            )
        return CodeExecutionResult(
            success=True,
            message="Execution completed",
            output=output,
        )

    def is_installed(self) -> bool:
        import shutil

        return shutil.which("gemini") is not None


class CodexAdapter(AICLIAdapter):
    """Codex CLI 适配器"""

    cli_name = "codex"
    requires_workspace = True

    def build_command(self, prompt: str, workspace: Path | None) -> list[str]:
        cmd = ["codex", "-p", prompt]
        return cmd

    def parse_output(self, output: str) -> CodeExecutionResult:
        if not output.strip():
            return CodeExecutionResult(
                success=False,
                message="No output from Codex CLI",
                output=output,
            )
        return CodeExecutionResult(
            success=True,
            message="Execution completed",
            output=output,
        )

    def is_installed(self) -> bool:
        import shutil

        return shutil.which("codex") is not None


class OpenCodeAdapter(AICLIAdapter):
    """OpenCode CLI 适配器"""

    cli_name = "opencode"
    requires_workspace = True

    def build_command(self, prompt: str, workspace: Path | None) -> list[str]:
        cmd = ["opencode", "-p", prompt]
        return cmd

    def parse_output(self, output: str) -> CodeExecutionResult:
        if not output.strip():
            return CodeExecutionResult(
                success=False,
                message="No output from OpenCode CLI",
                output=output,
            )
        return CodeExecutionResult(
            success=True,
            message="Execution completed",
            output=output,
        )

    def is_installed(self) -> bool:
        import shutil

        return shutil.which("opencode") is not None


# 提供商注册表
ADAPTER_REGISTRY: dict[str, AICLIAdapter] = {
    "claude": ClaudeAdapter(),
    "gemini": GeminiAdapter(),
    "codex": CodexAdapter(),
    "opencode": OpenCodeAdapter(),
}


def get_adapter(provider: str) -> AICLIAdapter:
    """获取指定提供商的适配器"""
    adapter = ADAPTER_REGISTRY.get(provider.lower())
    if adapter is None:
        raise ValueError(
            f"Unknown AI provider: {provider}. Available: {list(ADAPTER_REGISTRY.keys())}"
        )
    return adapter
