"""ConfluenceAdapter - Confluence 知识库适配器

对接 Confluence REST API，实现 KnowledgeBase 协议。
通过 base_url + username + api_token 认证。
"""

from __future__ import annotations

import logging
from typing import Any

import httpx

from agentkit.memory.adapters.base import KBAdapter
from agentkit.memory.knowledge_base import Document, QueryResult, SourceInfo
from agentkit.utils.security import is_safe_url

logger = logging.getLogger(__name__)


def _escape_cql(value: str) -> str:
    """Escape special characters in CQL values."""
    return value.replace("\\", "\\\\").replace('"', '\\"')


class ConfluenceAdapter(KBAdapter):
    """Confluence 知识库适配器

    对接 Confluence REST API，支持：
    - CQL 搜索
    - 获取页面内容
    - 列出空间

    典型配置::

        adapter = ConfluenceAdapter(
            base_url="https://your-domain.atlassian.net/wiki",
            username="user@example.com",
            api_token="xxx",
        )
    """

    def __init__(
        self,
        base_url: str,
        username: str,
        api_token: str,
        space_keys: list[str] | None = None,
        timeout: int = 30,
    ):
        super().__init__(
            source_id=f"confluence-{username.split('@')[0]}",
            source_name="Confluence",
            source_type="confluence",
            timeout=timeout,
        )
        self._base_url = base_url.rstrip("/")
        if not is_safe_url(self._base_url):
            raise ValueError(f"Unsafe base_url: {self._base_url}. Private/internal URLs are not allowed.")
        self._username = username
        self._api_token = api_token
        self._space_keys = space_keys or []

    def _make_client(self) -> httpx.AsyncClient:
        """创建 Confluence API HTTP 客户端"""
        import base64

        credentials = base64.b64encode(
            f"{self._username}:{self._api_token}".encode()
        ).decode()
        return httpx.AsyncClient(
            base_url=self._base_url,
            headers={
                "Content-Type": "application/json",
                "Authorization": f"Basic {credentials}",
            },
            timeout=self._timeout,
        )

    async def authenticate(self) -> bool:
        """Confluence 认证验证"""
        client = self._get_client()
        try:
            resp = await client.get("/rest/api/user/current")
            self._authenticated = resp.status_code == 200
            return self._authenticated
        except Exception as e:
            logger.error(f"Confluence auth error: {e}")
            self._authenticated = False
            return False

    async def search(self, query: str, top_k: int = 5) -> list[QueryResult]:
        """搜索 Confluence 页面

        使用 CQL (Confluence Query Language) 进行搜索。
        """
        client = self._get_client()
        try:
            cql = f'text ~ "{_escape_cql(query)}"'
            if self._space_keys:
                space_filter = " OR ".join(
                    f'space = "{_escape_cql(key)}"' for key in self._space_keys
                )
                cql = f'{cql} AND ({space_filter})'

            resp = await client.get(
                "/rest/api/content/search",
                params={"cql": cql, "limit": top_k, "expand": "body.storage"},
            )
            resp.raise_for_status()
            data = resp.json()

            results: list[QueryResult] = []
            for page in data.get("results", []):
                body = page.get("body", {}).get("storage", {}).get("value", "")
                # Strip HTML tags for plain text content
                import re
                content = re.sub(r"<[^>]+>", "", body) if body else page.get("title", "")

                results.append(
                    QueryResult(
                        content=content[:2000],  # Limit content length
                        source_id=self._source_id,
                        source_name=self._source_name,
                        score=1.0,  # Confluence doesn't return relevance score
                        metadata={
                            "space_key": page.get("space", {}).get("key", ""),
                            "type": page.get("type", ""),
                            "status": page.get("status", ""),
                        },
                        doc_id=page.get("id", ""),
                        title=page.get("title", ""),
                    )
                )
            return results[:top_k]

        except httpx.HTTPStatusError as e:
            logger.error(
                f"Confluence search HTTP error: {e.response.status_code} — "
                f"{e.response.text[:200]}"
            )
            return []
        except Exception as e:
            logger.error(f"Confluence search error: {e}")
            return []

    async def get_document(self, doc_id: str) -> Document | None:
        """获取 Confluence 页面内容"""
        client = self._get_client()
        try:
            resp = await client.get(
                f"/rest/api/content/{doc_id}",
                params={"expand": "body.storage,space"},
            )
            resp.raise_for_status()
            page = resp.json()

            body = page.get("body", {}).get("storage", {}).get("value", "")
            import re
            content = re.sub(r"<[^>]+>", "", body) if body else ""

            return Document(
                doc_id=str(page.get("id", doc_id)),
                content=content,
                title=page.get("title", ""),
                source_id=self._source_id,
                metadata={
                    "space_key": page.get("space", {}).get("key", ""),
                    "type": page.get("type", ""),
                    "version": page.get("version", {}).get("number", 0),
                },
            )
        except Exception as e:
            logger.error(f"Confluence get_document error: {e}")
            return None

    async def list_sources(self) -> list[SourceInfo]:
        """列出 Confluence 空间"""
        client = self._get_client()
        try:
            resp = await client.get("/rest/api/space", params={"limit": 50})
            resp.raise_for_status()
            data = resp.json()

            sources: list[SourceInfo] = []
            for space in data.get("results", []):
                sources.append(
                    SourceInfo(
                        source_id=f"confluence-space-{space.get('key', '')}",
                        source_name=space.get("name", ""),
                        source_type="confluence",
                    )
                )
            return sources if sources else [
                SourceInfo(
                    source_id=self._source_id,
                    source_name=self._source_name,
                    source_type=self._source_type,
                )
            ]
        except Exception as e:
            logger.error(f"Confluence list_sources error: {e}")
            return [
                SourceInfo(
                    source_id=self._source_id,
                    source_name=self._source_name,
                    source_type=self._source_type,
                )
            ]

    async def health_check(self) -> bool:
        """检查 Confluence API 连接状态"""
        client = self._get_client()
        try:
            resp = await client.get("/rest/api/space", params={"limit": 1})
            return resp.status_code == 200
        except Exception:
            return False
