"""
n8n HTTP 客户端
封装对 n8n REST API 的调用
"""

import logging
from typing import Any, Dict, List, Optional

import requests
from flask import current_app

logger = logging.getLogger(__name__)

DEFAULT_N8N_API_URL = ""
PLACEHOLDER_N8N_API_URLS = {
    "",
    "https://n8n.example.com",
    "http://n8n.example.com",
}
PLACEHOLDER_N8N_API_KEYS = {
    "",
    "replace-n8n-api-key",
    "your-api-key",
}


class N8nClientError(Exception):
    """n8n 客户端异常"""

    def __init__(
        self,
        message: str,
        status_code: Optional[int] = None,
        response: Optional[dict] = None,
    ):
        self.message = message
        self.status_code = status_code
        self.response = response
        super().__init__(self.message)


class N8nClient:
    """n8n REST API 客户端"""

    def __init__(
        self,
        api_url: Optional[str] = None,
        api_key: Optional[str] = None,
        timeout: Optional[int] = None,
    ):
        """
        初始化 n8n 客户端

        Args:
            api_url: n8n API 地址，默认从配置读取
            api_key: n8n API Key，默认从配置读取
            timeout: 请求超时时间（秒），默认从配置读取
        """
        self.api_url = api_url
        self.api_key = api_key
        self.timeout = timeout

    def _get_config(self):
        """从 Flask 配置获取 n8n 配置"""
        if self.api_url is None:
            configured_url = current_app.config.get("N8N_API_URL", DEFAULT_N8N_API_URL)
            self.api_url = configured_url
        if self.api_key is None:
            configured_key = current_app.config.get("N8N_API_KEY", "")
            self.api_key = configured_key
        if self.timeout is None:
            self.timeout = current_app.config.get("N8N_API_TIMEOUT", 30)
        self.api_url = self._normalize_api_url(self.api_url)
        self.api_key = self._normalize_api_key(self.api_key)

    @staticmethod
    def _normalize_api_url(api_url: Optional[str]) -> str:
        """Treat placeholder n8n URLs as unset."""
        normalized = (api_url or "").strip().rstrip("/")
        if normalized in PLACEHOLDER_N8N_API_URLS:
            return ""
        return normalized

    @staticmethod
    def _normalize_api_key(api_key: Optional[str]) -> str:
        """Treat placeholder n8n API keys as unset."""
        normalized = (api_key or "").strip()
        if normalized in PLACEHOLDER_N8N_API_KEYS:
            return ""
        return normalized

    def _validate_config(self) -> None:
        if not self.api_url:
            raise N8nClientError("N8N_API_URL 未配置")
        if not self.api_key:
            raise N8nClientError("N8N_API_KEY 未配置")

    def _get_headers(self) -> Dict[str, str]:
        """获取请求头"""
        self._get_config()
        self._validate_config()
        return {
            "X-N8N-API-KEY": self.api_key or "",
            "Content-Type": "application/json",
            "Accept": "application/json",
        }

    def _build_url(self, endpoint: str) -> str:
        """构建完整的 API URL"""
        self._get_config()
        base_url = self.api_url.rstrip("/") if self.api_url else ""
        endpoint = endpoint.lstrip("/")
        return f"{base_url}/api/v1/{endpoint}"

    def _request(
        self,
        method: str,
        endpoint: str,
        params: Optional[Dict] = None,
        data: Optional[Dict] = None,
    ) -> Dict[str, Any]:
        """
        发送 HTTP 请求

        Args:
            method: HTTP 方法 (GET, POST, PUT, DELETE)
            endpoint: API 端点
            params: URL 查询参数
            data: 请求体数据

        Returns:
            API 响应数据

        Raises:
            N8nClientError: 请求失败时抛出
        """
        url = self._build_url(endpoint)
        headers = self._get_headers()

        logger.debug(f"n8n API 请求: {method} {url}")

        try:
            response = requests.request(
                method=method,
                url=url,
                headers=headers,
                params=params,
                json=data,
                timeout=self.timeout,
            )

            # 检查响应状态
            if response.status_code == 401:
                raise N8nClientError(
                    "n8n API 认证失败，请检查 API Key 配置", status_code=401
                )
            elif response.status_code == 403:
                raise N8nClientError("n8n API 权限不足", status_code=403)
            elif response.status_code == 404:
                raise N8nClientError("请求的资源不存在", status_code=404)
            elif response.status_code >= 500:
                raise N8nClientError(
                    f"n8n 服务器错误: {response.status_code}",
                    status_code=response.status_code,
                )

            response.raise_for_status()

            # 解析响应
            if response.content:
                return response.json()
            return {}

        except requests.exceptions.Timeout as e:
            logger.error(f"n8n API 请求超时: {url}")
            raise N8nClientError("n8n API 请求超时") from e
        except requests.exceptions.ConnectionError as e:
            logger.error(f"n8n API 连接失败: {url}")
            raise N8nClientError("无法连接到 n8n 服务") from e
        except requests.exceptions.RequestException as e:
            logger.error(f"n8n API 请求异常: {str(e)}")
            raise N8nClientError(f"n8n API 请求失败: {str(e)}") from e

    # ==================== 工作流相关 API ====================

    def list_workflows(
        self,
        active: Optional[bool] = None,
        tags: Optional[List[str]] = None,
        limit: int = 100,
        cursor: Optional[str] = None,
    ) -> Dict[str, Any]:
        """
        获取工作流列表

        Args:
            active: 过滤活跃状态 (True/False/None)
            tags: 按标签过滤
            limit: 返回数量限制 (1-100)
            cursor: 分页游标

        Returns:
            工作流列表数据
        """
        params: Dict[str, Any] = {"limit": min(limit, 100)}

        if active is not None:
            params["active"] = "true" if active else "false"
        if tags:
            params["tags"] = ",".join(tags)
        if cursor:
            params["cursor"] = cursor

        return self._request("GET", "workflows", params=params)

    def get_workflow(self, workflow_id: str) -> Dict[str, Any]:
        """
        获取单个工作流详情

        Args:
            workflow_id: 工作流 ID

        Returns:
            工作流详情数据
        """
        return self._request("GET", f"workflows/{workflow_id}")

    def activate_workflow(self, workflow_id: str) -> Dict[str, Any]:
        """
        激活工作流

        Args:
            workflow_id: 工作流 ID

        Returns:
            更新后的工作流数据
        """
        return self._request("POST", f"workflows/{workflow_id}/activate")

    def deactivate_workflow(self, workflow_id: str) -> Dict[str, Any]:
        """
        停用工作流

        Args:
            workflow_id: 工作流 ID

        Returns:
            更新后的工作流数据
        """
        return self._request("POST", f"workflows/{workflow_id}/deactivate")

    def create_workflow(self, workflow_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        创建新工作流

        Args:
            workflow_data: 工作流配置数据，包含:
                - name: 工作流名称
                - nodes: 节点列表
                - connections: 连接配置
                - settings: 工作流设置（可选）

        Returns:
            创建的工作流数据（包含生成的ID）
        """
        return self._request("POST", "workflows", data=workflow_data)

    def update_workflow(
        self, workflow_id: str, workflow_data: Dict[str, Any]
    ) -> Dict[str, Any]:
        """
        更新工作流

        Args:
            workflow_id: 工作流 ID
            workflow_data: 更新的工作流配置数据

        Returns:
            更新后的工作流数据
        """
        return self._request("PUT", f"workflows/{workflow_id}", data=workflow_data)

    def delete_workflow(self, workflow_id: str) -> Dict[str, Any]:
        """
        删除工作流

        Args:
            workflow_id: 工作流 ID

        Returns:
            删除结果
        """
        return self._request("DELETE", f"workflows/{workflow_id}")

    # ==================== 执行记录相关 API ====================

    def list_executions(
        self,
        workflow_id: Optional[str] = None,
        status: Optional[str] = None,
        limit: int = 100,
        cursor: Optional[str] = None,
        include_data: bool = False,
    ) -> Dict[str, Any]:
        """
        获取执行记录列表

        Args:
            workflow_id: 按工作流 ID 过滤
            status: 按状态过滤 (success, error, waiting)
            limit: 返回数量限制 (1-100)
            cursor: 分页游标
            include_data: 是否包含执行数据

        Returns:
            执行记录列表数据
        """
        params: Dict[str, Any] = {"limit": min(limit, 100)}

        if workflow_id:
            params["workflowId"] = workflow_id
        if status:
            params["status"] = status
        if cursor:
            params["cursor"] = cursor
        if include_data:
            params["includeData"] = "true"

        return self._request("GET", "executions", params=params)

    def get_execution(
        self, execution_id: str, include_data: bool = True
    ) -> Dict[str, Any]:
        """
        获取单次执行详情

        Args:
            execution_id: 执行 ID
            include_data: 是否包含执行数据

        Returns:
            执行详情数据
        """
        params: Dict[str, Any] = {}
        if include_data:
            params["includeData"] = "true"

        return self._request("GET", f"executions/{execution_id}", params=params)

    def delete_execution(self, execution_id: str) -> Dict[str, Any]:
        """
        删除执行记录

        Args:
            execution_id: 执行 ID

        Returns:
            删除结果
        """
        return self._request("DELETE", f"executions/{execution_id}")

    # ==================== 工作流触发 API ====================

    def execute_workflow_webhook(
        self, webhook_path: str, data: Optional[Dict] = None, method: str = "POST"
    ) -> Dict[str, Any]:
        """
        通过 Webhook 触发工作流

        Args:
            webhook_path: Webhook 路径
            data: 请求数据
            method: HTTP 方法

        Returns:
            执行结果
        """
        self._get_config()
        base_url = self.api_url.rstrip("/") if self.api_url else ""
        url = f"{base_url}/webhook/{webhook_path}"

        headers = {"Content-Type": "application/json", "Accept": "application/json"}

        try:
            response = requests.request(
                method=method, url=url, headers=headers, json=data, timeout=self.timeout
            )
            response.raise_for_status()

            if response.content:
                return response.json()
            return {"success": True}

        except requests.exceptions.RequestException as e:
            logger.error(f"Webhook 触发失败: {str(e)}")
            raise N8nClientError(f"Webhook 触发失败: {str(e)}") from e

    # ==================== 健康检查 ====================

    def health_check(self) -> Dict[str, Any]:
        """
        检查 n8n 服务健康状态

        Returns:
            健康状态信息
        """
        try:
            # 尝试获取工作流列表来验证连接
            self.list_workflows(limit=1)
            return {
                "status": "healthy",
                "connected": True,
                "api_url": self.api_url or "",
            }
        except N8nClientError as e:
            return {
                "status": "unhealthy",
                "connected": False,
                "error": e.message,
                "api_url": self.api_url or "",
            }
