#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：erp_task_client.py
模块描述：ERP 任务 API 客户端，封装任务类型/状态/人员/需求/任务创建接口
          含缓存和重试机制，参考实现：ApiSecurityTest/utils/erp_client.py

作者：czj
创建日期：2026-08-17
最后修改：2026-08-17
"""

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

import requests

logger = logging.getLogger(__name__)


# API 端点常量
TASK_TYPE_ENDPOINT = "/openclaw/tasktype"
TASK_STATUS_ENDPOINT = "/openclaw/taskstatus"
STAFF_ENDPOINT = "/openclaw/stuff"
DEVELOP_ENDPOINT = "/openclaw/develop"
TASK_ENDPOINT = "/openclaw/task"


class ERPTaskClient:
    """
    ERP 任务 API 客户端

    缓存策略：
    - 任务类型、任务状态、人员列表缓存 1 小时
    - 需求列表、任务创建不缓存
    """

    def __init__(
        self,
        base_url: str,
        api_key: str,
        timeout: int = 30,
        max_retries: int = 3,
        retry_interval: int = 2,
        cache_duration: int = 3600,
    ):
        """
        Args:
            base_url: ERP 基础 URL（如 https://office.ubainsyun.com:5082/api/uerp）
            api_key: ERP API 密钥
            timeout: 请求超时时间（秒）
            max_retries: 最大重试次数
            retry_interval: 重试间隔（秒）
            cache_duration: 基础数据缓存时长（秒）
        """
        self.base_url = base_url.rstrip("/")
        self.api_key = api_key
        self.timeout = timeout
        self.max_retries = max_retries
        self.retry_interval = retry_interval
        self.cache_duration = cache_duration

        # 缓存
        self._cache: Dict[str, Any] = {}
        self._cache_timestamps: Dict[str, float] = {}

    # ==================== 公开 API ====================

    def get_task_types(self) -> Optional[List[Dict]]:
        """
        获取任务类型列表

        Returns:
            [{"id": 1, "name": "UI设计"}, ...]，失败返回 None
        """
        result = self._get_with_cache("task_types", lambda: self._make_request("GET", TASK_TYPE_ENDPOINT))
        if result and isinstance(result, dict) and "data" in result:
            return result["data"]
        return result

    def get_task_statuses(self) -> Optional[List[Dict]]:
        """
        获取任务状态列表

        Returns:
            [{"id": 1, "name": "新建"}, ...]，失败返回 None
        """
        result = self._get_with_cache("task_statuses", lambda: self._make_request("GET", TASK_STATUS_ENDPOINT))
        if result and isinstance(result, dict) and "data" in result:
            return result["data"]
        return result

    def get_staff_list(self) -> Optional[List[Dict]]:
        """
        获取人员列表

        Returns:
            [{"id": 1, "name": "超管员", ...}, ...]，失败返回 None
        """
        result = self._get_with_cache("staff_list", lambda: self._make_request("GET", STAFF_ENDPOINT))
        if result and isinstance(result, dict) and "data" in result:
            return result["data"]
        return result

    def search_develop(
        self,
        search_str: str,
        page_num: int = 1,
        page_size: int = 10,
    ) -> Optional[List[Dict]]:
        """
        搜索需求列表

        Args:
            search_str: 搜索关键词
            page_num: 页码
            page_size: 每页数量

        Returns:
            需求列表，格式 [{"id": 128, "name": "需求名称", ...}, ...]
            失败返回 None
        """
        params = {"pageNum": page_num, "pageSize": page_size}
        if search_str:
            params["search_str"] = search_str

        result = self._make_request("GET", DEVELOP_ENDPOINT, params=params)
        if result is None:
            return None

        # 响应可能是 dict 带 data 字段，也可能是直接列表
        if isinstance(result, dict) and "data" in result:
            data = result["data"]
            if isinstance(data, list):
                return data
        elif isinstance(result, list):
            return result

        return None

    def create_task(self, task_data: Dict) -> Optional[Dict]:
        """
        创建 ERP 任务

        Args:
            task_data: 任务数据字典

        Returns:
            ERP 响应结果，失败返回 None
        """
        return self._make_request("POST", TASK_ENDPOINT, json=task_data)

    def clear_cache(self):
        """清空所有缓存"""
        self._cache.clear()
        self._cache_timestamps.clear()
        logger.info("ERP 任务客户端缓存已清空")

    # ==================== 内部方法 ====================

    def _get_with_cache(self, cache_key: str, fetch_func) -> Optional[Any]:
        """
        带缓存的数据获取

        Args:
            cache_key: 缓存键名
            fetch_func: 获取数据的函数

        Returns:
            缓存或新获取的数据
        """
        now = time.time()
        if cache_key in self._cache:
            timestamp = self._cache_timestamps.get(cache_key, 0)
            if now - timestamp < self.cache_duration:
                logger.debug(f"使用缓存数据: {cache_key}")
                return self._cache[cache_key]

        data = fetch_func()
        if data is not None:
            self._cache[cache_key] = data
            self._cache_timestamps[cache_key] = now

        return data

    def _make_request(
        self,
        method: str,
        endpoint: str,
        **kwargs,
    ) -> Optional[Dict]:
        """
        统一请求方法（含重试机制）

        Args:
            method: HTTP 方法（GET/POST）
            endpoint: API 端点路径
            **kwargs: 其他请求参数（params, json 等）

        Returns:
            响应数据字典，失败返回 None
        """
        url = f"{self.base_url}{endpoint}"
        headers = {"X-Api-Key": self.api_key, "Content-Type": "application/json"}

        # 分离参数
        json_data = kwargs.pop("json", None)
        params = kwargs.pop("params", None)

        for attempt in range(self.max_retries):
            try:
                logger.info(f"ERP API 请求: {method} {endpoint}")

                if method == "GET":
                    response = requests.get(
                        url, headers=headers, params=params, timeout=self.timeout
                    )
                elif method == "POST":
                    request_kwargs = {}
                    if json_data:
                        request_kwargs["json"] = json_data
                    if params:
                        request_kwargs["params"] = params
                    response = requests.post(
                        url, headers=headers, timeout=self.timeout, **request_kwargs
                    )
                else:
                    logger.error(f"不支持的 HTTP 方法: {method}")
                    return None

                if response.status_code == 200:
                    result = response.json()

                    if result.get("success") == 1:
                        logger.info(f"✓ ERP API 请求成功: {endpoint}")
                        return result
                    else:
                        error_code = result.get("error", 0)
                        msg = result.get("msg", "未知错误")
                        if 400 <= error_code < 500:
                            logger.error(f"✗ ERP API 客户端错误 ({error_code}): {msg}")
                            return None
                        if attempt < self.max_retries - 1:
                            logger.warning(
                                f"ERP API 服务端错误，{self.retry_interval}s 后重试 ({attempt+1}/{self.max_retries}): {msg}"
                            )
                            time.sleep(self.retry_interval)
                        else:
                            logger.error(f"✗ ERP API 请求失败 (已达最大重试次数): {msg}")
                            return None
                else:
                    if attempt < self.max_retries - 1 and response.status_code >= 500:
                        logger.warning(
                            f"ERP API HTTP {response.status_code}，{self.retry_interval}s 后重试 ({attempt+1}/{self.max_retries})"
                        )
                        time.sleep(self.retry_interval)
                    else:
                        logger.error(f"✗ ERP API HTTP 错误: {response.status_code}")
                        return None

            except requests.exceptions.Timeout:
                if attempt < self.max_retries - 1:
                    logger.warning(
                        f"ERP API 请求超时，{self.retry_interval}s 后重试 ({attempt+1}/{self.max_retries})"
                    )
                    time.sleep(self.retry_interval)
                else:
                    logger.error("✗ ERP API 请求超时 (已达最大重试次数)")
                    return None

            except requests.exceptions.RequestException as e:
                logger.error(f"✗ ERP API 请求异常: {e}")
                return None

            except Exception as e:
                logger.error(f"✗ ERP API 未知异常: {e}")
                return None

        return None