"""
語意搜尋 API(階段 4d)。

單一頻道大量訊息累積後,要找「上次討論 Q4 預算的結論」靠關鍵字搜尋會撞到很多無關閒聊。
這支 API 用 Qdrant 向量搜尋(階段 3f 已建好)做語意比對 → 即使你打「Q4 預算」也能找到
「下季要花多少錢」這種講同一件事但用詞不同的訊息。

  - GET /api/search/messages?q=...&limit=10
"""

from datetime import datetime
from uuid import UUID

from fastapi import APIRouter, HTTPException, Query, status
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.orm import selectinload

from app.core.deps import CurrentUser, DBSession
from app.models.channel import Message
from app.services.coba_memory import search_relevant


router = APIRouter(prefix="/api/search", tags=["search"])


class SearchResultItem(BaseModel):
    message_id: UUID
    channel_id: UUID
    content: str
    sender_name: str | None        # 發送者名稱(NULL = 庫柏)
    created_at: datetime
    tags: list[str] = []
    score: float                     # Qdrant cosine similarity 分數


@router.get(
    "/messages",
    response_model=list[SearchResultItem],
    summary="跨歷史訊息語意搜尋",
)
async def search_messages(
    current_user: CurrentUser,
    db: DBSession,
    q: str = Query(..., min_length=1, max_length=500),
    limit: int = Query(default=10, ge=1, le=50),
):
    """用 Qdrant 找跟 q 語意最相關的訊息。

    回傳每筆會帶完整 message 資訊(內容、發送者、時間)。
    """
    # 1. Qdrant 拉相關 message id
    raw = await search_relevant(query=q, limit=limit, channel_id=None)
    if not raw:
        return []

    # 2. 從 SQLite 撈完整訊息(含 user)
    ids = [UUID(r["message_id"]) for r in raw if r.get("message_id")]
    if not ids:
        return []
    stmt = (
        select(Message)
        .options(selectinload(Message.user))
        .where(Message.id.in_(ids), Message.deleted_at.is_(None))
    )
    msgs = list((await db.execute(stmt)).scalars().all())
    msg_by_id = {str(m.id): m for m in msgs}

    # 3. 按 raw 的 score 順序輸出(Qdrant 已經按相關度排好)
    out = []
    for r in raw:
        m = msg_by_id.get(r["message_id"])
        if m is None:
            continue
        out.append({
            "message_id": m.id,
            "channel_id": m.channel_id,
            "content": m.content[:500],   # 太長截掉
            "sender_name": m.user.display_name if m.user else None,
            "created_at": m.created_at,
            "tags": m.tags or [],
            "score": r.get("score", 0.0),
        })
    return out
