"""
Base Agent - 專家 Agent 基礎類別
================================

定義所有專家 Agent 的共用介面和工具

使用 claude-agent-sdk 的 AgentDefinition
符合 ADR-009 架構規範
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from datetime import UTC, datetime
from enum import Enum
from typing import Any, Generic, TypeVar

import structlog

logger = structlog.get_logger(__name__)


# =============================================================================
# Agent Result Base
# =============================================================================


class AgentStatus(str, Enum):
    """Agent 執行狀態"""
    PENDING = "pending"
    RUNNING = "running"
    SUCCESS = "success"
    FAILED = "failed"
    TIMEOUT = "timeout"


@dataclass
class AgentResult:
    """
    Agent 執行結果基類

    所有專家 Agent 的輸出都必須包含:
    - agent_name: 識別哪個 Agent
    - status: 執行狀態
    - confidence: 信心分數 (0-1)
    - analysis: 分析摘要
    - latency_ms: 執行時間
    """
    agent_name: str
    status: AgentStatus
    confidence: float
    analysis: str
    latency_ms: int
    error: str | None = None
    raw_response: dict[str, Any] = field(default_factory=dict)
    timestamp: datetime = field(default_factory=lambda: datetime.now(UTC))

    def to_dict(self) -> dict[str, Any]:
        """轉換為 dict (API 回傳用)"""
        return {
            "agent_name": self.agent_name,
            "status": self.status.value,
            "confidence": self.confidence,
            "analysis": self.analysis,
            "latency_ms": self.latency_ms,
            "error": self.error,
            "timestamp": self.timestamp.isoformat(),
        }


# =============================================================================
# Base Agent
# =============================================================================

T = TypeVar("T", bound=AgentResult)


class BaseAgent(ABC, Generic[T]):
    """
    專家 Agent 基礎類別

    所有專家 Agent 都繼承此類別，並實作:
    - analyze(): 核心分析邏輯
    - _build_prompt(): 建構 Prompt
    - _parse_response(): 解析回應

    使用方式:
    ```python
    agent = SecurityAgent()
    result = await agent.analyze(incident_context)
    ```
    """

    # Agent 識別資訊 (子類別覆寫)
    AGENT_NAME: str = "base"
    AGENT_DESCRIPTION: str = "Base Agent"
    AGENT_TOOLS: list[str] = ["Read", "Grep"]

    def __init__(self, timeout_sec: float = 30.0):
        """
        初始化 Agent

        Args:
            timeout_sec: 執行超時時間 (秒)
        """
        self.timeout_sec = timeout_sec
        self.logger = logger.bind(agent=self.AGENT_NAME)

    @abstractmethod
    async def analyze(self, context: dict[str, Any]) -> T:
        """
        執行分析 (子類別必須實作)

        Args:
            context: 分析上下文 (incident 資訊)

        Returns:
            AgentResult 子類別實例
        """
        pass

    @abstractmethod
    def _build_prompt(self, context: dict[str, Any]) -> str:
        """
        建構 Prompt (子類別必須實作)

        Args:
            context: 分析上下文

        Returns:
            給 LLM 的 Prompt
        """
        pass

    @abstractmethod
    def _parse_response(self, response: str) -> dict[str, Any]:
        """
        解析 LLM 回應 (子類別必須實作)

        Args:
            response: LLM 原始回應

        Returns:
            解析後的結構化資料
        """
        pass

    def _extract_json(self, text: str) -> dict[str, Any]:
        """
        從 LLM 回應中提取 JSON

        支援:
        - ```json ... ``` 區塊
        - 純 JSON 文字
        """
        import json
        import re

        # 嘗試 ```json ... ``` 格式
        match = re.search(r"```json\s*(.*?)\s*```", text, re.DOTALL)
        if match:
            try:
                return json.loads(match.group(1))
            except json.JSONDecodeError:
                pass

        # 嘗試 { ... } 格式
        match = re.search(r"\{[^{}]*\}", text, re.DOTALL)
        if match:
            try:
                return json.loads(match.group(0))
            except json.JSONDecodeError:
                pass

        # 嘗試整段解析
        try:
            return json.loads(text)
        except json.JSONDecodeError:
            self.logger.warning("json_parse_failed", text=text[:200])
            return {}

    def _get_agent_definition(self) -> dict[str, Any]:
        """
        取得 Claude Agent SDK 的 AgentDefinition

        Returns:
            符合 SDK 規範的 AgentDefinition dict
        """
        return {
            "name": self.AGENT_NAME,
            "description": self.AGENT_DESCRIPTION,
            "tools": self.AGENT_TOOLS,
        }
