from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import func, select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.core.dependencies import get_current_admin
from app.core.responses import api_success
from app.models.admin import Admin
from app.models.knowledge import (
    Knowledge,
    KnowledgeCard,
    KnowledgeChunk,
    KnowledgeManifest,
    KnowledgePublishLog,
    KnowledgeReviewRecord,
    KnowledgeSection,
    KnowledgeSourceSnapshot,
    KnowledgeSyncJob,
    KnowledgeVersion,
    UserKnowledgePermission,
)
from app.schemas.admin import KnowledgeSaveRequest
from app.services.admin_service import OperationLogService
from app.services.feishu_service import FeishuKnowledgeService
from app.api.pagination import page_result

router = APIRouter()


@router.get("/knowledge/list")
def list_knowledge(
    keyword: str = Query(default=""),
    knowledgeType: str = Query(default=""),
    openStatus: int | None = Query(default=None),
    sourceStatus: str = Query(default=""),
    page: int = Query(default=1, ge=1),
    pageSize: int = Query(default=20, ge=10, le=100),
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin),
) -> dict:
    query = select(Knowledge)
    if keyword:
        query = query.where((Knowledge.name.like(f"%{keyword}%")) | (Knowledge.source_title.like(f"%{keyword}%")))
    if knowledgeType:
        query = query.where(Knowledge.knowledge_type == knowledgeType)
    if openStatus is not None:
        query = query.where(Knowledge.status == openStatus)
    if sourceStatus:
        query = query.where(Knowledge.source_status == sourceStatus)
    total = db.scalar(select(func.count()).select_from(query.subquery())) or 0
    items = db.scalars(query.order_by(Knowledge.id.desc()).offset((page - 1) * pageSize).limit(pageSize)).all()
    return api_success(page_result([_knowledge_dict(item) for item in items], total=total, page=page, page_size=pageSize))


@router.get("/knowledge/options")
def knowledge_options(db: Session = Depends(get_db), current_admin: Admin = Depends(get_current_admin)) -> dict:
    items = db.scalars(select(Knowledge).where(Knowledge.lifecycle_status == "active").order_by(Knowledge.id.desc())).all()
    return api_success([_knowledge_dict(item) for item in items])


@router.post("/knowledge/resolve-node")
def resolve_knowledge_node(
    payload: dict,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin),
) -> dict:
    _require_super_admin(current_admin)
    node_id = str(payload.get("nodeId") or "").strip()
    if not node_id or len(node_id) > 100 or not node_id.replace("_", "").replace("-", "").isalnum():
        raise HTTPException(status_code=400, detail="Node ID 格式错误")
    existing = db.scalar(select(Knowledge).where(Knowledge.feishu_node_id == node_id))
    if existing is not None:
        raise HTTPException(status_code=409, detail=f"该 Node ID 已添加（知识库：{existing.name}）")
    try:
        info = FeishuKnowledgeService.get_node_info(node_id, db)
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"飞书节点信息获取失败：{exc}") from exc
    space_id, title = str(info.get("space_id") or "").strip(), str(info.get("title") or "").strip()
    if not space_id:
        raise HTTPException(status_code=422, detail="飞书接口未返回 Space ID，请检查节点是否移动或当前应用权限")
    if not title:
        raise HTTPException(status_code=422, detail="飞书接口未返回文章标题，请检查文章是否已删除")
    return api_success({"nodeId": node_id, "spaceId": space_id, "sourceTitle": title, "name": title, "remark": str(info.get("description") or ""), "objType": info.get("obj_type")})


@router.post("/knowledge/import")
def import_knowledge_from_space(
    payload: dict,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin),
) -> dict:
    _require_super_admin(current_admin)
    node_token = payload.get("node_token", "").strip()
    if not node_token:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="NodeToken 不能为空")

    info = FeishuKnowledgeService.get_node_info(node_token, db)
    space_id = info.get("space_id", "")
    if not space_id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"无法获取节点 {node_token} 的 SpaceID",
        )

    # 检查是否已存在
    existing = db.scalar(select(Knowledge).where(Knowledge.feishu_node_id == node_token))
    if existing is not None:
        return api_success({"imported": 0, "skipped": 1, "id": existing.id, "name": existing.name})

    knowledge = Knowledge(
        name=info.get("title", node_token),
        feishu_space_id=space_id,
        feishu_node_id=node_token,
        status=0,
        knowledge_type="general",
        review_mode="automatic",
        remark=f"obj_type={info.get('obj_type', '')}",
    )
    db.add(knowledge)
    db.flush()
    OperationLogService.write(
        db, admin_id=current_admin.id, module="knowledge", action="import", target_id=knowledge.id
    )
    try:
        db.commit()
    except IntegrityError as exc:
        db.rollback()
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="该飞书文章已创建知识库") from exc
    db.refresh(knowledge)
    return api_success({"imported": 1, "skipped": 0, "id": knowledge.id, "name": knowledge.name})


