"""Provide service-layer logic for deepseek client.

P0-0: ``chat()`` now accepts an optional ``tools`` list and parses ``tool_calls``
from the model response so that callers can dispatch tool invocations.
"""

import time
from typing import List, Dict, Optional
from loguru import logger
import httpx

from .base_client import BaseLLMClient, LLMResponse, LLMConfig, LLMProvider
from .tool_types import Tool, ToolCall
# Keep provider-specific behavior explicit so debugging stays straightforward.



class DeepSeekClient(BaseLLMClient):
    """Represent the Deep Seek Client type."""

    SUPPORTED_MODELS = [
        "deepseek-chat",
        "deepseek-coder",
        "deepseek-reasoner",
        "deepseek-v3",
        "deepseek-v3.2",
        "deepseek-v4-flash"
    ]

    def __init__(self, config: LLMConfig):
        """Initialize the Deep Seek Client instance."""
        if config.provider != LLMProvider.DEEPSEEK:
            raise ValueError(f"配置provider应为DEEPSEEK，实际为{config.provider}")
        super().__init__(config)
        self._init_client()

    def _init_client(self):
        """Handle init client for this module for the Deep Seek Client instance."""
        self._client = httpx.Client(
            base_url=self.config.base_url,
            headers={
                "Authorization": f"Bearer {self.config.api_key}",
                "Content-Type": "application/json"
            },
            timeout=self.config.timeout
        )
        logger.info(f"DeepSeek客户端初始化完成: {self.config.base_url} - {self.config.model}")

    def chat(
        self,
        messages: List[Dict[str, str]],
        max_tokens: Optional[int] = None,
        temperature: Optional[float] = None,
        tools: Optional[List[Tool]] = None,
        **kwargs
    ) -> LLMResponse:
        """Handle chat for the Deep Seek Client instance.

        When ``tools`` is provided the request includes the tool definitions and
        ``tool_choice="auto"``; any tool_calls returned by the model are parsed
        into ``LLMResponse.tool_calls``.
        """
        import json
        start_time = time.time()

        try:
            payload: Dict = {
                "model": self.config.model,
                "messages": messages,
                "max_tokens": max_tokens or self.config.max_tokens,
                "temperature": temperature or self.config.temperature,
                "top_p": kwargs.get("top_p", self.config.top_p),
                "stream": False
            }

            # P0-0: inject tool definitions when provided.
            if tools:
                payload["tools"] = [t.to_openai_format() for t in tools]
                payload["tool_choice"] = "auto"

            response = self._client.post("/chat/completions", json=payload)
            response.raise_for_status()

            data = response.json()

            latency_ms = int((time.time() - start_time) * 1000)

            choices = data.get("choices", [{}])
            message = choices[0].get("message", {})

            # P0-0: parse tool_calls returned by the model.
            raw_tool_calls = message.get("tool_calls") or []
            parsed_tool_calls: List[ToolCall] = []
            for tc in raw_tool_calls:
                fn = tc.get("function", {})
                try:
                    args = json.loads(fn.get("arguments", "{}"))
                except json.JSONDecodeError:
                    args = {}
                parsed_tool_calls.append(ToolCall(id=tc.get("id", ""), name=fn.get("name", ""), arguments=args))

            return LLMResponse(
                content=message.get("content", "") or "",
                model=data.get("model", self.config.model),
                usage=data.get("usage", {}),
                finish_reason=choices[0].get("finish_reason", "stop"),
                latency_ms=latency_ms,
                tool_calls=parsed_tool_calls,
            )

        except httpx.HTTPStatusError as e:
            logger.error(f"DeepSeek API错误: {e.response.status_code} - {e.response.text}")
            return LLMResponse(
                content="",
                model=self.config.model,
                error=f"API错误: {e.response.status_code} - {e.response.text[:200]}"
            )

        except Exception as e:
            logger.error(f"DeepSeek调用失败: {e}")
            return LLMResponse(
                content="",
                model=self.config.model,
                error=str(e)
            )

    def stream_chat(
        self,
        messages: List[Dict[str, str]],
        max_tokens: Optional[int] = None,
        temperature: Optional[float] = None,
        **kwargs
    ):
        """Stream chat for the Deep Seek Client instance."""
        try:
            payload = {
                "model": self.config.model,
                "messages": messages,
                "max_tokens": max_tokens or self.config.max_tokens,
                "temperature": temperature or self.config.temperature,
                "top_p": kwargs.get("top_p", self.config.top_p),
                "stream": True
            }

            with self._client.stream("POST", "/chat/completions", json=payload) as response:
                response.raise_for_status()
                for line in response.iter_lines():
                    if not line:
                        continue

                    line = line.strip()
                    if line.startswith(":"):
                        continue

                    if not line.startswith("data: "):
                        continue

                    data_str = line[6:]
                    if data_str == "[DONE]":
                        break

                    try:
                        import json
                        data = json.loads(data_str)
                        choices = data.get("choices", [])
                        if choices:
                            delta = choices[0].get("delta", {})
                            content = delta.get("content", "")
                            if content:
                                yield content
                    except json.JSONDecodeError:
                        continue

        except httpx.HTTPStatusError as e:
            logger.error(f"DeepSeek Stream API错误: {e.response.status_code}")
            yield ""
        except Exception as e:
            logger.error(f"DeepSeek Stream调用失败: {e}")
            yield ""

    def get_available_models(self) -> List[str]:
        """Return available models for the Deep Seek Client instance."""
        return self.SUPPORTED_MODELS

    def close(self):
        """Release the resources held by this component."""
        if self._client:
            self._client.close()


def create_deepseek_client(
    api_key: str,
    model: str = "deepseek-v4-flash",
    base_url: str = "http://6.86.80.4:30080/v1",
    **kwargs
) -> DeepSeekClient:
    """Create deepseek client."""
    config = LLMConfig(
        provider=LLMProvider.DEEPSEEK,
        model=model,
        api_key=api_key,
        base_url=base_url,
        **kwargs
    )
    return DeepSeekClient(config)
