"""
工作流API调用客户端
用于调用工作流管理和执行接口
"""

import httpx
import json
import os
import time
from typing import Dict, Any, Optional, List, Tuple

try:
    from .env_config import get_backend_base_url, get_workflow_execute_key
    from .logger_config import get_logger
except ImportError:
    from env_config import get_backend_base_url, get_workflow_execute_key
    from logger_config import get_logger

logger = get_logger(__name__)

# 默认超时配置（秒）
DEFAULT_TIMEOUT = 30.0  # 普通请求超时
WORKFLOW_EXECUTE_TIMEOUT = 600.0  # 工作流执行超时（10分钟，参考 workflow-execution-api.md）

# 异步轮询默认配置（参考 workflow-execution-api.md）
DEFAULT_POLLING_INTERVAL = 1.0
DEFAULT_MAX_POLL_COUNT = 120
DEFAULT_MAX_ERROR_COUNT = 3


def _get_polling_config() -> Tuple[float, int, int]:
    """
    获取轮询配置（允许用环境变量覆盖）

    Env:
      - workflowPollingIntervalSeconds: float, 默认 1
      - workflowMaxPollCount: int, 默认 120
      - workflowMaxErrorCount: int, 默认 3
    """
    try:
        interval = float(os.environ.get("workflowPollingIntervalSeconds", str(DEFAULT_POLLING_INTERVAL)))
    except ValueError:
        interval = DEFAULT_POLLING_INTERVAL

    try:
        max_polls = int(os.environ.get("workflowMaxPollCount", str(DEFAULT_MAX_POLL_COUNT)))
    except ValueError:
        max_polls = DEFAULT_MAX_POLL_COUNT

    try:
        max_errors = int(os.environ.get("workflowMaxErrorCount", str(DEFAULT_MAX_ERROR_COUNT)))
    except ValueError:
        max_errors = DEFAULT_MAX_ERROR_COUNT

    # 避免被错误配置成 0 或负数
    interval = interval if interval > 0 else DEFAULT_POLLING_INTERVAL
    max_polls = max_polls if max_polls > 0 else DEFAULT_MAX_POLL_COUNT
    max_errors = max_errors if max_errors > 0 else DEFAULT_MAX_ERROR_COUNT

    return interval, max_polls, max_errors


def _extract_async_ids(execute_response: Dict[str, Any]) -> Optional[Tuple[str, str, str]]:
    """
    从执行接口响应中提取 (status, execution_id, workflow_id)
    兼容 snake_case / camelCase。
    """
    if not isinstance(execute_response, dict):
        return None
    data = execute_response.get("data")
    if not isinstance(data, dict):
        return None

    status = data.get("status")
    execution_id = data.get("execution_id") or data.get("executionId")
    workflow_id = data.get("workflow_id") or data.get("workflowId")

    if status and execution_id and workflow_id:
        return str(status), str(execution_id), str(workflow_id)
    return None


