"""
节点处理器 V2 (Node Handler - Pure Execution Layer)

Handler 职责：
1. 执行后端 API 调用（load/create/update/delete）
2. 返回执行结果（TaskResult）
3. 提供异步任务轮询（poll）
4. 提供数据质量检查（validate）

Handler 不负责：
- ❌ 状态管理（由 DataSource 负责）
- ❌ ID 映射（由 Strategy 负责，已保存在 node.data）
- ❌ 依赖关系（由 Strategy 负责）
"""
from __future__ import annotations

from typing import (
    TypeVar, Generic, Type, Protocol, Dict, List, Any, Optional, 
    runtime_checkable, TYPE_CHECKING
)
from abc import ABC, abstractmethod
from pydantic import BaseModel

from .task_result import TaskResult

if TYPE_CHECKING:
    from ..common.sync_node import SyncNode
    from ..common.collection import DataCollection
    from .api.client import ApiClient

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


class ValidationResult:
    """数据质量检查结果"""
    def __init__(self, is_valid: bool, errors: Optional[List[str]] = None):
        self.is_valid = is_valid
        self.errors = errors or []


@runtime_checkable
class NodeHandler(Protocol[T]):
    """
    节点处理器协议（纯执行层）
    
    Handler 只负责调用后端 API，不管理状态。
    """
    
    @property
    def node_type(self) -> str:
        """节点类型（如 'contract'）"""
        ...
    
    @property
    def node_class(self) -> Type["SyncNode[T]"]:
        """SyncNode 类型"""
        ...
    
    @property
    def schema(self) -> Type[T]:
        """Schema 类型"""
        ...
    
    def set_collection(self, collection: "DataCollection") -> None:
        """
        设置 Collection 引用
        
        Args:
            collection: 数据集合
        """
        ...

    def set_handler_config(self, config: Dict[str, Any]) -> None:
        """注入 handler 级别配置。默认可忽略。"""
        ...

    def set_api_client(self, client: "ApiClient") -> None:
        """注入 API 客户端。默认可忽略。"""
        ...

    def set_poll_mode(self, mode: str) -> None:
        """设置轮询模式。默认可忽略。"""
        ...

    def get_update_fields(self, *, exclude: frozenset[str] = frozenset({"id"})) -> List[str]:
        """返回 post-check 可比较字段列表。默认空。"""
        ...
    
    async def load(self) -> List['SyncNode']:
        """
        从后端加载全部数据并创建节点
        
        注意：调用前需先 set_collection()
            
        Returns:
            SyncNode 列表
            
        示例：
            # Project Handler（无依赖）
            async def load(self):
                response = await self.api.get_projects()
                nodes = []
                for data in response["data"]:
                    node = self.create_node(data)
                    node.context["project_id"] = data["id"]
                    nodes.append(node)
                return nodes
            
            # Contract Handler（依赖 Project）
            async def load(self):
                # 使用 self._collection 查询依赖
                projects = self._collection.filter(node_type="project")
                project_ids = [p.data_id for p in projects if p.data_id]
                
                nodes = []
                for project_id in project_ids:
                    response = await self.api.get_contracts(project_id=project_id)
                    for data in response["data"]:
                        node = self.create_node(data)
                        node.context["project_id"] = project_id
                        node.context["contract_id"] = data["id"]
                        nodes.append(node)
                return nodes
        """
        ...
    
    async def create_all(
        self, 
        nodes: List["SyncNode"]
    ) -> List[TaskResult]:
        """
        批量创建节点
        
        Args:
            nodes: 需要创建的节点列表（DataSource 已筛选为 CREATE + PENDING）
            
        Returns:
            List[TaskResult]:
                每个 TaskResult 必须包含 node_id，用于定位节点：
                - TaskResult(status=SUCCESS, node_id="xxx", data_id="yyy")
                - TaskResult(status=FAILED, node_id="xxx", error="...")
                - TaskResult(status=IN_PROGRESS, node_id="xxx", task_id="...")
                
        示例：
            # JSONL Handler
            async def create_all(self, nodes):
                results = []
                for node in nodes:
                    try:
                        new_id = str(uuid4())
                        data = node.get_data()
                        # ... 存储逻辑 ...
                        results.append(TaskResult.success(
                            node_id=node.node_id,
                            data_id=new_id
                        ))
                    except Exception as e:
                        results.append(TaskResult.failed(
                            node_id=node.node_id,
                            error=str(e)
                        ))
                return results
            
            # API Handler - 查询依赖
            async def create_all(self, nodes):
                results = []
                for node in nodes:
                    # 查询依赖数据（如合同创建时查项目）
                    project_id = node.context.get("project_id")
                    projects = self._collection.filter(
                        node_type="project",
                        node_filter={"data_id": project_id}
                    )
                    
                    if not projects:
                        results.append(TaskResult.failed(
                            node_id=node.node_id,
                            error=f"Project {project_id} not found"
                        ))
                        continue
                    
                    # 构造请求数据
                    data = node.get_data()
                    if not data:
                        results.append(TaskResult.failed(
                            node_id=node.node_id,
                            error="node data is None"
                        ))
                        continue
                    
                    contract_data = {
                        "project_id": projects[0].data_id,
                        **data
                    }
                    
                    # 调用 API
                    response = await self.api.create_contract(contract_data)
                    results.append(TaskResult.success(
                        node_id=node.node_id,
                        data_id=response["id"]
                    ))
                
                return results
        """
        ...
    
    async def update_all(
        self,
        nodes: List["SyncNode"]
    ) -> List[TaskResult]:
        """
        批量更新节点
        
        Args:
            nodes: 需要更新的节点列表（DataSource 已筛选为 UPDATE + PENDING）
            
        Returns:
            List[TaskResult]（同 create_all）
        """
        ...
    
    async def delete_all(
        self,
        nodes: List["SyncNode"]
    ) -> List[TaskResult]:
        """
        批量删除节点
        
        Args:
            nodes: 需要删除的节点列表（DataSource 已筛选为 DELETE + PENDING）
        
        Args:
            collection: Collection 上下文
            
        Returns:
            List[TaskResult]（同 create_all）
        """
        ...
    
    async def poll_tasks(self, task_ids: List[str]) -> Dict[str, TaskResult]:
        """
        批量轮询异步任务状态
        
        Args:
            task_ids: 任务 ID 列表
            
        Returns:
            {task_id: TaskResult} 字典
            - SUCCESS: 任务完成，返回 data_id
            - FAILED: 任务失败，返回 error
            - IN_PROGRESS: 仍在进行中
            
        示例：
            async def poll_tasks(self, task_ids):
                response = await self.api.batch_query_tasks(task_ids)
                results = {}
                for task in response["tasks"]:
                    if task["status"] == "completed":
                        results[task["id"]] = TaskResult.success(
                            data_id=task["result"]["contract_id"]
                        )
                    elif task["status"] == "failed":
                        results[task["id"]] = TaskResult.failed(
                            error=task["error"]
                        )
                    else:  # running
                        results[task["id"]] = TaskResult.in_progress(
                            task_id=task["id"]
                        )
                return results
        """
        ...
    
    async def validate(self, data: Dict[str, Any]) -> ValidationResult:
        """
        数据质量检查
        
        Args:
            data: 原始数据
            
        Returns:
            ValidationResult（是否有效 + 错误列表）
            
        示例：
            async def validate(self, data):
                errors = []
                if not data.get("code"):
                    errors.append("合同编码为空")
                if not data.get("project_id"):
                    errors.append("项目 ID 为空")
                
                return ValidationResult(
                    is_valid=len(errors) == 0,
                    errors=errors
                )
        """
        ...
    
    def extract_id(self, data: Dict[str, Any]) -> str:
        """
        从原始数据提取 ID
        
        Args:
            data: 原始数据
            
        Returns:
            业务主键
        """
        ...
    
    def _create_node(self, data: Dict[str, Any]) -> "SyncNode[T]":
        """
        从原始数据创建 SyncNode
        
        Args:
            data: 原始数据
            
        Returns:
            类型化的 SyncNode
        """
        ...


