"""
Contract API Handler

职责：
- 加载合同列表（依赖 Project）
- 合同创建（POST /contract/create，异步）
- 合同更新（PUT /contract/update，同步）
- 合同删除（DELETE /contract/delete，同步）
"""

from typing import List, Dict, Any, Optional

from ...datasource.api.handler import BaseApiHandler
from ...datasource.task_result import TaskResult
from ...common.sync_node import SyncNode
from ...datasource.api.client import ApiClient
from .sync_node import ContractSyncNode
from schemas.contract.contract import ContractResponse, ContractCreate, ContractUpdate


# ========== 静态 API 函数 ==========

async def api_get_contract_list(client: ApiClient, project_id: str) -> List[ContractResponse]:
    """GET /contract/list - 获取项目合同列表"""
    response = await client.request(
        method="GET",
        endpoint="/contract/list",
        params={"project_id": project_id}
    )
    if response.get("code") != 200:
        raise Exception(f"Failed to get contract list: {response.get('message', 'Unknown error')}")
    
    # V2 API 返回格式：{code: 200, data: [...]}
    items = response.get("data", [])
    
    return [ContractResponse.model_validate(item) for item in items]


async def api_get_contract(client: ApiClient, contract_id: str) -> ContractResponse:
    """GET /contract - 获取合同详情"""
    response = await client.request(
        method="GET",
        endpoint="/contract",
        params={"contract_id": contract_id}
    )
    if response.get("code") != 200:
        raise Exception(f"Failed to get contract: {response.get('message', 'Unknown error')}")
    return ContractResponse.model_validate(response["data"])


async def api_create_contract(
    client: ApiClient,
    data: Dict[str, Any],
    push_id: str,
    *,
    steps: List[Dict[str, Any]] | None = None,
) -> Dict[str, Any]:
    """POST /contract/create - 创建合同（异步）"""
    validated_data = ContractCreate.model_validate(data)
    request_data = {"push_id": push_id, "data": validated_data.model_dump(exclude_none=True), "steps": steps or []}
    response = await client.request("POST", "/contract/create", data=request_data)
    if response.get("code") != 200:
        raise Exception(f"Failed to create contract: {response.get('message', 'Unknown error')}")
    return response


async def api_update_contract(
    client: ApiClient,
    data_id: str,
    data: Dict[str, Any],
    push_id: str,
    *,
    steps: List[Dict[str, Any]] | None = None,
) -> Dict[str, Any]:
    """PUT /contract/update - 更新合同（同步）"""
    validated_data = ContractUpdate.model_validate(data)
    request_data = {
        "push_id": push_id,
        "biz_id": data_id,
        "data": validated_data.model_dump(exclude_none=True),
        "steps": steps or [],
    }
    response = await client.request("PUT", "/contract/update", data=request_data)
    if response.get("code") != 200:
        raise Exception(f"Failed to update contract: {response.get('message', 'Unknown error')}")
    return response


async def api_delete_contract(client: ApiClient, data_id: str, push_id: str) -> Dict[str, Any]:
    """DELETE /contract/delete - 删除合同（同步）"""
    request_data = {"push_id": push_id, "biz_id": data_id}
    response = await client.request("DELETE", "/contract/delete", data=request_data)
    if response.get("code") != 200:
        raise Exception(f"Failed to delete contract: {response.get('message', 'Unknown error')}")
    return response


# ========== Handler ==========