class WorkflowAPIClient:
    """工作流API客户端"""
    
    def __init__(
        self, 
        base_url: Optional[str] = None,
        token: Optional[str] = None,
        default_timeout: float = DEFAULT_TIMEOUT,
        execute_timeout: float = WORKFLOW_EXECUTE_TIMEOUT
    ):
        """
        初始化API客户端
        
        Args:
            base_url: API基础URL（默认从环境变量 backendBaseUrl 读取）
            token: 认证令牌（默认从环境变量 workflowExecuteKey 读取）
            default_timeout: 普通请求超时时间（秒），默认30秒
            execute_timeout: 工作流执行超时时间（秒），默认300秒（5分钟）
        """
        if base_url is None:
            base_url = get_backend_base_url()
        
        if token is None:
            token = get_workflow_execute_key()
        
        self.base_url = base_url.rstrip('/')
        self.token = token
        self.default_timeout = default_timeout
        self.execute_timeout = execute_timeout
        self._client: Optional[httpx.Client] = None
        
        # 打印完整的配置信息用于调试
        logger.info(f"[客户端初始化] base_url={self.base_url}")
        logger.info(f"[客户端初始化] token={self.token}")
        logger.info(f"[客户端初始化] execute_timeout={self.execute_timeout}s")
    
    @property
    def client(self) -> httpx.Client:
        """懒加载 HTTP 客户端"""
        if self._client is None:
            self._client = httpx.Client(timeout=self.default_timeout)
        return self._client
        
    def _get_headers(self) -> Dict[str, str]:
        """获取请求头"""
        return {
            'X-API-Key': f'{self.token}',
        }
    
    def get_workflow_by_id(self, workflow_id: str) -> Dict[str, Any]:
        """
        根据工作流ID获取工作流信息
        
        Args:
            workflow_id: 工作流ID
            
        Returns:
            API响应数据
            
        Raises:
            Exception: 请求失败时抛出
        """
        url = f"{self.base_url}/system/workflowManage/getByWorkflowId/{workflow_id}"
        
        try:
            logger.info(f"[API请求] GET {url}")
            logger.debug(f"[API请求] Headers: {self._get_headers()}")
            
            response = self.client.get(
                url,
                headers=self._get_headers()
            )
            
            logger.info(f"[API响应] HTTP {response.status_code}")
            logger.debug(f"[API响应] Headers: {dict(response.headers)}")
            
            response.raise_for_status()
            data = response.json()
            
            logger.info(f"[API响应] 获取工作流配置成功: workflow_id={workflow_id}")
            logger.debug(f"[API响应] Body: {json.dumps(data, ensure_ascii=False, indent=2)}")
            
            return data
            
        except httpx.TimeoutException:
            error_msg = f"API请求超时: {url}"
            logger.error(f"[API错误] {error_msg}")
            raise Exception(error_msg)

        except httpx.HTTPStatusError as e:
            error_msg = f"API请求失败 (HTTP {e.response.status_code}): {url}"
            logger.error(f"[API错误] {error_msg}")
            logger.error(f"[API错误] 响应内容: {e.response.text}")
            raise Exception(error_msg)
            
        except httpx.RequestError as e:
            error_msg = f"API请求异常: {url}, 错误: {str(e)}"
            logger.error(f"[API错误] {error_msg}")
            raise Exception(error_msg)
            
        except Exception as e:
            error_msg = f"处理API响应时出错: {str(e)}"
            logger.error(f"[API错误] {error_msg}", exc_info=True)
            raise Exception(error_msg)
    
    def execute_workflow(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        执行工作流
        
        Args:
            request_data: 请求数据，包含工作流执行所需的参数
                
        Returns:
            API响应数据
            
        Raises:
            Exception: 请求失败时抛出
        """
        url = f"{self.base_url}/open/workflow/execute"
        
        try:
            headers = self._get_headers()
            headers['Content-Type'] = 'application/json'
            headers['Accept'] = '*/*'
            
            # 打印完整的请求信息
            logger.info(f"[执行工作流] URL: {url}")
            logger.info(f"[执行工作流] Token: {self.token}")
            logger.info(f"[执行工作流] Headers: {json.dumps(headers, ensure_ascii=False)}")
            logger.info(f"[执行工作流] 请求参数: {json.dumps(request_data, ensure_ascii=False, indent=2)}")
            logger.info(f"[执行工作流] 超时时间: {self.execute_timeout}s")
            
            # 使用更长的超时时间执行工作流
            response = self.client.post(
                url,
                headers=headers,
                json=request_data,
                timeout=self.execute_timeout  # 使用工作流执行专用超时时间
            )
            
            logger.info(f"[API响应] HTTP {response.status_code}")
            logger.debug(f"[API响应] Headers: {dict(response.headers)}")
            
            response.raise_for_status()
            data = response.json()
            
            logger.info(f"[API响应] 执行工作流成功")
            logger.debug(f"[API响应] Body: {json.dumps(data, ensure_ascii=False, indent=2)}")
            
            # 兼容：如果服务端返回 async 的 execution_id/workflow_id，则按文档轮询状态接口直到结束
            async_info = _extract_async_ids(data)
            if async_info is None:
                return data

            status, execution_id, workflow_id = async_info
            if status not in ("pending", "running"):
                # 有些服务端可能直接返回 success/failed 但仍带 execution_id
                return data

            logger.info(
                f"[执行工作流] 检测到异步执行: status={status}, execution_id={execution_id}, workflow_id={workflow_id}"
            )
            return self.poll_workflow_result(execution_id=execution_id, workflow_id=workflow_id)
            
        except httpx.TimeoutException:
            error_msg = f"执行工作流API请求超时: {url}"
            logger.error(f"[API错误] {error_msg}")
            raise Exception(error_msg)
            
        except httpx.HTTPStatusError as e:
            error_msg = f"执行工作流API请求失败 (HTTP {e.response.status_code}): {url}"
            logger.error(f"[API错误] {error_msg}")
            logger.error(f"[API错误] 响应内容: {e.response.text}")
            raise Exception(error_msg)
            
        except httpx.RequestError as e:
            error_msg = f"执行工作流API请求异常: {url}, 错误: {str(e)}"
            logger.error(f"[API错误] {error_msg}")
            raise Exception(error_msg)
            
        except Exception as e:
            error_msg = f"处理执行工作流API响应时出错: {str(e)}"
            logger.error(f"[API错误] {error_msg}", exc_info=True)
            raise Exception(error_msg)
    
    def get_workflow_execute_status(self, execution_id: str, workflow_id: str) -> Dict[str, Any]:
        """
        查询异步执行状态

        GET /open/workflow/execute/status/{executionId}?workflowId={workflowId}
        """
        url = f"{self.base_url}/open/workflow/status/{execution_id}"
        try:
            logger.info(f"[API请求] GET {url}")
            response = self.client.get(
                url,
                headers=self._get_headers(),
                params={"workflowId": workflow_id},
            )
            logger.info(f"[API响应] HTTP {response.status_code}")
            response.raise_for_status()
            data = response.json()
            logger.debug(f"[API响应] Body: {json.dumps(data, ensure_ascii=False, indent=2)}")
            return data
        except httpx.TimeoutException:
            error_msg = f"查询工作流执行状态超时: {url}"
            logger.error(f"[API错误] {error_msg}")
            raise Exception(error_msg)
        except httpx.HTTPStatusError as e:
            error_msg = f"查询工作流执行状态失败 (HTTP {e.response.status_code}): {url}"
            logger.error(f"[API错误] {error_msg}")
            logger.error(f"[API错误] 响应内容: {e.response.text}")
            raise Exception(error_msg)
        except httpx.RequestError as e:
            error_msg = f"查询工作流执行状态请求异常: {url}, 错误: {str(e)}"
            logger.error(f"[API错误] {error_msg}")
            raise Exception(error_msg)
        except Exception as e:
            error_msg = f"处理查询执行状态响应时出错: {str(e)}"
            logger.error(f"[API错误] {error_msg}", exc_info=True)
            raise Exception(error_msg)

    def poll_workflow_result(self, execution_id: str, workflow_id: str) -> Dict[str, Any]:
        """轮询直到工作流执行完成（success/failed）或超时"""
        interval, max_polls, max_errors = _get_polling_config()
        error_count = 0

        logger.info(
            f"[轮询] 开始轮询执行状态: execution_id={execution_id}, workflow_id={workflow_id}, "
            f"interval={interval}s, max_polls={max_polls}, max_errors={max_errors}"
        )

        for i in range(max_polls):
            try:
                resp = self.get_workflow_execute_status(execution_id=execution_id, workflow_id=workflow_id)
                if resp.get("code") != 200:
                    error_count += 1
                    logger.warning(f"[轮询] 状态接口返回非200(code={resp.get('code')}), error_count={error_count}")
                    if error_count >= max_errors:
                        raise Exception(f"轮询连续错误次数过多: code={resp.get('code')}, msg={resp.get('msg')}")
                    time.sleep(interval)
                    continue

                error_count = 0
                data = resp.get("data") or {}
                status = data.get("status")

                logger.info(f"[轮询] 第{i+1}/{max_polls}次: status={status}")

                if status in ("pending", "running"):
                    time.sleep(interval)
                    continue
                if status in ("success", "failed"):
                    return resp

                # 兜底：未知状态
                raise Exception(f"未知执行状态: {status}")

            except Exception as e:
                error_count += 1
                logger.warning(f"[轮询] 轮询异常: {e}, error_count={error_count}")
                if error_count >= max_errors:
                    raise
                time.sleep(interval)

        raise Exception("轮询超时：超过最大轮询次数仍未完成")

    def close(self):
        """关闭HTTP客户端"""
        if self._client is not None:
            self._client.close()
            self._client = None
    
    def __enter__(self):
        """支持 context manager"""
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """退出时关闭客户端"""
        self.close()
        return False


# 懒加载的默认客户端
_default_client: Optional[WorkflowAPIClient] = None


def get_default_client() -> WorkflowAPIClient:
    """获取默认客户端（懒加载）"""
    global _default_client
    if _default_client is None:
        _default_client = WorkflowAPIClient()
    return _default_client


def get_workflow_by_id(workflow_id: str, base_url: Optional[str] = None, token: Optional[str] = None) -> Dict[str, Any]:
    """
    便捷函数：根据工作流ID获取工作流信息
    
    Args:
        workflow_id: 工作流ID
        base_url: API基础URL（可选）
        token: 认证令牌（可选）
        
    Returns:
        API响应数据
    """
    if base_url or token:
        with WorkflowAPIClient(base_url=base_url, token=token) as client:
            return client.get_workflow_by_id(workflow_id)
    else:
        return get_default_client().get_workflow_by_id(workflow_id)


def execute_workflow(
    request_data: Dict[str, Any], 
    base_url: Optional[str] = None, 
    token: Optional[str] = None,
    timeout: float = WORKFLOW_EXECUTE_TIMEOUT
) -> Dict[str, Any]:
    """
    便捷函数：执行工作流
    
    Args:
        request_data: 请求数据
        base_url: API基础URL（可选）
        token: 认证令牌（可选）
        timeout: 超时时间（秒），默认300秒（5分钟）
        
    Returns:
        API响应数据
    """
    if base_url or token:
        with WorkflowAPIClient(base_url=base_url, token=token, execute_timeout=timeout) as client:
            return client.execute_workflow(request_data)
    else:
        # 更新默认客户端的超时时间
        default_client = get_default_client()
        default_client.execute_timeout = timeout
        return default_client.execute_workflow(request_data)


def extract_final_output(response: Dict[str, Any]) -> Dict[str, Any]:
    """
    提取工作流执行结果中 final_output 的最后一个属性的所有值
    
    Args:
        response: execute_workflow 返回的响应数据
        
    Returns:
        final_output 中最后一个节点的输出值
    """
    try:
        # 获取 data.final_output
        data = response.get("data", {})
        final_output = data.get("final_output", {})
        
        if not final_output:
            logger.warning("final_output 为空")
            return {}
        
        # 获取最后一个 key 的值
        last_key = list(final_output.keys())[-1]
        result = final_output[last_key]
        
        logger.info(f"提取 final_output 最后节点成功: key={last_key}")
        logger.debug(f"提取结果: {json.dumps(result, ensure_ascii=False)}")
        
        return result
        
    except Exception as e:
        logger.error(f"提取 final_output 失败: {e}", exc_info=True)
        return {}


def process_workflow_response(response: Dict[str, Any]) -> List[Dict[str, Any]]:
    """
    处理API响应数据，映射为工作流配置格式
    
    Args:
        response: API原始响应数据
        
    Returns:
        处理后的工作流配置列表
    """
    try:
        data_list = response.get("data", [])
        
        # 如果 data 是单个对象而不是列表，转换为列表
        if isinstance(data_list, dict):
            data_list = [data_list]
        
        workflows = []
        for workflow in data_list:
            # 解析 inputParams 字符串为 JSON 对象
            input_params = workflow.get("inputParams", {})
            if isinstance(input_params, str):
                try:
                    input_params = json.loads(input_params)
                except json.JSONDecodeError:
                    input_params = {}
            
            # 映射字段
            config = {
                "id": workflow.get("id"),
                "workflowId": workflow.get("workflowId"),
                "workflowName": workflow.get("workflowName") or workflow.get("name"),
                "workflowDescription": workflow.get("workflowDescription") or workflow.get("description"),
                "inputParams": input_params
            }
            workflows.append(config)
        
        logger.info(f"成功处理 {len(workflows)} 条工作流数据")
        return workflows
        
    except Exception as e:
        logger.error(f"处理API响应数据失败: {e}", exc_info=True)
        raise
