# core/chat.py
from __future__ import annotations

from datetime import UTC, datetime

import structlog

from core.protocol import ChatContext
from core.store import StateStore

logger = structlog.get_logger(__name__)


def _to_dict(ctx: ChatContext) -> dict:
    return {
        "chat_id": ctx.chat_id,
        "display_name": ctx.display_name,
        "platform": ctx.platform,
        "surface_ref": ctx.surface_ref,
        "created_at": ctx.created_at.isoformat(),
        "is_archived": ctx.is_archived,
    }


def _from_dict(d: dict) -> ChatContext:
    return ChatContext(
        chat_id=d["chat_id"],
        display_name=d["display_name"],
        platform=d["platform"],
        surface_ref=d["surface_ref"],
        created_at=datetime.fromisoformat(d["created_at"]),
        is_archived=d.get("is_archived", False),
    )


class ChatManager:
    """
    Управляет метаданными чатов (C1/C2/C3 в workspace пользователя).
    НЕ управляет lifecycle контейнера — это дело Master'а на стороне платформы.
    """

    def __init__(self, platform: object, store: StateStore) -> None:
        self._store = store

    def _key(self, user_id: str, chat_id: str) -> str:
        return f"chat:{user_id}:{chat_id}"

    async def get_or_create(
        self,
        user_id: str,
        chat_id: str,
        platform: str,
        surface_ref: str,
        name: str | None = None,
    ) -> ChatContext:
        key = self._key(user_id, chat_id)
        stored = await self._store.get(key)
        if stored:
            return _from_dict(stored)

        ctx = ChatContext(
            chat_id=chat_id,
            display_name=name or f"Чат {chat_id}",
            platform=platform,
            surface_ref=surface_ref,
            created_at=datetime.now(UTC),
        )
        await self._store.set(key, _to_dict(ctx))
        logger.info("Chat created", chat_id=chat_id, user_id=user_id)
        return ctx

    async def get(self, chat_id: str, user_id: str | None = None) -> ChatContext | None:
        if user_id:
            stored = await self._store.get(self._key(user_id, chat_id))
            return _from_dict(stored) if stored else None
        # Scan by chat_id suffix when user_id unknown (slower)
        for key in await self._store.keys("chat:"):
            if key.endswith(f":{chat_id}"):
                stored = await self._store.get(key)
                if stored:
                    return _from_dict(stored)
        return None

    async def rename(self, chat_id: str, name: str, user_id: str | None = None) -> ChatContext:
        ctx = await self.get(chat_id, user_id)
        if not ctx:
            raise ValueError(f"Chat {chat_id} not found")
        ctx.display_name = name
        for key in await self._store.keys("chat:"):
            if key.endswith(f":{chat_id}"):
                await self._store.set(key, _to_dict(ctx))
                break
        return ctx

    async def archive(self, chat_id: str, user_id: str | None = None) -> None:
        ctx = await self.get(chat_id, user_id)
        if not ctx:
            raise ValueError(f"Chat {chat_id} not found")
        ctx.is_archived = True
        for key in await self._store.keys("chat:"):
            if key.endswith(f":{chat_id}"):
                await self._store.set(key, _to_dict(ctx))
                break

    async def list_active(self, user_id: str) -> list[ChatContext]:
        chats = []
        for key in await self._store.keys(f"chat:{user_id}:"):
            stored = await self._store.get(key)
            if stored and not stored.get("is_archived"):
                chats.append(_from_dict(stored))
        return chats