class ContractApiHandler(BaseApiHandler):
    """合同 API Handler"""
    
    def __init__(self):
        super().__init__()
        self._node_type = "contract"
        self._node_class = ContractSyncNode
        self._schema = ContractResponse
        self.update_schemas = [ContractCreate, ContractUpdate]
    
    # ========== Handler 接口实现 ==========
    
    async def load(self) -> List[SyncNode]:
        """
        加载合同列表
        
        依赖 Project：从 collection 获取项目列表，然后加载这些项目的合同
        
        Returns:
            合同数据列表
        """
        try:
            # 从 collection 获取项目列表
            projects = self._collection.filter(node_type="project")
            project_ids = [p.data_id for p in projects if p.data_id]
            
            if not project_ids:
                print("⚠️  No projects found, skipping contract load")
                return []
            
            # 为每个项目加载合同
            all_nodes = []
            for project_id in project_ids:
                try:
                    contracts = await api_get_contract_list(self.api_client, project_id)
                    
                    # 已验证的 Pydantic model，转换为 dict 并创建 node
                    for contract in contracts:
                        contract_data = contract.model_dump()
                        all_nodes.append(self._create_node(contract_data))
                
                except Exception as e:
                    print(f"❌ Failed to load contracts for project {project_id}: {e}")
                    continue
            
            return all_nodes
        
        except Exception as e:
            print(f"❌ Failed to load contracts: {e}")
            return []
    
    async def create_all(self, nodes: List[SyncNode]) -> List[TaskResult]:
        """批量创建合同"""
        results = []
        for node in nodes:
            result = await self._create_single(node)
            results.append(result)
        return results
    
    async def update_all(self, nodes: List[SyncNode]) -> List[TaskResult]:
        """批量更新合同"""
        results = []
        for node in nodes:
            result = await self._update_single(node)
            results.append(result)
        return results
    
    async def delete_all(self, nodes: List[SyncNode]) -> List[TaskResult]:
        """批量删除合同"""
        results = []
        for node in nodes:
            result = await self._delete_single(node)
            results.append(result)
        return results
    
    async def poll_tasks(self, task_ids: List[str]) -> Dict[str, TaskResult]:
        """轮询异步任务状态"""
        return await super().poll_tasks(task_ids)
    
    async def _create_single(self, node: SyncNode) -> TaskResult:
        """
        创建合同（异步）
        
        Args:
            node: 同步节点
            
        Returns:
            TaskResult (IN_PROGRESS with push_id)
        """
        push_id: str | None = None
        try:
            # 获取数据
            data = node.get_data()
            if not data:
                return TaskResult.failed(node_id=node.node_id, error="Node data is None or validation failed")
            
            # 从 context 获取 project_id
            project_id = node.context.get("project_id")
            if not project_id:
                project_id = data.get("project_id")
            
            if not project_id:
                return TaskResult.failed(
                    node_id=node.node_id,
                    error="project_id not found in context or data"
                )
            
            # 构建请求数据（确保包含 project_id）
            request_data = {
                "project_id": project_id,
                **data
            }
            
            # 调用 API（直接调用顶层函数）
            push_id = self._generate_push_id()
            response = await api_create_contract(
                self.api_client,
                request_data,
                push_id,
                steps=self._get_request_steps(node),
            )
            if self.poll_mode == "sync":
                created_id = self._extract_created_id_from_response(response)
                if not created_id:
                    return TaskResult.failed(
                        node_id=node.node_id,
                        error="Missing created_id in create response"
                    )
                return TaskResult.success(node_id=node.node_id, data_id=created_id)
            else:
                return TaskResult.in_progress(node_id=node.node_id, task_id=push_id)
        
        except Exception as e:
            return TaskResult.failed(
                node_id=node.node_id,
                error=f"Create failed: {str(e)}",
                push_id=push_id,
            )
    
    async def _update_single(self, node: SyncNode) -> TaskResult:
        """
        更新合同（同步）
        
        自动选择需要更新的字段（基于 update_schema）
        
        Args:
            node: 同步节点
            
        Returns:
            TaskResult (SUCCESS or FAILED)
        """
        try:
            data = node.get_data()
            if not data:
                return TaskResult.failed(node_id=node.node_id, error="Missing data for update")

            # 过滤出需要更新的字段（排除空值、未变化的字段）
            origin_data = node.get_origin_data() or {}
            force_steps_update = self._steps_changed(node)
            update_data = self._filter_update_data(
                new_data=data,
                original_data=origin_data,
                schema=ContractUpdate,
                force_full_schema=force_steps_update,
            )
            
            # 如果没有需要更新的字段，降级 action 并返回跳过
            if not update_data:
                return TaskResult.skipped(node_id=node.node_id, reason="No updatable fields changed")
            
            # Schema 验证
            error = self._validate_schema(update_data, ContractUpdate)
            if error:
                return TaskResult.failed(
                    node_id=node.node_id,
                    error=f"Schema validation failed: {error}"
                )
            
            # 生成 push_id 和 biz_id
            push_id = self._generate_push_id()
            biz_id = node.data_id or update_data.get("id")
            if not biz_id:
                return TaskResult.failed(node_id=node.node_id, error="Missing biz_id for update")
            
            # 调用 API
            response = await api_update_contract(
                self.api_client,
                biz_id,
                update_data,
                push_id,
                steps=self._get_request_steps(node),
            )
            
            # 检查响应状态（更新接口是同步的）
            if response.get("code") == 200:
                self._mark_approval_snapshot_synced(node)
                return TaskResult.success(node_id=node.node_id)
            else:
                return TaskResult.failed(
                    node_id=node.node_id,
                    error=f"API returned error: {response.get('message', 'Unknown error')}"
                )
        
        except Exception as e:
            return TaskResult.failed(
                node_id=node.node_id,
                error=f"Update failed: {str(e)}"
            )
    
    async def _delete_single(self, node: SyncNode) -> TaskResult:
        """
        删除合同（同步）
        
        Args:
            node: 同步节点
            
        Returns:
            TaskResult (SUCCESS or FAILED)
        """
        if not self.api_client:
            return TaskResult.failed(
                node_id=node.node_id,
                error="api_client not initialized"
            )
        
        try:
            # 生成 push_id 和 biz_id
            push_id = self._generate_push_id()
            biz_id = node.data_id
            if not biz_id:
                return TaskResult.failed(node_id=node.node_id, error="Missing biz_id for delete")
            
            # 调用 API
            response = await api_delete_contract(self.api_client, biz_id, push_id)
            
            # 检查响应状态
            if response.get("code") == 200:
                return TaskResult.success(node_id=node.node_id)
            else:
                return TaskResult.failed(
                    node_id=node.node_id,
                    error=f"API returned error: {response.get('message', 'Unknown error')}"
                )
        
        except Exception as e:
            return TaskResult.failed(
                node_id=node.node_id,
                error=f"Delete failed: {str(e)}"
            )
    
    # ========== 辅助方法 ==========
    
    def _create_node(self, data: Dict[str, Any]) -> SyncNode:
        """创建合同同步节点（设置 project_id 到 context）"""
        node = self._create_basic_node(data, depend_ids=[])
        
        # 设置 project_id 到 context（供子节点使用）
        if data.get("project_id"):
            node.context["project_id"] = data["project_id"]
        
        return node

