# ========== api_client.py ==========
# utils/api_client.py - OpenAI-compatible API 客户端（支持Web模式）

import httpx
import json
import asyncio
import base64
import mimetypes
import os
from typing import List, Dict, Optional, AsyncGenerator, Any
from pathlib import Path
from datetime import datetime
from pathlib import Path
from typing import Tuple
try:
    from config import (
        OUTPUT_FORMATS,
        DEFAULT_RESPONSE_MAX_TOKENS,
        LOGS_DIR,
    )
except ImportError:
    import sys
    from pathlib import Path
    project_root = Path(__file__).resolve().parents[1]
    if str(project_root) not in sys.path:
        sys.path.insert(0, str(project_root))
    from config import (
        OUTPUT_FORMATS,
        DEFAULT_RESPONSE_MAX_TOKENS,
        LOGS_DIR,
    )

from utils.log_rotation import append_line, prune_dir



from utils.api_client.utils import _api_dump_enabled

class DeepSeekClientToolMixin:
    def _validate_json_string(self, json_str: str) -> tuple:
        """
        验证JSON字符串的完整性
        
        Returns:
            (is_valid: bool, error_message: str, parsed_data: dict or None)
        """
        if not json_str or not json_str.strip():
            return True, "", {}
        
        # 检查基本的JSON结构标记
        stripped = json_str.strip()
        if not stripped.startswith('{') or not stripped.endswith('}'):
            return False, "JSON字符串格式不完整（缺少开始或结束大括号）", None
        
        # 检查引号配对
        in_string = False
        escape_next = False
        quote_count = 0
        
        for char in stripped:
            if escape_next:
                escape_next = False
                continue
            
            if char == '\\':
                escape_next = True
                continue
                
            if char == '"':
                quote_count += 1
                in_string = not in_string
        
        if in_string:
            return False, "JSON字符串中存在未闭合的引号", None
        
        # 尝试解析JSON
        try:
            parsed_data = json.loads(stripped)
            return True, "", parsed_data
        except json.JSONDecodeError as e:
            return False, f"JSON解析错误: {str(e)}", None

    def _safe_tool_arguments_parse(self, arguments_str: str, tool_name: str) -> tuple:
        """
        安全地解析工具参数，保持失败即时返回
        
        Returns:
            (success: bool, arguments: dict, error_message: str)
        """
        if not arguments_str or not arguments_str.strip():
            return True, {}, ""
        
        # 长度检查
        max_length = 999999999  # 50KB限制
        if len(arguments_str) > max_length:
            return False, {}, f"参数过长({len(arguments_str)}字符)，超过{max_length}字符限制"
        
        # 尝试直接解析JSON
        try:
            parsed_data = json.loads(arguments_str)
            return True, parsed_data, ""
        except json.JSONDecodeError as e:
            preview_length = 200
            stripped = arguments_str.strip()
            preview = stripped[:preview_length] + "..." if len(stripped) > preview_length else stripped
            return False, {}, f"JSON解析失败: {str(e)}\n参数预览: {preview}"

    def _extract_reasoning_delta(self, delta: Dict[str, Any]) -> str:
        """统一提取思考内容，兼容 reasoning_content / reasoning_details。"""
        if not isinstance(delta, dict):
            return ""
        if "reasoning_content" in delta:
            return delta.get("reasoning_content") or ""
        details = delta.get("reasoning_details")
        if isinstance(details, list):
            parts: List[str] = []
            for item in details:
                if isinstance(item, dict):
                    text = item.get("text")
                    if text:
                        parts.append(text)
            if parts:
                return "".join(parts)
        return ""
