import uuid

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.auth.api_key import get_user_by_api_key
from app.database import get_db
from app.models.collection import Collection
from app.models.schemas import TicketInput, TicketsUpload, TicketsUploadResponse, UserResponse, CollectionResponse
from app.models.search_schemas import SearchRequest, SearchResponse, SourceItem
from app.models.user import User
from app.services.embedding import embed_query
from app.services.vector_store import search as qdrant_search, get_existing_ticket_ids
from app.services.reranking import rerank
from app.services.llm import generate_answer
from app.services.chunking import build_chunk
from app.services.embedding import embed_texts
from app.services.vector_store import upsert_chunks

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

FETCH_K = 20
FINAL_K = 5


@router.get("/me", response_model=UserResponse)
async def get_me(user: User = Depends(get_user_by_api_key)):
    return user


@router.patch("/me/api-key")
async def rotate_api_key(
    user: User = Depends(get_user_by_api_key),
    db: AsyncSession = Depends(get_db),
):
    user.api_key = str(uuid.uuid4().hex[:32])
    await db.commit()
    return {"api_key": user.api_key}


@router.get("/collections", response_model=list[CollectionResponse])
async def list_collections(
    user: User = Depends(get_user_by_api_key),
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(
        select(Collection).where(Collection.user_id == user.id).order_by(Collection.created_at.desc())
    )
    return result.scalars().all()


@router.post("/tickets", response_model=TicketsUploadResponse)
async def upload_tickets(
    body: TicketsUpload,
    collection_id: uuid.UUID,
    user: User = Depends(get_user_by_api_key),
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(
        select(Collection).where(Collection.id == collection_id, Collection.user_id == user.id)
    )
    collection = result.scalar_one_or_none()
    if not collection:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Collection not found")

    existing_ids = get_existing_ticket_ids(str(user.id), str(collection_id))

    processed = 0
    skipped = 0
    chunks = []

    for t in body.tickets:
        if t.ticket_id in existing_ids:
            skipped += 1
            continue
        ticket_dict = {
            "ticket_id": t.ticket_id,
            "category": t.category,
            "description": t.description,
            "client": t.client,
            "messages": [{"role": m.role, "text": m.text} for m in t.messages],
        }
        chunk = build_chunk(ticket_dict)
        if chunk:
            chunk["tenant_id"] = str(user.id)
            chunk["collection_id"] = str(collection_id)
            chunks.append(chunk)
            processed += 1
        else:
            skipped += 1

    if chunks:
        search_texts = [c["search_text"] for c in chunks]
        vectors = await embed_texts(search_texts)
        await upsert_chunks(str(user.id), chunks, vectors)
        collection.ticket_count += processed
        await db.commit()

    return TicketsUploadResponse(
        processed=processed,
        skipped=skipped,
        collection_ticket_count=collection.ticket_count,
    )


@router.post("/search", response_model=SearchResponse)
async def search(
    body: SearchRequest,
    user: User = Depends(get_user_by_api_key),
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(
        select(Collection).where(
            Collection.id == uuid.UUID(body.collection_id),
            Collection.user_id == user.id,
        )
    )
    collection = result.scalar_one_or_none()
    if not collection:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Collection not found")

    query_vector = await embed_query(body.query)

    qdrant_results = await qdrant_search(
        tenant_id=str(user.id),
        query_vector=query_vector,
        collection_id=body.collection_id,
        k=FETCH_K,
    )

    if not qdrant_results:
        return SearchResponse(
            answer="Недостаточно информации в истории обращений" if body.generate_answer else None,
            sources=[],
        )

    reranked = rerank(body.query, qdrant_results, k=FINAL_K)

    sources = [
        SourceItem(ticket_id=r["ticket_id"], score=r["score"], category=r["category"], full_text=r["full_text"])
        for r in reranked
    ]

    answer = None
    if body.generate_answer:
        context = "\n\n".join(
            f"Тикет №{r['ticket_id']} ({r['category']}):\n{r['full_text']}"
            for r in reranked
        )
        answer = await generate_answer(body.query, context)

    return SearchResponse(answer=answer, sources=sources)
