"""
OpenClaw HTTP Service - 統一 OpenClaw API 呼叫
==============================================
Phase 22 P0 修復: Router 層禁止直接 httpx.AsyncClient

遵循規範:
- Skill 09: Router 層禁止直接外部 API 呼叫
- feedback_lewooogo_modular_enforcement.md: Service 層封裝

功能:
- Error Analysis (Sentry 錯誤分析)
- Code Review (PR 代碼審查)
- Push Review (Push 審查)
- CI Diagnosis (CI 失敗診斷)

設計原則:
- 返回 dict | None，由調用者決定如何轉換為具體類型
- 保持與現有調用者的相容性

版本: v1.0
建立: 2026-03-31 (台北時區)
建立者: Claude Code (首席架構師 P0 修復)
"""

import httpx
import structlog

from src.core.config import settings

logger = structlog.get_logger(__name__)


# =============================================================================
# OpenClaw HTTP Service
# =============================================================================


class OpenClawHttpService:
    """
    OpenClaw HTTP Service

    統一 OpenClaw API 呼叫，符合 leWOOOgo 積木化原則

    2026-03-31 Claude Code (Phase 22 P0 修復)
    """

    def __init__(
        self,
        base_url: str | None = None,
        default_timeout: float = 60.0,
    ):
        self._base_url = base_url or settings.OPENCLAW_URL
        self._default_timeout = default_timeout

    async def analyze_error(
        self,
        error_context: dict,
        prefer_local: bool = True,
        timeout: float | None = None,
    ) -> dict | None:
        """
        呼叫 OpenClaw Error Analyzer Agent

        Args:
            error_context: 錯誤上下文
            prefer_local: 優先使用 Ollama (本地，零成本)
            timeout: 超時秒數 (預設 60s)

        Returns:
            dict | None: API 回應 JSON，由調用者轉換為具體類型
        """
        try:
            async with httpx.AsyncClient(
                timeout=timeout or self._default_timeout
            ) as client:
                response = await client.post(
                    f"{self._base_url}/api/v1/analyze/error",
                    json={
                        "error_context": error_context,
                        "prefer_local": prefer_local,
                    },
                )

                if response.status_code == 200:
                    return response.json()
                else:
                    logger.warning(
                        "openclaw_analyze_error_failed",
                        status=response.status_code,
                    )
                    return None

        except httpx.TimeoutException:
            logger.warning("openclaw_analyze_error_timeout")
            return None
        except Exception as e:
            logger.exception("openclaw_analyze_error_exception", error=str(e))
            return None

    async def code_review(
        self,
        repo_name: str,
        pr_title: str,
        pr_body: str,
        diff_content: str,
        changed_files: int,
        additions: int,
        deletions: int,
        prefer_local: bool = True,
        timeout: float = 120.0,
    ) -> dict | None:
        """
        呼叫 OpenClaw 進行 PR 代碼審查

        Args:
            repo_name: 倉庫名稱
            pr_title: PR 標題
            pr_body: PR 描述
            diff_content: diff 內容
            changed_files: 變更檔案數
            additions: 新增行數
            deletions: 刪除行數
            prefer_local: 優先 Ollama
            timeout: 超時秒數 (預設 120s)

        Returns:
            dict | None: API 回應 JSON
        """
        try:
            async with httpx.AsyncClient(timeout=timeout) as client:
                response = await client.post(
                    f"{self._base_url}/api/v1/analyze/code-review",
                    json={
                        "repo": repo_name,
                        "pr_title": pr_title,
                        "pr_body": pr_body,
                        "diff": diff_content,
                        "changed_files": changed_files,
                        "additions": additions,
                        "deletions": deletions,
                        "prefer_local": prefer_local,
                    },
                )

                if response.status_code == 200:
                    return response.json()
                else:
                    logger.warning(
                        "openclaw_code_review_failed",
                        status=response.status_code,
                        response=response.text[:200],
                    )
                    return None

        except httpx.TimeoutException:
            logger.warning("openclaw_code_review_timeout")
            return None
        except Exception as e:
            logger.exception("openclaw_code_review_exception", error=str(e))
            return None

    async def push_review(
        self,
        repo_name: str,
        ref: str,
        commits: list[dict],
        files_changed: dict,
        prefer_local: bool = True,
        timeout: float = 120.0,
    ) -> dict | None:
        """
        呼叫 OpenClaw 進行 Push 代碼審查

        Args:
            repo_name: 倉庫名稱
            ref: Git ref
            commits: commit 列表
            files_changed: 變更檔案
            prefer_local: 優先 Ollama
            timeout: 超時秒數

        Returns:
            dict | None: API 回應 JSON
        """
        try:
            async with httpx.AsyncClient(timeout=timeout) as client:
                response = await client.post(
                    f"{self._base_url}/api/v1/analyze/push-review",
                    json={
                        "repo": repo_name,
                        "ref": ref,
                        "commits": commits,
                        "files_changed": files_changed,
                        "prefer_local": prefer_local,
                    },
                )

                if response.status_code == 200:
                    return response.json()
                else:
                    logger.warning(
                        "openclaw_push_review_failed",
                        status=response.status_code,
                    )
                    return None

        except httpx.TimeoutException:
            logger.warning("openclaw_push_review_timeout")
            return None
        except Exception as e:
            logger.exception("openclaw_push_review_exception", error=str(e))
            return None

    async def ci_diagnosis(
        self,
        repo_name: str,
        failure_context: dict,
        prefer_local: bool = True,
        timeout: float = 120.0,
    ) -> dict | None:
        """
        呼叫 OpenClaw 進行 CI 失敗診斷

        Args:
            repo_name: 倉庫名稱
            failure_context: 失敗上下文
            prefer_local: 優先 Ollama
            timeout: 超時秒數

        Returns:
            dict | None: API 回應 JSON
        """
        try:
            async with httpx.AsyncClient(timeout=timeout) as client:
                response = await client.post(
                    f"{self._base_url}/api/v1/analyze/ci-failure",
                    json={
                        "repo": repo_name,
                        "workflow_name": failure_context.get("workflow_name"),
                        "conclusion": failure_context.get("conclusion"),
                        "head_sha": failure_context.get("head_sha"),
                        "head_branch": failure_context.get("head_branch"),
                        "event_trigger": failure_context.get("event_trigger"),
                        "run_number": failure_context.get("run_number"),
                        "run_attempt": failure_context.get("run_attempt"),
                        "workflow_url": failure_context.get("html_url"),
                        "prefer_local": prefer_local,
                    },
                )

                if response.status_code == 200:
                    return response.json()
                else:
                    logger.warning(
                        "openclaw_ci_diagnosis_failed",
                        status=response.status_code,
                    )
                    return None

        except httpx.TimeoutException:
            logger.warning("openclaw_ci_diagnosis_timeout")
            return None
        except Exception as e:
            logger.exception("openclaw_ci_diagnosis_exception", error=str(e))
            return None


# =============================================================================
# Singleton
# =============================================================================

_openclaw_http_service: OpenClawHttpService | None = None


def get_openclaw_http_service() -> OpenClawHttpService:
    """取得 OpenClawHttpService singleton"""
    global _openclaw_http_service
    if _openclaw_http_service is None:
        _openclaw_http_service = OpenClawHttpService()
    return _openclaw_http_service
