"""
app/repositories/base_workspace_repo.py — 多租户基础 Repo
所有 workspace 相关 Repo 继承此类，强制过滤 workspace_id（基石C）。
禁止 SELECT *，明确字段（db.md规范）。
"""

import logging
from typing import Any, Generic, TypeVar

from sqlalchemy import select
from sqlalchemy.orm import Session

from app.core.response import raise_not_found

logger = logging.getLogger(__name__)

T = TypeVar("T")


class BaseWorkspaceRepo(Generic[T]):
    """
    workspace 感知的基础 Repo。
    子类设置 model_class，所有查询自动注入 workspace_id 过滤。
    """

    model_class: type[T]

    def __init__(self, db: Session, workspace_id: int):
        self.db = db
        self.workspace_id = workspace_id

    def _base_query(self):
        """所有查询的基础：强制带 workspace_id 过滤（多租户红线）。"""
        return self.db.query(self.model_class).filter(
            self.model_class.workspace_id == self.workspace_id  # type: ignore[attr-defined]
        )

    def get_by_id(self, record_id: int) -> T | None:
        """按 ID 查单条，强制带 workspace_id 防越权读。"""
        return self._base_query().filter(
            self.model_class.id == record_id  # type: ignore[attr-defined]
        ).first()

    def get_by_id_or_404(self, record_id: int) -> T:
        obj = self.get_by_id(record_id)
        if not obj:
            raise_not_found(f"{self.model_class.__name__} {record_id} 不存在")
        return obj  # type: ignore[return-value]

    def list_all(
        self,
        offset: int = 0,
        limit: int = 20,
        filters: list[Any] | None = None,
    ) -> tuple[list[T], int]:
        """分页列表，返回 (items, total)。"""
        q = self._base_query()
        if filters:
            q = q.filter(*filters)
        total = q.count()
        items = q.offset(offset).limit(limit).all()
        return items, total

    def create(self, obj: T) -> T:
        """插入一条记录，自动设置 workspace_id。"""
        obj.workspace_id = self.workspace_id  # type: ignore[attr-defined]
        self.db.add(obj)
        self.db.flush()
        self.db.refresh(obj)
        logger.debug("Created %s id=%s ws=%s", self.model_class.__name__, obj.id, self.workspace_id)  # type: ignore[attr-defined]
        return obj

    def delete(self, obj: T) -> None:
        """物理删除（软删各子类自己处理 archived 态）。"""
        self.db.delete(obj)
        self.db.flush()

    def save(self) -> None:
        """提交事务，错误不静默（官网V1坑3）。"""
        try:
            self.db.commit()
        except Exception:
            self.db.rollback()
            logger.error("DB commit failed in %s ws=%s", self.model_class.__name__, self.workspace_id)
            raise
