from fastapi import APIRouter, Depends, HTTPException, Request, status
from sqlalchemy.orm import Session

from app.api.deps import get_db
from app.api.permissions import require_create, require_delete, require_read, require_update
from app.core.exceptions import CategoryNotFoundError, KnowledgeBaseNotFoundError
from app.core.i18n import get_translator
from app.models import KnowledgeBase, KnowledgeCategory, KnowledgeDocument, KnowledgeQA, User
from app.schemas import KnowledgeCategoryCreate, KnowledgeCategoryResponse, KnowledgeCategoryUpdate
from common_logging import get_logger

logger = get_logger(__name__)
router = APIRouter(tags=["knowledge-categories"])


def get_category_doc_count(db: Session, category_id: int) -> int:
    return db.query(KnowledgeDocument).filter(KnowledgeDocument.category_id == category_id).count()


def get_category_qa_count(db: Session, category_id: int) -> int:
    return db.query(KnowledgeQA).filter(KnowledgeQA.category_id == category_id).count()


@router.get("/", response_model=list[KnowledgeCategoryResponse])
def get_categories(
    search: str | None = None,
    knowledge_base_id: int | None = None,
    parent_id: int | None = None,
    page: int = 1,
    page_size: int = 50,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_read("knowledge_categories")),
):
    kb_query = db.query(KnowledgeBase.id)
    allowed_kb_ids = [kb_id[0] for kb_id in kb_query.all()]
    query = db.query(KnowledgeCategory)
    if allowed_kb_ids:
        query = query.filter(KnowledgeCategory.knowledge_base_id.in_(allowed_kb_ids))
    else:
        return []
    if search:
        query = query.filter(KnowledgeCategory.name.contains(search))
    if knowledge_base_id:
        query = query.filter(KnowledgeCategory.knowledge_base_id == knowledge_base_id)
    if parent_id is not None:
        query = query.filter(KnowledgeCategory.parent_id == parent_id)
    query.count()
    categories = (
        query.order_by(KnowledgeCategory.sort_order.asc(), KnowledgeCategory.created_at.desc())
        .offset((page - 1) * page_size)
        .limit(page_size)
        .all()
    )
    result = []
    for cat in categories:
        kb_name = None
        if cat.knowledge_base_id:
            kb = db.query(KnowledgeBase).filter(KnowledgeBase.id == cat.knowledge_base_id).first()
            if kb:
                kb_name = kb.name
        parent_name = None
        if cat.parent_id:
            parent = (
                db.query(KnowledgeCategory).filter(KnowledgeCategory.id == cat.parent_id).first()
            )
            if parent:
                parent_name = parent.name
        doc_count = get_category_doc_count(db, cat.id)
        qa_count = get_category_qa_count(db, cat.id)
        logger.info(f"Category {cat.id} ({cat.name}): doc_count={doc_count}, qa_count={qa_count}")
        result.append(
            KnowledgeCategoryResponse(
                id=cat.id,
                knowledge_base_id=cat.knowledge_base_id,
                knowledge_base_name=kb_name,
                name=cat.name,
                description=cat.description,
                parent_id=cat.parent_id,
                parent_name=parent_name,
                icon=cat.icon,
                color=cat.color,
                sort_order=cat.sort_order,
                doc_count=doc_count,
                qa_count=qa_count,
                document_count=doc_count,
                created_at=cat.created_at,
                updated_at=cat.updated_at,
            )
        )
    logger.info(
        f"Returning {len(result)} categories for user {current_user.id} (role: {current_user.role})"
    )
    return result


