"""
n8n 工作流服务层
处理业务逻辑、数据转换和格式化
"""

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

from app.core.data_factory.n8n_client import N8nClient, N8nClientError

logger = logging.getLogger(__name__)


class N8nService:
    """n8n 工作流服务"""

    # 执行状态映射
    STATUS_MAP = {
        "success": "成功",
        "error": "失败",
        "waiting": "等待中",
        "running": "运行中",
        "unknown": "未知",
    }

    @staticmethod
    def _get_client() -> N8nClient:
        """获取 n8n 客户端实例"""
        return N8nClient()

    @staticmethod
    def _format_datetime(dt_str: Optional[str]) -> str:
        """
        格式化日期时间字符串

        Args:
            dt_str: ISO 格式的日期时间字符串

        Returns:
            格式化后的字符串
        """
        if not dt_str:
            return ""
        try:
            dt = datetime.fromisoformat(dt_str.replace("Z", "+00:00"))
            return dt.strftime("%Y-%m-%d %H:%M:%S")
        except (ValueError, AttributeError):
            return dt_str

    @staticmethod
    def _format_workflow(workflow: Dict) -> Dict:
        """
        格式化工作流数据

        Args:
            workflow: 原始工作流数据

        Returns:
            格式化后的工作流数据
        """
        return {
            "id": workflow.get("id"),
            "name": workflow.get("name", ""),
            "active": workflow.get("active", False),
            "tags": [tag.get("name", "") for tag in workflow.get("tags", [])],
            "created_at": N8nService._format_datetime(workflow.get("createdAt")),
            "updated_at": N8nService._format_datetime(workflow.get("updatedAt")),
            "nodes_count": len(workflow.get("nodes", [])),
            "nodes": N8nService._format_nodes(workflow.get("nodes", [])),
            "settings": workflow.get("settings", {}),
        }

    @staticmethod
    def _format_workflow_summary(workflow: Dict) -> Dict:
        """
        格式化工作流摘要（列表用）

        Args:
            workflow: 原始工作流数据

        Returns:
            格式化后的工作流摘要
        """
        return {
            "id": workflow.get("id"),
            "name": workflow.get("name", ""),
            "active": workflow.get("active", False),
            "tags": [tag.get("name", "") for tag in workflow.get("tags", [])],
            "created_at": N8nService._format_datetime(workflow.get("createdAt")),
            "updated_at": N8nService._format_datetime(workflow.get("updatedAt")),
        }

    @staticmethod
    def _format_nodes(nodes: List[Dict]) -> List[Dict]:
        """
        格式化节点列表

        Args:
            nodes: 原始节点列表

        Returns:
            格式化后的节点列表
        """
        return [
            {
                "id": node.get("id"),
                "name": node.get("name", ""),
                "type": node.get("type", ""),
                "type_version": node.get("typeVersion"),
                "position": node.get("position", []),
                "disabled": node.get("disabled", False),
            }
            for node in nodes
        ]

    @staticmethod
    def _format_execution(execution: Dict) -> Dict:
        """
        格式化执行记录

        Args:
            execution: 原始执行记录数据

        Returns:
            格式化后的执行记录
        """
        status = execution.get("status", "unknown")

        return {
            "id": execution.get("id"),
            "workflow_id": execution.get("workflowId"),
            "workflow_name": execution.get("workflowData", {}).get("name", ""),
            "status": status,
            "status_label": N8nService.STATUS_MAP.get(status, "未知"),
            "mode": execution.get("mode", ""),
            "started_at": N8nService._format_datetime(execution.get("startedAt")),
            "finished_at": N8nService._format_datetime(execution.get("stoppedAt")),
            "retry_of": execution.get("retryOf"),
            "retry_success_id": execution.get("retrySuccessId"),
        }

    @staticmethod
    def _format_execution_detail(execution: Dict) -> Dict:
        """
        格式化执行详情（包含执行数据）

        Args:
            execution: 原始执行详情数据

        Returns:
            格式化后的执行详情
        """
        base = N8nService._format_execution(execution)

        # 添加执行数据
        data = execution.get("data", {})
        result_data = data.get("resultData", {})
        run_data = result_data.get("runData", {})

        # 提取节点执行结果
        node_results = []
        for node_name, node_runs in run_data.items():
            for run in node_runs:
                node_results.append(
                    {
                        "node_name": node_name,
                        "start_time": N8nService._format_datetime(run.get("startTime")),
                        "execution_time": run.get("executionTime"),
                        "source": run.get("source", []),
                        "data": run.get("data", {}),
                    }
                )

        base["node_results"] = node_results
        base["error"] = result_data.get("error")

        return base

    # ==================== 工作流服务方法 ====================

    @classmethod
    def get_workflows(
        cls,
        page: int = 1,
        page_size: int = 20,
        active: Optional[bool] = None,
        tags: Optional[List[str]] = None,
        search: Optional[str] = None,
    ) -> Dict[str, Any]:
        """
        获取工作流列表（带分页）

        Args:
            page: 页码（从1开始）
            page_size: 每页数量
            active: 过滤活跃状态
            tags: 按标签过滤
            search: 搜索关键词（按名称过滤）

        Returns:
            分页后的工作流列表
        """
        client = cls._get_client()

        # n8n API 使用游标分页，这里简化为获取所有数据后内存分页
        # 生产环境应考虑使用游标分页优化
        all_workflows = []
        cursor = None

        try:
            while True:
                result = client.list_workflows(
                    active=active, tags=tags, limit=100, cursor=cursor
                )

                workflows = result.get("data", [])
                all_workflows.extend(workflows)

                # 检查是否有更多数据
                next_cursor = result.get("nextCursor")
                if not next_cursor or not workflows:
                    break
                cursor = next_cursor

            # 按名称搜索过滤
            if search:
                search_lower = search.lower()
                all_workflows = [
                    w
                    for w in all_workflows
                    if search_lower in w.get("name", "").lower()
                ]

            # 计算分页
            total = len(all_workflows)
            start = (page - 1) * page_size
            end = start + page_size
            page_workflows = all_workflows[start:end]

            return {
                "items": [cls._format_workflow_summary(w) for w in page_workflows],
                "total": total,
                "page": page,
                "page_size": page_size,
                "total_pages": (total + page_size - 1) // page_size
                if page_size > 0
                else 0,
            }

        except N8nClientError as e:
            logger.error(f"获取工作流列表失败: {e.message}")
            raise

    @classmethod
    def get_workflow_by_id(cls, workflow_id: str) -> Dict[str, Any]:
        """
        获取工作流详情

        Args:
            workflow_id: 工作流 ID

        Returns:
            工作流详情
        """
        client = cls._get_client()

        try:
            workflow = client.get_workflow(workflow_id)
            return cls._format_workflow(workflow)
        except N8nClientError as e:
            logger.error(f"获取工作流详情失败: {e.message}")
            raise

    @classmethod
    def get_workflow_status(cls, workflow_id: str) -> Dict[str, Any]:
        """
        获取工作流状态

        Args:
            workflow_id: 工作流 ID

        Returns:
            工作流状态信息
        """
        client = cls._get_client()

        try:
            workflow = client.get_workflow(workflow_id)

            # 获取最近的执行记录
            executions = client.list_executions(workflow_id=workflow_id, limit=5)

            recent_executions = executions.get("data", [])

            # 统计执行状态
            success_count = sum(
                1 for e in recent_executions if e.get("status") == "success"
            )
            error_count = sum(
                1 for e in recent_executions if e.get("status") == "error"
            )

            return {
                "workflow_id": workflow_id,
                "name": workflow.get("name", ""),
                "active": workflow.get("active", False),
                "status": "active" if workflow.get("active") else "inactive",
                "status_label": "运行中" if workflow.get("active") else "已停用",
                "recent_executions": {
                    "total": len(recent_executions),
                    "success": success_count,
                    "error": error_count,
                },
                "last_execution": cls._format_execution(recent_executions[0])
                if recent_executions
                else None,
                "updated_at": cls._format_datetime(workflow.get("updatedAt")),
            }

        except N8nClientError as e:
            logger.error(f"获取工作流状态失败: {e.message}")
            raise

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

        Args:
            workflow_id: 工作流 ID

        Returns:
            更新后的工作流信息
        """
        client = cls._get_client()

        try:
            result = client.activate_workflow(workflow_id)
            return {
                "workflow_id": workflow_id,
                "active": result.get("active", True),
                "message": "工作流已激活",
            }
        except N8nClientError as e:
            logger.error(f"激活工作流失败: {e.message}")
            raise

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

        Args:
            workflow_id: 工作流 ID

        Returns:
            更新后的工作流信息
        """
        client = cls._get_client()

        try:
            result = client.deactivate_workflow(workflow_id)
            return {
                "workflow_id": workflow_id,
                "active": result.get("active", False),
                "message": "工作流已停用",
            }
        except N8nClientError as e:
            logger.error(f"停用工作流失败: {e.message}")
            raise

    # ==================== 执行记录服务方法 ====================

    @classmethod
    def get_executions(
        cls,
        workflow_id: Optional[str] = None,
        status: Optional[str] = None,
        page: int = 1,
        page_size: int = 20,
    ) -> Dict[str, Any]:
        """
        获取执行记录列表

        Args:
            workflow_id: 工作流 ID（可选）
            status: 状态过滤（可选）
            page: 页码
            page_size: 每页数量

        Returns:
            分页后的执行记录列表
        """
        client = cls._get_client()

        try:
            # 获取执行记录
            all_executions = []
            cursor = None

            while True:
                result = client.list_executions(
                    workflow_id=workflow_id, status=status, limit=100, cursor=cursor
                )

                executions = result.get("data", [])
                all_executions.extend(executions)

                next_cursor = result.get("nextCursor")
                if not next_cursor or not executions:
                    break
                cursor = next_cursor

            # 计算分页
            total = len(all_executions)
            start = (page - 1) * page_size
            end = start + page_size
            page_executions = all_executions[start:end]

            return {
                "items": [cls._format_execution(e) for e in page_executions],
                "total": total,
                "page": page,
                "page_size": page_size,
                "total_pages": (total + page_size - 1) // page_size
                if page_size > 0
                else 0,
            }

        except N8nClientError as e:
            logger.error(f"获取执行记录列表失败: {e.message}")
            raise

    @classmethod
    def get_execution_by_id(cls, execution_id: str) -> Dict[str, Any]:
        """
        获取执行详情

        Args:
            execution_id: 执行 ID

        Returns:
            执行详情
        """
        client = cls._get_client()

        try:
            execution = client.get_execution(execution_id, include_data=True)
            return cls._format_execution_detail(execution)
        except N8nClientError as e:
            logger.error(f"获取执行详情失败: {e.message}")
            raise

    # ==================== 工作流触发服务方法 ====================

    @classmethod
    def trigger_workflow(
        cls,
        workflow_id: str,
        webhook_path: Optional[str] = None,
        data: Optional[Dict] = None,
    ) -> Dict[str, Any]:
        """
        触发工作流执行

        Args:
            workflow_id: 工作流 ID
            webhook_path: Webhook 路径（如果工作流有 Webhook 触发器）
            data: 触发数据

        Returns:
            触发结果
        """
        client = cls._get_client()

        try:
            if webhook_path:
                # 通过 Webhook 触发
                result = client.execute_workflow_webhook(
                    webhook_path=webhook_path, data=data or {}
                )
                return {
                    "success": True,
                    "message": "工作流已通过 Webhook 触发",
                    "workflow_id": workflow_id,
                    "response": result,
                }
            else:
                # 如果没有提供 webhook_path，返回错误提示
                return {
                    "success": False,
                    "message": "请提供 Webhook 路径以触发工作流",
                    "workflow_id": workflow_id,
                }

        except N8nClientError as e:
            logger.error(f"触发工作流失败: {e.message}")
            raise

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

    @classmethod
    def health_check(cls) -> Dict[str, Any]:
        """
        检查 n8n 服务连接状态

        Returns:
            健康状态信息
        """
        client = cls._get_client()
        return client.health_check()
