"""Knowledge Base Management API routes"""

from __future__ import annotations

import logging
import uuid
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any

from fastapi import APIRouter, HTTPException, Request, UploadFile, File
from pydantic import BaseModel

logger = logging.getLogger(__name__)

router = APIRouter(tags=["kb-management"])

MAX_UPLOAD_SIZE = 50 * 1024 * 1024  # 50MB


# ---------------------------------------------------------------------------
# In-memory Knowledge Source Store
# ---------------------------------------------------------------------------


@dataclass
class KnowledgeSource:
    id: str
    name: str
    type: str  # "local" | "feishu" | "confluence" | "http"
    config: dict[str, Any] = field(default_factory=dict)
    status: str = "active"
    document_count: int = 0
    last_synced: str | None = None


@dataclass
class UploadedDocument:
    document_id: str
    filename: str
    source_id: str
    chunks: int
    status: str
    created_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())


class KnowledgeSourceStore:
    def __init__(self, max_sources: int = 500):
        self._sources: dict[str, KnowledgeSource] = {}
        self._documents: list[UploadedDocument] = []
        self._max = max_sources

    def add_source(self, name: str, source_type: str, config: dict[str, Any]) -> KnowledgeSource:
        source_id = str(uuid.uuid4())
        source = KnowledgeSource(
            id=source_id,
            name=name,
            type=source_type,
            config=config,
        )
        self._sources[source_id] = source
        return source

    def get_source(self, source_id: str) -> KnowledgeSource | None:
        return self._sources.get(source_id)

    def remove_source(self, source_id: str) -> bool:
        if source_id in self._sources:
            del self._sources[source_id]
            return True
        return False

    def list_sources(self) -> list[KnowledgeSource]:
        return list(self._sources.values())

    def add_document(self, doc: UploadedDocument) -> None:
        self._documents.append(doc)
        # Update source document count
        source = self._sources.get(doc.source_id)
        if source:
            source.document_count += 1
            source.last_synced = doc.created_at

    def list_documents(self, source_id: str | None = None) -> list[UploadedDocument]:
        if source_id:
            return [d for d in self._documents if d.source_id == source_id]
        return list(self._documents)


# Module-level singleton
_source_store = KnowledgeSourceStore()


# ---------------------------------------------------------------------------
# Request / Response models
# ---------------------------------------------------------------------------


class AddSourceRequest(BaseModel):
    name: str
    type: str  # "local" | "feishu" | "confluence" | "http"
    config: dict[str, Any] = {}


class SearchRequest(BaseModel):
    query: str
    sources: list[str] | None = None
    top_k: int = 5


class SearchResult(BaseModel):
    content: str
    source: str
    score: float
    metadata: dict[str, Any] = {}


# ---------------------------------------------------------------------------
# Endpoints
# ---------------------------------------------------------------------------


@router.get("/kb-management/sources")
async def list_sources(req: Request):
    """List all knowledge sources."""
    sources = _source_store.list_sources()
    return {
        "sources": [
            {
                "id": s.id,
                "name": s.name,
                "type": s.type,
                "status": s.status,
                "document_count": s.document_count,
                "last_synced": s.last_synced,
            }
            for s in sources
        ]
    }


@router.post("/kb-management/sources", status_code=201)
async def add_source(request: AddSourceRequest, req: Request):
    """Add a knowledge source."""
    valid_types = {"local", "feishu", "confluence", "http"}
    if request.type not in valid_types:
        raise HTTPException(
            status_code=422,
            detail=f"Invalid source type '{request.type}'. Must be one of: {valid_types}",
        )

    source = _source_store.add_source(
        name=request.name,
        source_type=request.type,
        config=request.config,
    )
    return {
        "id": source.id,
        "name": source.name,
        "type": source.type,
        "status": source.status,
    }