@router.post("/knowledge")
def create_knowledge(
    payload: KnowledgeSaveRequest,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin),
) -> dict:
    _require_super_admin(current_admin)
    existing = db.scalar(select(Knowledge).where(Knowledge.feishu_node_id == payload.feishuNodeId))
    if existing is not None:
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="该飞书文章已创建知识库")
    knowledge = Knowledge(
        name=payload.name,
        feishu_space_id=payload.feishuSpaceId,
        feishu_node_id=payload.feishuNodeId,
        status=0,
        remark=payload.remark,
        knowledge_type=payload.knowledgeType,
        review_mode="automatic",
    )
    db.add(knowledge)
    db.flush()
    OperationLogService.write(db, admin_id=current_admin.id, module="knowledge", action="create", target_id=knowledge.id)
    try:
        db.commit()
    except IntegrityError as exc:
        db.rollback()
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="该飞书文章已创建知识库") from exc
    db.refresh(knowledge)
    return api_success(_knowledge_dict(knowledge))


@router.put("/knowledge/{knowledge_id}")
def update_knowledge(
    knowledge_id: int,
    payload: KnowledgeSaveRequest,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin),
) -> dict:
    _require_super_admin(current_admin)
    knowledge = _get_knowledge(db, knowledge_id)
    knowledge.name = payload.name
    knowledge.remark = payload.remark
    knowledge.knowledge_type = payload.knowledgeType
    knowledge.review_mode = "automatic"
    db.add(knowledge)
    OperationLogService.write(db, admin_id=current_admin.id, module="knowledge", action="update", target_id=knowledge.id)
    db.commit()
    db.refresh(knowledge)
    return api_success(_knowledge_dict(knowledge))


@router.delete("/knowledge/{knowledge_id}")
def delete_knowledge(
    knowledge_id: int,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin),
) -> dict:
    _require_super_admin(current_admin)
    knowledge = _get_knowledge(db, knowledge_id)
    # 删除操作本身会立即停止开放并清理正式内容，不再要求管理员先执行“关闭、归档”两步。
    knowledge.status = 0
    knowledge.lifecycle_status = "archived"
    db.add(knowledge)
    db.flush()

    # 清理按用户授权口径留下的历史关联，避免外键阻止知识库删除。
    permissions = db.scalars(
        select(UserKnowledgePermission).where(UserKnowledgePermission.knowledge_id == knowledge.id)
    ).all()
    for permission in permissions:
        db.delete(permission)
    for model in (KnowledgeReviewRecord, KnowledgeCard, KnowledgeChunk, KnowledgeSection, KnowledgeManifest, KnowledgePublishLog, KnowledgeSyncJob):
        for row in db.scalars(select(model).where(model.knowledge_id == knowledge.id)).all():
            db.delete(row)
    db.flush()
    for row in db.scalars(select(KnowledgeVersion).where(KnowledgeVersion.knowledge_id == knowledge.id)).all():
        db.delete(row)
    db.flush()
    for row in db.scalars(select(KnowledgeSourceSnapshot).where(KnowledgeSourceSnapshot.knowledge_id == knowledge.id)).all():
        db.delete(row)
    OperationLogService.write(db, admin_id=current_admin.id, module="knowledge", action="delete", target_id=knowledge.id)
    db.delete(knowledge)
    try:
        db.commit()
    except IntegrityError as exc:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="知识库仍有关联数据，删除未执行，请刷新后重试",
        ) from exc
    return api_success()


def _get_knowledge(db: Session, knowledge_id: int) -> Knowledge:
    knowledge = db.get(Knowledge, knowledge_id)
    if knowledge is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="知识库不存在")
    return knowledge


def _require_super_admin(admin: Admin) -> None:
    if admin.role is not None and admin.role.code != "super_admin":
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="仅超级管理员可以管理知识库")


def _knowledge_dict(knowledge: Knowledge) -> dict:
    return {
        "id": knowledge.id,
        "name": knowledge.name,
        "feishuSpaceId": knowledge.feishu_space_id,
        "feishuNodeId": knowledge.feishu_node_id,
        "status": knowledge.status,
        "remark": knowledge.remark,
        "sourceTitle": knowledge.source_title,
        "knowledgeType": knowledge.knowledge_type,
        "lifecycleStatus": knowledge.lifecycle_status,
        "sourceStatus": knowledge.source_status,
        "sourceError": knowledge.source_error,
        "currentVersionId": knowledge.current_version_id,
        "lastSyncedAt": knowledge.last_synced_at,
        "lastPublishedAt": knowledge.last_published_at,
        "migrationStatus": knowledge.migration_status,
        "createdAt": knowledge.created_at,
        "updatedAt": knowledge.updated_at,
    }
