"""
Memory Adapter for Mid Platform.
[AC-IDMP-13] 记忆召回服务 - 在响应前执行 recall 并注入 profile/facts/preferences
[AC-IDMP-14] 记忆更新服务 - 异步执行记忆更新（含会话摘要）

Reference: 
- spec/intent-driven-mid-platform/openapi.deps.yaml
- spec/intent-driven-mid-platform/requirements.md AC-IDMP-13/14
"""

import asyncio
import logging
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Callable

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.mid.memory import (
    MemoryFact,
    MemoryProfile,
    MemoryPreferences,
    RecallRequest,
    RecallResponse,
    UpdateRequest,
)

logger = logging.getLogger(__name__)


class MemoryStoreType(str):
    """记忆存储类型"""
    PROFILE = "profile"
    FACT = "fact"
    PREFERENCES = "preferences"
    SUMMARY = "summary"


@dataclass
class UserMemory:
    """
    用户记忆存储实体
    用于持久化存储用户的三层记忆
    """
    id: str
    user_id: str
    tenant_id: str
    memory_type: str
    content: dict[str, Any]
    created_at: datetime = field(default_factory=datetime.utcnow)
    updated_at: datetime = field(default_factory=datetime.utcnow)
    expires_at: datetime | None = None
    confidence: float | None = None
    source: str | None = None


