"""
mcp_server.py

MCP(Model Context Protocol) 서버.
아누 시스템의 지식 베이스를 Claude Desktop/Cursor에서 직접 사용할 수 있게 합니다.

통신 방식: stdio (stdout은 MCP 프로토콜 전용 - print/logging은 stderr로만)
"""

from __future__ import annotations

import logging
import os
import sys
from collections import Counter
from typing import Any, cast

# stderr로만 로깅 (stdio 통신이므로 stdout 사용 금지)
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
logger = logging.getLogger(__name__)

# libs 디렉토리를 sys.path에 추가
libs_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "libs")
if libs_path not in sys.path:
    sys.path.insert(0, libs_path)

from search import hybrid_search  # type: ignore[import-not-found]  # libs/search.py
from supabase import Client, create_client

from mcp.server.fastmcp import FastMCP

# ---------------------------------------------------------------------------
# Supabase 클라이언트 (lazy init - 모듈 import 시 환경변수 없어도 에러 없음)
# ---------------------------------------------------------------------------

supabase_client: Client | None = None


def _get_supabase_client() -> Client:
    """환경변수에서 Supabase 접속 정보를 읽어 클라이언트를 반환한다."""
    url = os.environ.get("INSURO_SUPABASE_URL") or os.environ.get("INSURO_NEW_SUPABASE_URL")
    key = os.environ.get("INSURO_NEW_SERVICE_ROLE_KEY") or os.environ.get("INSURO_SUPABASE_SERVICE_ROLE_KEY")
    if not url or not key:
        raise ValueError("Supabase URL and service role key must be set via environment variables")
    return create_client(url, key)


def _ensure_client() -> Client:
    """supabase_client가 None이면 초기화 후 반환한다."""
    global supabase_client
    if supabase_client is None:
        supabase_client = _get_supabase_client()
    return supabase_client


# ---------------------------------------------------------------------------
# FastMCP 서버 인스턴스
# ---------------------------------------------------------------------------

mcp = FastMCP("anu-knowledge")


# ---------------------------------------------------------------------------
# Tool 1: search_knowledge
# ---------------------------------------------------------------------------


@mcp.tool()
def search_knowledge(query: str, source: str | None = None, limit: int = 5) -> list[dict[str, Any]]:
    """아누 지식 베이스에서 관련 문서를 검색합니다.

    Args:
        query: 검색할 질문 또는 키워드
        source: 특정 소스로 검색 범위 제한 (예: 'insurance_docs'). None이면 전체 검색
        limit: 반환할 최대 결과 수 (기본값: 5)

    Returns:
        검색 결과 목록. 각 항목: content, title, source, similarity
    """
    results = hybrid_search(query=query, limit=limit, source_filter=source)
    return [
        {
            "content": r["content"],
            "title": r["title"],
            "source": r["source"],
            "similarity": r["similarity"],
        }
        for r in results
    ]


# ---------------------------------------------------------------------------
# Tool 2: get_document
# ---------------------------------------------------------------------------


@mcp.tool()
def get_document(document_id: str) -> dict[str, Any] | None:
    """특정 문서의 전체 내용을 조회합니다.

    Args:
        document_id: 조회할 문서의 ID

    Returns:
        문서 상세 정보: id, title, content, source, metadata. 존재하지 않으면 None
    """
    client = _ensure_client()
    response = client.table("knowledge_documents").select("*").eq("id", document_id).execute()
    rows = cast(list[dict[str, Any]], response.data or [])
    if not rows:
        return None
    doc = rows[0]
    return {
        "id": doc["id"],
        "title": doc.get("title", ""),
        "content": doc.get("content", ""),
        "source": doc.get("source", ""),
        "metadata": doc.get("metadata", {}),
    }


# ---------------------------------------------------------------------------
# Tool 3: list_sources
# ---------------------------------------------------------------------------


@mcp.tool()
def list_sources() -> list[dict[str, Any]]:
    """지식 베이스에 등록된 소스 목록과 각 소스의 문서 수를 조회합니다.

    Returns:
        소스 목록. 각 항목: source (소스명), document_count (문서 수)
    """
    client = _ensure_client()
    response = client.table("knowledge_documents").select("source").execute()
    rows = cast(list[dict[str, Any]], response.data or [])
    if not rows:
        return []

    # row에 document_count 필드가 있으면 그 값을 직접 사용 (RPC/뷰 결과)
    # 없으면 Python에서 source별 카운트 집계
    first_row = rows[0]
    if "document_count" in first_row:
        return [
            {"source": row["source"], "document_count": row["document_count"]}
            for row in sorted(rows, key=lambda x: str(x["source"]))
        ]

    source_counts = Counter(str(row["source"]) for row in rows)
    return [{"source": source, "document_count": count} for source, count in sorted(source_counts.items())]


# ---------------------------------------------------------------------------
# 엔트리포인트
# ---------------------------------------------------------------------------

if __name__ == "__main__":
    mcp.run(transport="stdio")
