"""MCP 工具实现。

每个工具:接收自然语言查询 → DashScope 嵌入 → Qdrant 检索 → 格式化返回。
嵌入 provider 复用 M5,检索复用 M6。
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

from dotenv import load_dotenv
from loguru import logger
from mcp.server.fastmcp import FastMCP

from embedding import make_sync_provider
from vectorstore import SearchFilter, VectorStore, make_qdrant_client

# 加载 .env(API key 等)
load_dotenv()

# --------------------------------------------------------------------------- #
# 单例(模块加载时初始化,所有工具共用)
# --------------------------------------------------------------------------- #

@dataclass
class _Backend:
    embedder: Any          # EmbeddingProvider
    vector_store: VectorStore

_backend: _Backend | None = None


def _get_backend() -> _Backend:
    global _backend
    if _backend is None:
        emb = make_sync_provider()  # 读取 EMBEDDING_PROVIDER 环境变量
        logger.info("MCP embedder 就绪: dim={}", emb.dim)
        client = make_qdrant_client()
        store = VectorStore(client)
        logger.info("MCP vector_store 就绪: count={}", store.count())
        _backend = _Backend(embedder=emb, vector_store=store)
    return _backend


# --------------------------------------------------------------------------- #
# 嵌入 + 检索
# --------------------------------------------------------------------------- #

def _search(
    query: str,
    top_k: int = 10,
    filter: SearchFilter | None = None,
) -> list[dict[str, Any]]:
    """嵌入查询文本 → Qdrant 检索 → 返回 dict 列表。"""
    be = _get_backend()
    vec = be.embedder.embed_one(query)
    results = be.vector_store.query(
        query_vector=vec, top_k=top_k, filter=filter, score_threshold=0.3,
    )
    return [
        {
            "title": r.title,
            "url": r.url,
            "source": r.source_id,
            "score": round(r.score, 4),
            "publish_time": r.publish_time.isoformat() if r.publish_time else None,
            "event": {
                "sentiment": (r.event or {}).get("sentiment"),
                "importance": (r.event or {}).get("importance"),
                "event_type": (r.event or {}).get("event_type"),
                "stock_codes": (r.event or {}).get("stock_codes", []),
                "company_names": (r.event or {}).get("company_names", []),
                "industries": (r.event or {}).get("industries", []),
                "summary": (r.event or {}).get("summary"),
            },
        }
        for r in results
    ]


# --------------------------------------------------------------------------- #
# MCP 服务器 & 工具
# --------------------------------------------------------------------------- #

mcp = FastMCP(
    name="A股DeepResearch",
    instructions="A 股 Deep Research 知识库——语义检索财经新闻与投资事件。",
)


def _fmt_results(hits: list[dict[str, Any]], query: str) -> str:
    """把检索结果格式化为 Markdown 文本。"""
    if not hits:
        return f"未找到与「{query}」相关的结果。"
    lines = [f"# 检索结果: {query}", "", f"共 {len(hits)} 条:", ""]
    for i, h in enumerate(hits, 1):
        ev = h["event"]
        sentiment = {"positive": "🟢利好", "neutral": "⚪中性", "negative": "🔴利空"}.get(
            ev.get("sentiment"), ""
        )
        lines.append(f"### {i}. {h['title']}")
        lines.append(f"- 来源: {h['source']} | 相似度: {h['score']} | {sentiment}")
        lines.append(f"- 时间: {h['publish_time'] or '未知'}")
        if ev.get("company_names"):
            lines.append(f"- 公司: {', '.join(ev['company_names'][:5])}")
        if ev.get("stock_codes"):
            lines.append(f"- 代码: {', '.join(ev['stock_codes'][:5])}")
        if ev.get("industries"):
            lines.append(f"- 行业: {', '.join(ev['industries'][:3])}")
        if ev.get("summary"):
            lines.append(f"- 摘要: {ev['summary']}")
        lines.append(f"- URL: {h['url']}")
        lines.append("")
    return "\n".join(lines)


# --------------------------------------------------------------------------- #
# Tool 1: search_news
# --------------------------------------------------------------------------- #

@mcp.tool()
def search_news(query: str, top_k: int = 10) -> str:
    """语义检索 A 股财经新闻知识库。

    参数:
        query: 自然语言查询(如 "宁德时代最新动态" "AI 行业政策")
        top_k: 返回条数(默认 10)

    返回: Markdown 格式的检索结果,含标题、来源、相似度、URL。
    """
    logger.info("search_news query={!r} top_k={}", query, top_k)
    hits = _search(query, top_k=top_k)
    return _fmt_results(hits, query)


# --------------------------------------------------------------------------- #
# Tool 2: search_company_news
# --------------------------------------------------------------------------- #

@mcp.tool()
def search_company_news(query: str, company: str, top_k: int = 10) -> str:
    """检索指定公司的相关新闻。

    参数:
        query:   自然语言查询
        company: 公司名称(如 "宁德时代" "贵州茅台")
        top_k:   返回条数(默认 10)

    返回: Markdown 格式的检索结果。
    """
    logger.info("search_company_news query={!r} company={!r}", query, company)
    hits = _search(
        query, top_k=top_k,
        filter=SearchFilter(company_names=[company]),
    )
    if not hits:
        # 降级:无精确命中时做纯语义搜索
        logger.info("company 精确命中 0 条,降级为纯语义搜索")
        hits = _search(query, top_k=top_k)
    return _fmt_results(hits, f"{query} (公司:{company})")


# --------------------------------------------------------------------------- #
# Tool 3: search_industry_news
# --------------------------------------------------------------------------- #

@mcp.tool()
def search_industry_news(query: str, industry: str, top_k: int = 10) -> str:
    """检索指定行业的相关新闻。

    参数:
        query:    自然语言查询
        industry: 行业名(如 "动力电池" "白酒" "半导体")
        top_k:    返回条数(默认 10)

    返回: Markdown 格式的检索结果。
    """
    logger.info("search_industry_news query={!r} industry={!r}", query, industry)
    hits = _search(
        query, top_k=top_k,
        filter=SearchFilter(industries=[industry]),
    )
    if not hits:
        logger.info("industry 精确命中 0 条,降级为纯语义搜索")
        hits = _search(query, top_k=top_k)
    return _fmt_results(hits, f"{query} (行业:{industry})")


# --------------------------------------------------------------------------- #
# Tool 4: search_stock_events
# --------------------------------------------------------------------------- #

@mcp.tool()
def search_stock_events(query: str, stock_code: str, top_k: int = 10) -> str:
    """检索指定股票代码相关的投资事件。

    参数:
        query:      自然语言查询
        stock_code: 6 位 A 股代码(如 "300750" "000001",可带 .SH/.SZ 后缀)
        top_k:      返回条数(默认 10)

    返回: Markdown 格式的检索结果。
    """
    # 标准化:去掉后缀,补一致性
    code = stock_code.strip().split(".")[0].upper()
    logger.info("search_stock_events query={!r} code={!r}", query, code)
    hits = _search(
        query, top_k=top_k,
        filter=SearchFilter(stock_codes=[code]),
    )
    if not hits:
        logger.info("stock_code 精确命中 0 条,降级为纯语义搜索")
        hits = _search(query, top_k=top_k)
    return _fmt_results(hits, f"{query} (代码:{code})")


# --------------------------------------------------------------------------- #
# Tool 5: search_sentiment_trend
# --------------------------------------------------------------------------- #

@mcp.tool()
def search_sentiment_trend(query: str, sentiment: str = "all", top_k: int = 20) -> str:
    """检索并统计特定情绪倾向的新闻。

    参数:
        query:     自然语言查询
        sentiment: positive(利好) / negative(利空) / neutral(中性) / all(全部,默认)
        top_k:     返回条数(默认 20)

    返回: Markdown 格式的检索结果 + 情绪分布统计。
    """
    logger.info("search_sentiment_trend query={!r} sentiment={!r}", query, sentiment)
    filt = None
    if sentiment in ("positive", "negative", "neutral"):
        filt = SearchFilter(sentiment=sentiment)

    hits = _search(query, top_k=top_k, filter=filt)

    # 统计情绪分布
    pos = sum(1 for h in hits if h["event"].get("sentiment") == "positive")
    neg = sum(1 for h in hits if h["event"].get("sentiment") == "negative")
    neu = sum(1 for h in hits if h["event"].get("sentiment") == "neutral")

    header = (
        f"# 情绪趋势: {query}\n\n"
        f"共 {len(hits)} 条 | "
        f"🟢利好 {pos} | 🔴利空 {neg} | ⚪中性 {neu}\n"
    )
    return header + "\n" + _fmt_results(hits, query)