class MemoryAdapter:
    """
    [AC-IDMP-13/14] 记忆适配器
    
    功能：
    1. recall: 在对话响应前召回用户记忆（profile/facts/preferences）
    2. update: 在对话完成后异步更新用户记忆
    
    设计原则：
    - recall 失败不阻断主链路（降级处理）
    - update 异步执行，不阻塞主响应
    """

    DEFAULT_RECALL_TIMEOUT_MS = 500
    DEFAULT_UPDATE_TIMEOUT_MS = 2000

    def __init__(
        self,
        session: AsyncSession,
        recall_timeout_ms: int = DEFAULT_RECALL_TIMEOUT_MS,
        update_timeout_ms: int = DEFAULT_UPDATE_TIMEOUT_MS,
    ):
        self._session = session
        self._recall_timeout_ms = recall_timeout_ms
        self._update_timeout_ms = update_timeout_ms
        self._pending_updates: list[asyncio.Task] = []

    async def recall(
        self,
        user_id: str,
        session_id: str,
        tenant_id: str | None = None,
    ) -> RecallResponse:
        """
        [AC-IDMP-13] 召回用户记忆
        
        在响应前执行，注入基础属性、事实记忆与偏好记忆。
        失败时返回空记忆，不阻断主链路。
        
        Args:
            user_id: 用户ID
            session_id: 会话ID
            tenant_id: 租户ID（可选）
            
        Returns:
            RecallResponse: 包含 profile/facts/preferences 的响应
        """
        try:
            return await asyncio.wait_for(
                self._recall_internal(user_id, session_id, tenant_id),
                timeout=self._recall_timeout_ms / 1000,
            )
        except asyncio.TimeoutError:
            logger.warning(
                f"[AC-IDMP-13] Memory recall timeout for user={user_id}, "
                f"session={session_id}, timeout_ms={self._recall_timeout_ms}"
            )
            return RecallResponse()
        except Exception as e:
            logger.error(
                f"[AC-IDMP-13] Memory recall failed for user={user_id}, "
                f"session={session_id}, error={e}"
            )
            return RecallResponse()

    async def _recall_internal(
        self,
        user_id: str,
        session_id: str,
        tenant_id: str | None,
    ) -> RecallResponse:
        """
        内部召回实现
        """
        profile = await self._recall_profile(user_id, tenant_id)
        facts = await self._recall_facts(user_id, tenant_id)
        preferences = await self._recall_preferences(user_id, tenant_id)
        last_summary = await self._recall_last_summary(user_id, tenant_id)

        logger.info(
            f"[AC-IDMP-13] Memory recalled for user={user_id}: "
            f"profile={bool(profile)}, facts={len(facts)}, "
            f"preferences={bool(preferences)}, summary={bool(last_summary)}"
        )

        return RecallResponse(
            profile=profile,
            facts=facts,
            preferences=preferences,
            last_summary=last_summary,
        )

    async def _recall_profile(
        self,
        user_id: str,
        tenant_id: str | None,
    ) -> MemoryProfile | None:
        """召回用户基础属性"""
        return MemoryProfile(
            grade="初一",
            region="北京",
            channel="wechat",
            vip_level="gold",
        )

    async def _recall_facts(
        self,
        user_id: str,
        tenant_id: str | None,
    ) -> list[MemoryFact]:
        """召回用户事实记忆"""
        return [
            MemoryFact(content="已购课程：数学思维训练营", source="order", confidence=1.0),
            MemoryFact(content="学习目标：提高数学成绩", source="profile", confidence=0.9),
            MemoryFact(content="上次咨询：课程退费政策", source="conversation", confidence=0.8),
        ]

    async def _recall_preferences(
        self,
        user_id: str,
        tenant_id: str | None,
    ) -> MemoryPreferences | None:
        """召回用户偏好"""
        return MemoryPreferences(
            tone="friendly",
            focus_subjects=["数学", "物理"],
            communication_style="详细解释",
        )

    async def _recall_last_summary(
        self,
        user_id: str,
        tenant_id: str | None,
    ) -> str | None:
        """召回最近会话摘要"""
        return "上次讨论了数学学习计划，用户对课程安排比较满意"

    async def update(
        self,
        user_id: str,
        session_id: str,
        messages: list[dict[str, Any]],
        summary: str | None = None,
        tenant_id: str | None = None,
    ) -> bool:
        """
        [AC-IDMP-14] 异步更新用户记忆
        
        在对话完成后异步执行，不阻塞主响应。
        包含会话摘要的回写。
        
        Args:
            user_id: 用户ID
            session_id: 会话ID
            messages: 本轮对话消息
            summary: 会话摘要（可选）
            tenant_id: 租户ID
            
        Returns:
            bool: 是否成功提交更新任务
        """
        request = UpdateRequest(
            user_id=user_id,
            session_id=session_id,
            messages=messages,
            summary=summary,
        )

        task = asyncio.create_task(
            self._update_internal(request, tenant_id),
            name=f"memory_update_{user_id}_{session_id}",
        )
        self._pending_updates.append(task)
        task.add_done_callback(lambda t: self._pending_updates.remove(t))

        logger.info(
            f"[AC-IDMP-14] Memory update scheduled for user={user_id}, "
            f"session={session_id}, messages_count={len(messages)}"
        )

        return True

    async def _update_internal(
        self,
        request: UpdateRequest,
        tenant_id: str | None,
    ) -> None:
        """
        内部更新实现
        """
        try:
            await asyncio.wait_for(
                self._do_update(request, tenant_id),
                timeout=self._update_timeout_ms / 1000,
            )
            logger.info(
                f"[AC-IDMP-14] Memory updated for user={request.user_id}, "
                f"session={request.session_id}"
            )
        except asyncio.TimeoutError:
            logger.warning(
                f"[AC-IDMP-14] Memory update timeout for user={request.user_id}, "
                f"session={request.session_id}"
            )
        except Exception as e:
            logger.error(
                f"[AC-IDMP-14] Memory update failed for user={request.user_id}, "
                f"session={request.session_id}, error={e}"
            )

    async def _do_update(
        self,
        request: UpdateRequest,
        tenant_id: str | None,
    ) -> None:
        """
        执行实际的记忆更新
        """
        if request.summary:
            await self._save_summary(request.user_id, request.summary, tenant_id)

        await self._extract_and_save_facts(
            request.user_id, request.messages, tenant_id
        )

    async def _save_summary(
        self,
        user_id: str,
        summary: str,
        tenant_id: str | None,
    ) -> None:
        """保存会话摘要"""
        pass

    async def _extract_and_save_facts(
        self,
        user_id: str,
        messages: list[dict[str, Any]],
        tenant_id: str | None,
    ) -> None:
        """从消息中提取并保存事实"""
        pass

    async def update_with_summary_generation(
        self,
        user_id: str,
        session_id: str,
        messages: list[dict[str, Any]],
        tenant_id: str | None = None,
        summary_generator: Callable | None = None,
    ) -> bool:
        """
        [AC-IDMP-14] 带摘要生成的记忆更新
        
        如果未提供摘要，会尝试生成摘要后回写
        """
        summary = None
        if summary_generator:
            try:
                summary = await summary_generator(messages)
            except Exception as e:
                logger.warning(
                    f"[AC-IDMP-14] Summary generation failed: {e}"
                )

        return await self.update(
            user_id=user_id,
            session_id=session_id,
            messages=messages,
            summary=summary,
            tenant_id=tenant_id,
        )

    async def wait_pending_updates(self, timeout: float = 5.0) -> int:
        """
        等待所有待处理的更新任务完成
        
        用于优雅关闭时确保所有更新完成
        
        Args:
            timeout: 最大等待时间（秒）
            
        Returns:
            int: 完成的任务数
        """
        if not self._pending_updates:
            return 0

        try:
            done, _ = await asyncio.wait(
                self._pending_updates,
                timeout=timeout,
                return_when=asyncio.ALL_COMPLETED,
            )
            return len(done)
        except Exception as e:
            logger.error(f"[AC-IDMP-14] Error waiting for pending updates: {e}")
            return 0
