"""Per-KB 访问控制 — ACL 过滤逻辑。

遵循 filter_kb_sources_by_department 模式，实现 filter_kb_by_user_acl()。
ACL 变更必须触发检索缓存失效（KTD5）。
"""

from __future__ import annotations

import logging

from sqlalchemy import select

from agentkit.rag_platform.models import KBAclModel

logger = logging.getLogger(__name__)


async def filter_kb_by_user_acl(
    session_factory,
    user_id: str,
    all_kb_ids: list[str],
) -> list[str]:
    """返回用户有权访问的 KB ID 子集。

    权限规则：用户是 KB 的 owner 或 viewer 时有访问权限。
    与 filter_kb_sources_by_department 并行运行 — 部门过滤和 ACL 过滤取交集。

    Args:
        session_factory: SQLAlchemy async session factory
        user_id: 用户 ID
        all_kb_ids: 所有已知 KB ID（通常来自 KBStore.list_kbs()）

    Returns:
        排序后的授权 KB ID 列表
    """
    if not all_kb_ids:
        return []

    async with session_factory() as db:
        stmt = (
            select(KBAclModel.kb_id)
            .where(KBAclModel.user_id == user_id)
            .where(KBAclModel.kb_id.in_(all_kb_ids))
            .distinct()
        )
        result = await db.execute(stmt)
        authorized = {row[0] for row in result.all()}

    visible = authorized & set(all_kb_ids)
    return sorted(visible)


async def grant_access(
    session_factory,
    kb_id: str,
    user_id: str,
    role: str = "viewer",
) -> bool:
    """授予用户对 KB 的访问权限。

    Args:
        role: "owner" 或 "viewer"

    Returns:
        True 如果授权成功，False 如果已存在相同条目
    """
    from sqlalchemy import insert

    async with session_factory() as db:
        stmt = insert(KBAclModel).values(kb_id=kb_id, user_id=user_id, role=role)
        try:
            await db.execute(stmt)
            await db.commit()
            logger.info("Granted %s access to kb=%s for user=%s", role, kb_id, user_id)
            return True
        except Exception:  # UniqueConstraint violation — 已存在
            await db.rollback()
            return False


async def revoke_access(session_factory, kb_id: str, user_id: str) -> bool:
    """撤销用户对 KB 的访问权限。

    不会撤销 owner 的权限（owner 始终有访问权限）。
    ACL 变更后必须触发检索缓存失效。
    """
    from sqlalchemy import delete

    async with session_factory() as db:
        stmt = (
            delete(KBAclModel)
            .where(KBAclModel.kb_id == kb_id)
            .where(KBAclModel.user_id == user_id)
            .where(KBAclModel.role != "owner")  # 不撤销 owner
        )
        result = await db.execute(stmt)
        await db.commit()
        return result.rowcount > 0  # type: ignore[union-attr]


async def list_acl(session_factory, kb_id: str) -> list[dict]:
    """列出 KB 的所有 ACL 条目。"""
    async with session_factory() as db:
        stmt = select(KBAclModel).where(KBAclModel.kb_id == kb_id)
        result = await db.execute(stmt)
        return [
            {"user_id": row.user_id, "role": row.role, "created_at": row.created_at}
            for row in result.scalars().all()
        ]
