"""
Tag Search API — FastAPI route cho tìm kiếm sản phẩm bằng AI tags.
Gọi TagSearchGraph 2-Agent (Planner ⇄ Tool → Responder) qua Controller.
Controller có Langfuse tracing + timing breakdown.
History lưu Redis, tự expire sau 30 phút.
"""

import json
import logging
from pydantic import BaseModel
from fastapi import APIRouter, BackgroundTasks
from fastapi.responses import JSONResponse

from langchain_core.messages import AIMessage, HumanMessage

# ── Controller v2 (có Langfuse tracing + timing) ──
from agent.tag_search_agent_v2.controller import tag_search_chat_controller
from common.cache import redis_cache


logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/tag-search", tags=["Tag Search"])

HISTORY_KEY_PREFIX = "tagsearch:hist:"
HISTORY_TTL = 1800  # 30 phút tự chết


class TagChatRequest(BaseModel):
    query: str
    session_id: str | None = None


# ─── Helpers: serialize/deserialize LangChain messages ↔ Redis ───

def _serialize_messages(messages: list) -> str:
    """LangChain messages → JSON string cho Redis."""
    data = []
    for msg in messages:
        content = msg.content if isinstance(msg.content, str) else str(msg.content)
        if isinstance(msg, HumanMessage):
            data.append({"role": "human", "content": content})
        elif isinstance(msg, AIMessage):
            data.append({"role": "ai", "content": content})
    return json.dumps(data, ensure_ascii=False)


def _deserialize_messages(raw: str) -> list:
    """JSON string từ Redis → LangChain messages."""
    try:
        data = json.loads(raw)
    except Exception:
        return []
    messages = []
    for item in data:
        if item["role"] == "human":
            messages.append(HumanMessage(content=item["content"]))
        elif item["role"] == "ai":
            messages.append(AIMessage(content=item["content"]))
    return messages


async def _load_history(session_id: str) -> list:
    """Load history từ Redis. Trả [] nếu không có hoặc Redis tắt."""
    try:
        client = redis_cache.get_client()
        if not client:
            return []
        raw = await client.get(f"{HISTORY_KEY_PREFIX}{session_id}")
        if raw:
            msgs = _deserialize_messages(raw)
            logger.debug("📜 Loaded %d history messages for session %s", len(msgs), session_id[:8])
            return msgs
    except Exception as e:
        logger.warning("Redis load history error: %s", e)
    return []


async def _save_history(session_id: str, messages: list):
    """Save history vào Redis với TTL. Tự chết sau HISTORY_TTL."""
    try:
        client = redis_cache.get_client()
        if not client:
            return
        # Giới hạn 20 cặp cuối (40 messages) để không phình Redis
        trimmed = messages[-40:]
        raw = _serialize_messages(trimmed)
        await client.setex(f"{HISTORY_KEY_PREFIX}{session_id}", HISTORY_TTL, raw)
        logger.debug("💾 Saved %d messages for session %s (TTL=%ds)", len(trimmed), session_id[:8], HISTORY_TTL)
    except Exception as e:
        logger.warning("Redis save history error: %s", e)


async def _clear_history(session_id: str):
    """Xoá history khỏi Redis."""
    try:
        client = redis_cache.get_client()
        if client:
            await client.delete(f"{HISTORY_KEY_PREFIX}{session_id}")
            logger.info("🗑️ Cleared history for session %s", session_id[:8])
    except Exception as e:
        logger.warning("Redis clear history error: %s", e)


# ─── Endpoints ───

@router.post("/chat", summary="Chat with Tag Search Agent")
async def tag_chat(req: TagChatRequest, background_tasks: BackgroundTasks):
    """
    Gửi câu hỏi cho Tag Search Agent.
    Nếu có session_id, history được load/save tự động từ Redis.
    """
    query = req.query.strip()
    if not query:
        return JSONResponse(status_code=400, content={"status": "error", "message": "Query trống"})

    session_id = req.session_id

    try:
        # Load history từ Redis (nếu có session)
        history = []
        if session_id:
            history = await _load_history(session_id)

        # Delegate to controller — có Langfuse tracing + timing
        result = await tag_search_chat_controller(
            query=query,
            session_id=session_id,
            background_tasks=background_tasks,
            history=history if history else None,
        )

        if result.get("status") == "error":
            return JSONResponse(
                status_code=500,
                content={
                    "status": "error",
                    "message": result.get("message", "Unknown error"),
                    "trace_id": result.get("trace_id"),
                }
            )

        # Save history to Redis (append user + AI)
        if session_id and result.get("response"):
            history.append(HumanMessage(content=query))
            history.append(AIMessage(content=result["response"]))
            await _save_history(session_id, history)

        return {
            "status": "success",
            "response": result["response"],
            "products": result.get("products", []),
            "product_ids": result.get("product_ids", []),
            "product_count": result.get("product_count", 0),
            "pipeline": result.get("pipeline", []),
            "agent_path": result.get("agent_path", ""),
            "tool_calls": result.get("tool_calls", []),
            "trace_id": result.get("trace_id"),
            "timing": result.get("timing", {}),
            "session_id": session_id,
            "history_count": len(history),
        }
    except Exception as e:
        logger.error(f"❌ Tag Search error: {e}", exc_info=True)
        return JSONResponse(status_code=500, content={"status": "error", "message": str(e)})


@router.post("/clear", summary="Clear chat history")
async def tag_clear(req: TagChatRequest):
    """Xoá history của session."""
    if req.session_id:
        await _clear_history(req.session_id)
    return {"status": "success", "message": "History cleared"}


@router.get("/history", summary="Get chat history")
async def tag_history(session_id: str):
    """Load history từ Redis theo session_id cho frontend (khi f5 reload lại)."""
    if not session_id:
        return {"status": "success", "history": []}

    history_objs = await _load_history(session_id)
    formatted = []
    for msg in history_objs:
        if isinstance(msg, HumanMessage):
            formatted.append({"role": "user", "content": msg.content})
        elif isinstance(msg, AIMessage):
            formatted.append({"role": "ai", "content": msg.content})

    return {"status": "success", "history": formatted, "count": len(formatted)}