@router.delete("/kb-management/sources/{source_id}")
async def remove_source(source_id: str, req: Request):
    """Remove a knowledge source."""
    if not _source_store.remove_source(source_id):
        raise HTTPException(status_code=404, detail=f"Source '{source_id}' not found")
    return {"status": "removed"}


@router.post("/kb-management/documents/upload")
async def upload_document(
    req: Request,
    file: UploadFile = File(...),
    source_id: str = "",
):
    """Upload a document to the knowledge base."""
    if not file.filename:
        raise HTTPException(status_code=422, detail="Filename is required")

    # Try to use DocumentLoader if available
    chunks = 1
    try:
        from agentkit.memory.document_loader import DocumentLoader

        content = await file.read(MAX_UPLOAD_SIZE + 1)
        if len(content) > MAX_UPLOAD_SIZE:
            raise HTTPException(status_code=413, detail=f"File too large. Maximum size is {MAX_UPLOAD_SIZE // (1024*1024)}MB")
        loader = DocumentLoader()
        doc = loader.load_bytes(content, file.filename)
        # Estimate chunks based on content length (rough approximation)
        chunks = max(1, len(doc.content) // 500)
    except ImportError:
        # DocumentLoader not available, use basic estimation
        content = await file.read(MAX_UPLOAD_SIZE + 1)
        if len(content) > MAX_UPLOAD_SIZE:
            raise HTTPException(status_code=413, detail=f"File too large. Maximum size is {MAX_UPLOAD_SIZE // (1024*1024)}MB")
        chunks = max(1, len(content) // 500)
    except Exception as e:
        logger.warning(f"Document parsing failed: {e}")
        chunks = 1

    # Determine source_id - use "local" default if not provided
    effective_source_id = source_id or "local"

    # Ensure a local source exists
    if effective_source_id == "local":
        local_sources = [
            s for s in _source_store.list_sources() if s.type == "local"
        ]
        if not local_sources:
            _source_store.add_source("本地文档", "local", {})

    uploaded = UploadedDocument(
        document_id=str(uuid.uuid4()),
        filename=file.filename,
        source_id=effective_source_id,
        chunks=chunks,
        status="indexed",
    )
    _source_store.add_document(uploaded)

    return {
        "document_id": uploaded.document_id,
        "filename": uploaded.filename,
        "chunks": uploaded.chunks,
        "status": uploaded.status,
    }


@router.post("/kb-management/search")
async def search_knowledge(request: SearchRequest, req: Request):
    """Test search/retrieval against the knowledge base."""
    # Try to use semantic memory if available
    memory_retriever = getattr(req.app.state, "memory_retriever", None)
    if memory_retriever and hasattr(memory_retriever, "semantic_memory") and memory_retriever.semantic_memory:
        try:
            results = await memory_retriever.semantic_memory.retrieve(
                query=request.query,
                top_k=request.top_k,
            )
            return {
                "results": [
                    {
                        "content": r.content if hasattr(r, "content") else str(r),
                        "source": r.source_id if hasattr(r, "source_id") else "",
                        "score": r.score if hasattr(r, "score") else 0.0,
                        "metadata": r.metadata if hasattr(r, "metadata") else {},
                    }
                    for r in results
                ]
            }
        except Exception as e:
            logger.warning(f"Semantic search failed: {e}")

    # Fallback: return empty results with a hint
    return {
        "results": [],
        "message": "未配置语义检索服务，请先配置知识库连接",
    }


@router.get("/kb-management/sources/{source_id}/health")
async def check_source_health(source_id: str, req: Request):
    """Check the health of a knowledge source."""
    source = _source_store.get_source(source_id)
    if source is None:
        raise HTTPException(status_code=404, detail=f"Source '{source_id}' not found")

    # For local sources, always healthy
    if source.type == "local":
        return {"source_id": source_id, "status": "healthy", "message": "本地存储正常"}

    # For external sources, try to check connectivity
    # This would use the actual KB adapters in production
    return {"source_id": source_id, "status": "unknown", "message": "健康检查未实现"}
