from typing import Any, Dict, List, Optional

from langchain_core.callbacks import CallbackManagerForLLMRun
from langchain_core.messages import BaseMessage
from langchain_core.outputs import ChatResult
from langchain_openai import ChatOpenAI


# Docs: https://api-docs.deepseek.com/guides/reasoning_model
class ChatDeepseekReasoner(ChatOpenAI):
    """ChatDeepseekReasoner with custom overrides for R1/reasoner models."""

    def __init__(self, *args, timeout: int = 180, max_retries: int = 5, **kwargs):
        super().__init__(*args, timeout=timeout, max_retries=max_retries, **kwargs)

    def invocation_params(
        self, options: Optional[Dict[str, Any]] = None, **kwargs: Any
    ) -> Dict[str, Any]:
        params = super().invocation_params(options, **kwargs)

        # Remove unsupported params for R1 models
        params.pop("temperature", None)
        params.pop("top_p", None)
        params.pop("presence_penalty", None)
        params.pop("frequency_penalty", None)

        return params

    def _generate(
        self,
        messages: List[BaseMessage],
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> ChatResult:
        """Override _generate to ensure message alternation in accordance to Deepseek API."""

        processed = []
        prev_role = None

        for msg in messages:
            current_role = "user" if msg.type == "human" else "assistant"

            if prev_role == current_role:
                if processed:
                    processed[-1].content += f"\n\n{msg.content}"
            else:
                processed.append(msg)
                prev_role = current_role

        return super()._generate(
            processed, stop=stop, run_manager=run_manager, **kwargs
        )