class BaseNodeHandler(ABC, Generic[T]):
    """
    节点处理器基类
    
    子类需实现：
    - load()
    - create()
    - update()
    - delete()（可选）
    - poll_tasks()（如果支持异步）
    - validate()（可选）
    - extract_id()
    """
    
    def __init__(
        self,
        node_type: str | None = None,
        node_class: Type["SyncNode[T]"] | None = None,
        schema: Type[T] | None = None,
    ):
        self._node_type = node_type or ""
        self._node_class = node_class
        self._schema = schema
        self._collection: Optional["DataCollection"] = None
        self.handler_config: Dict[str, Any] = {}
    
    def set_collection(self, collection: "DataCollection") -> None:
        """
        设置 Collection 引用
        
        Args:
            collection: 数据集合
        """
        self._collection = collection

    def set_handler_config(self, config: Dict[str, Any]) -> None:
        """默认保存 handler 级别配置，供子类按需读取。"""
        self.handler_config = dict(config)

    def get_data_id_filter(self) -> List[str]:
        if "data_id_filter" in self.handler_config:
            value = self.handler_config.get("data_id_filter", [])
            if isinstance(value, str):
                return [value] if value else []
            if isinstance(value, list):
                return [str(item) for item in value if str(item)]
            return []
        if self.node_type != "project" and self._collection is not None:
            return [node.data_id for node in self._collection.filter(node_type="project") if node.data_id]
        return []

    def should_skip_by_data_id_filter(self, item: Dict[str, Any], item_id: str) -> bool:
        data_id_filter = set(self.get_data_id_filter())
        if not data_id_filter:
            return False
        if self.node_type == "project":
            return item_id not in data_id_filter

        project_id = item.get("project_id")
        if project_id:
            return str(project_id) not in data_id_filter
        return False

    def set_api_client(self, client: "ApiClient") -> None:
        """默认忽略 API 客户端注入。"""
        return

    def set_poll_mode(self, mode: str) -> None:
        """默认忽略轮询模式。"""
        return

    def get_update_fields(self, *, exclude: frozenset[str] = frozenset({"id"})) -> List[str]:
        """默认无 post-check 字段白名单。"""
        return []
    
    @property
    def node_type(self) -> str:
        return self._node_type
    
    @property
    def node_class(self) -> Type["SyncNode[T]"]:
        return self._node_class
    
    @property
    def schema(self) -> Type[T]:
        return self._schema
    
    # ========== 必须实现 ==========
    
    @abstractmethod
    async def load(self) -> List['SyncNode']:
        """
        从数据源加载数据并创建节点
        
        Handler 负责：
        1. 加载原始数据
        2. 创建 SyncNode（调用 create_node）
        3. 设置 context（如 project_id, contract_id 等）
        
        Returns:
            SyncNode 列表
        """
        pass
    
    @abstractmethod
    async def create_all(
        self,
        nodes: List["SyncNode"]
    ) -> List[TaskResult]:
        """批量创建节点"""
        pass
    
    @abstractmethod
    async def update_all(
        self,
        nodes: List["SyncNode"]
    ) -> List[TaskResult]:
        """批量更新节点"""
        pass
    
    @abstractmethod
    def extract_id(self, data: Dict[str, Any]) -> str:
        """提取 ID"""
        pass
    
    # ========== 可选实现 ==========
    
    async def delete_all(
        self,
        nodes: List["SyncNode"]
    ) -> List[TaskResult]:
        """批量删除节点（默认不支持）"""
        return [
            TaskResult.failed(node_id=node.node_id, error="Delete operation not supported")
            for node in nodes
        ]
    
    async def poll_tasks(self, task_ids: List[str]) -> Dict[str, TaskResult]:
        """轮询异步任务（默认不支持）"""
        return {
            task_id: TaskResult.failed(error="Async tasks not supported")
            for task_id in task_ids
        }
    
    async def validate(self, data: Dict[str, Any]) -> ValidationResult:
        """数据质量检查（默认不检查）"""
        return ValidationResult(is_valid=True)
    
    def create_node(self, data: Dict[str, Any]) -> "SyncNode[T]":
        """创建或复用 SyncNode（默认实现）"""
        data_id = self.extract_id(data)
        if self._collection is None:
            raise RuntimeError("Collection not set. Call set_collection() before create_node().")

        if data_id:
            existing_node = self._collection.get_by_data_id(self.node_type, data_id)
            if existing_node is not None:
                existing_node.set_data(data.copy())
                existing_node.set_origin_data(data.copy())
                return existing_node

        node_id = self._collection.generate_node_id()

        return self.node_class(
            node_id=node_id,
            data_id=data_id,
            data=data.copy()
        )

    def _create_node(self, data: Dict[str, Any]) -> "SyncNode[T]":
        """兼容 NodeHandler 协议的默认实现"""
        return self.create_node(data)


class NodeHandlerRegistry:
    """节点处理器注册表"""
    
    _handlers: Dict[str, NodeHandler] = {}
    
    @classmethod
    def register(cls, node_type: str, handler: NodeHandler) -> None:
        """注册 handler"""
        cls._handlers[node_type] = handler
    
    @classmethod
    def get(cls, node_type: str) -> NodeHandler:
        """获取 handler"""
        if node_type not in cls._handlers:
            raise KeyError(f"Handler for '{node_type}' not registered")
        return cls._handlers[node_type]
    
    @classmethod
    def has(cls, node_type: str) -> bool:
        """检查是否已注册"""
        return node_type in cls._handlers
    
    @classmethod
    def clear(cls) -> None:
        """清空注册表"""
        cls._handlers.clear()
    
    @classmethod
    def list_handlers(cls) -> List[str]:
        """列出所有已注册的 node_type"""
        return list(cls._handlers.keys())