@router.get("/{category_id}", response_model=KnowledgeCategoryResponse)
def get_category(
    category_id: int,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_read("knowledge_categories")),
):
    get_translator(request)
    cat = db.query(KnowledgeCategory).filter(KnowledgeCategory.id == category_id).first()
    if not cat:
        raise CategoryNotFoundError(category_id)
    kb_name = None
    if cat.knowledge_base_id:
        kb = db.query(KnowledgeBase).filter(KnowledgeBase.id == cat.knowledge_base_id).first()
        if kb:
            kb_name = kb.name
    parent_name = None
    if cat.parent_id:
        parent = db.query(KnowledgeCategory).filter(KnowledgeCategory.id == cat.parent_id).first()
        if parent:
            parent_name = parent.name
    doc_count = get_category_doc_count(db, cat.id)
    qa_count = get_category_qa_count(db, cat.id)
    return KnowledgeCategoryResponse(
        id=cat.id,
        knowledge_base_id=cat.knowledge_base_id,
        knowledge_base_name=kb_name,
        name=cat.name,
        description=cat.description,
        parent_id=cat.parent_id,
        parent_name=parent_name,
        icon=cat.icon,
        color=cat.color,
        sort_order=cat.sort_order,
        doc_count=doc_count,
        qa_count=qa_count,
        document_count=doc_count,
        created_at=cat.created_at,
        updated_at=cat.updated_at,
    )


@router.post("/", response_model=KnowledgeCategoryResponse, status_code=status.HTTP_201_CREATED)
def create_category(
    category: KnowledgeCategoryCreate,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_create("knowledge_categories")),
):
    get_translator(request)
    if category.knowledge_base_id:
        kb = db.query(KnowledgeBase).filter(KnowledgeBase.id == category.knowledge_base_id).first()
        if not kb:
            raise KnowledgeBaseNotFoundError(category.knowledge_base_id)
    if category.parent_id:
        parent = (
            db.query(KnowledgeCategory).filter(KnowledgeCategory.id == category.parent_id).first()
        )
        if not parent:
            raise CategoryNotFoundError(category.parent_id)
    db_category = KnowledgeCategory(**category.model_dump())
    db.add(db_category)
    db.commit()
    db.refresh(db_category)
    logger.info("Category created", category_id=db_category.id, category_name=db_category.name)
    return get_category(db_category.id, request, db, current_user)


@router.put("/{category_id}", response_model=KnowledgeCategoryResponse)
def update_category(
    category_id: int,
    category: KnowledgeCategoryUpdate,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_update("knowledge_categories")),
):
    t = get_translator(request)
    db_category = db.query(KnowledgeCategory).filter(KnowledgeCategory.id == category_id).first()
    if not db_category:
        raise CategoryNotFoundError(category_id)
    if category.knowledge_base_id:
        kb = db.query(KnowledgeBase).filter(KnowledgeBase.id == category.knowledge_base_id).first()
        if not kb:
            raise KnowledgeBaseNotFoundError(category.knowledge_base_id)
    if category.parent_id:
        if category.parent_id == category_id:
            raise HTTPException(
                status_code=400, detail=t.t("knowledge_category.cannot_set_self_as_parent")
            )
        parent = (
            db.query(KnowledgeCategory).filter(KnowledgeCategory.id == category.parent_id).first()
        )
        if not parent:
            raise CategoryNotFoundError(category.parent_id)
    update_data = category.model_dump(exclude_unset=True)
    for key, value in update_data.items():
        setattr(db_category, key, value)
    db.commit()
    db.refresh(db_category)
    logger.info("Category updated", category_id=category_id, category_name=db_category.name)
    return get_category(category_id, request, db, current_user)


@router.delete("/{category_id}", status_code=status.HTTP_200_OK)
def delete_category(
    category_id: int,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(require_delete("knowledge_categories")),
):
    t = get_translator(request)
    db_category = db.query(KnowledgeCategory).filter(KnowledgeCategory.id == category_id).first()
    if not db_category:
        raise CategoryNotFoundError(category_id)
    children = (
        db.query(KnowledgeCategory).filter(KnowledgeCategory.parent_id == category_id).count()
    )
    if children > 0:
        raise HTTPException(status_code=400, detail=t.t("knowledge_category.has_children"))
    doc_count = get_category_doc_count(db, category_id)
    if doc_count > 0:
        raise HTTPException(
            status_code=400, detail=t.t("knowledge_category.has_documents", count=doc_count)
        )
    db.delete(db_category)
    db.commit()
    logger.info("Category deleted", category_id=category_id)
    return {"success": True, "message": t.t("knowledge_category.category_deleted")}
