"""Mock HTTP client for 1C.ai - 用于测试"""

import asyncio
import json
import logging
from datetime import datetime, timedelta
from typing import Optional, AsyncGenerator, Dict, Any

from .config import get_settings, Settings
from .onec_models import (
    ConversationSession,
)

logger = logging.getLogger(__name__)


class MockOneCApiClient:
    """Mock client for testing without external API dependency."""

    def __init__(self, settings: Optional[Settings] = None):
        self.settings: Settings = settings or get_settings()
        self.sessions: Dict[str, ConversationSession] = {}
        self._conversation_counter = 0

    async def create_conversation(
        self,
        programming_language: Optional[str] = None,
    ) -> str:
        """Create a new mock conversation."""
        self._conversation_counter += 1
        conversation_id = f"mock-conversation-{self._conversation_counter}"

        self.sessions[conversation_id] = ConversationSession(
            conversation_id=conversation_id
        )

        logger.info(f"[MOCK] Created new conversation: {conversation_id}")
        return conversation_id

    async def iter_message_stream(
        self, conversation_id: str, message: str, parent_uuid: Optional[str] = None
    ) -> AsyncGenerator[Dict[str, Any], None]:
        """
        Send a message and yield mock streaming updates.
        """
        # Ensure session exists
        if conversation_id not in self.sessions:
            self.sessions[conversation_id] = ConversationSession(
                conversation_id=conversation_id
            )

        # Update usage
        self.sessions[conversation_id].update_usage()

        logger.info(f"[MOCK] Sending message to conversation: {conversation_id}")

        # Generate mock response based on message content
        mock_response = self._generate_mock_response(message)

        # Simulate streaming by yielding chunks
        chunks = self._split_text(mock_response, 50)
        accumulated_text = ""

        for chunk in chunks:
            accumulated_text += chunk
            await asyncio.sleep(0.05)  # Simulate network delay
            yield {
                "text": accumulated_text,
                "finished": False,
                "message_id": f"{conversation_id}:mock-message-id"
            }

        # Final finished message
        yield {
            "text": accumulated_text,
            "finished": True,
            "message_id": f"{conversation_id}:mock-message-id"
        }

    async def send_message_full(self, conversation_id: str, message: str, parent_uuid: Optional[str] = None) -> str:
        """Send a message and return the final full text."""
        final_text = ""
        async for update in self.iter_message_stream(conversation_id, message, parent_uuid):
            final_text = update.get("text") or final_text
        return (final_text or "").strip()

    async def send_feedback(self, message_id: str, score: int) -> None:
        """Mock feedback sending."""
        logger.info(f"[MOCK] Sending feedback: message_id={message_id}, score={score}")

    async def get_or_create_session(
        self, create_new: bool = False, programming_language: Optional[str] = None
    ) -> str:
        """Return an active session id, or create a new one."""
        await self._cleanup_old_sessions()

        if create_new or not self.sessions:
            return await self.create_conversation(programming_language=programming_language)

        # Enforce max active sessions
        if len(self.sessions) >= self.settings.MAX_ACTIVE_SESSIONS:
            oldest_session_id = min(
                self.sessions.keys(), key=lambda k: self.sessions[k].last_used
            )
            del self.sessions[oldest_session_id]
            logger.info(f"[MOCK] Removed oldest session: {oldest_session_id}")

        # Return most recently used
        recent_session_id = max(
            self.sessions.keys(), key=lambda k: self.sessions[k].last_used
        )
        return recent_session_id

    async def _cleanup_old_sessions(self):
        """Remove expired sessions by TTL."""
        now = datetime.now()
        ttl_delta = timedelta(seconds=self.settings.SESSION_TTL)
        expired = [
            sid
            for sid, sess in self.sessions.items()
            if now - sess.last_used > ttl_delta
        ]
        for sid in expired:
            del self.sessions[sid]
            logger.info(f"[MOCK] Removed expired session: {sid}")

    async def close(self):
        """Mock close."""
        logger.info("[MOCK] Client closed")

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.close()

    def _generate_mock_response(self, message: str) -> str:
        """Generate a mock response based on the message."""
        message_lower = message.lower()

        if "http" in message_lower:
            return "Для работы с HTTP-запросами в 1С:Предприятие используйте объекты HTTPСоединение и HTTPЗапрос. Пример:\n\n```bsl\nСоединение = Новый HTTPСоединение(\"api.example.com\");\nЗапрос = Новый HTTPЗапрос(\"/endpoint\");\nЗапрос.Заголовки.Вставить(\"Content-Type\", \"application/json\");\nОтвет = Соединение.Выполнить(Запрос);\n```"
        elif "запрос" in message_lower or "query" in message_lower:
            return "Объект Запрос в 1С:Предприятие используется для выполнения SQL-подобных запросов к данным. Основные методы:\n- Выполнить() - возвращает результат запроса\n- НайтиПоСсылкам() - поиск по ссылкам\n- МенеджерВременныхТаблиц - для временных таблиц"
        elif "код" in message_lower or "code" in message_lower:
            return "Код выглядит корректно. Рекомендации:\n1. Добавьте обработку исключений (Попытка...Исключение...КонецПопытки)\n2. Проверяйте заполненность обязательных полей перед использованием\n3. Используйте транзакции для атомарных операций"
        else:
            return f"Спасибо за ваш вопрос: \"{message}\". В тестовом режиме я предоставляю базовые ответы по 1С:Предприятие. Для получения полноценных ответов, пожалуйста, настройте ONEC_AI_TOKEN."

    def _split_text(self, text: str, chunk_size: int) -> list[str]:
        """Split text into chunks."""
        return [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]