"""IAM 服务 gRPC 客户端.

用于：
  - 查询用户有效数据范围（GetEffectiveDataScope - ISSUE-07: P4 补全，ai 用 mock）

全并行模式：IAM 不可用时使用 mock 数据降级。
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Any

import structlog

logger = structlog.get_logger()


@dataclass
class DataScope:
    """用户有效数据范围（用于数据权限过滤）."""

    user_id: str
    school_id: str = ""
    class_ids: list[str] = None  # type: ignore[assignment]
    grade_ids: list[str] = None  # type: ignore[assignment]
    subject_ids: list[str] = None  # type: ignore[assignment]
    role: str = "teacher"
    is_admin: bool = False

    def __post_init__(self) -> None:
        if self.class_ids is None:
            self.class_ids = []
        if self.grade_ids is None:
            self.grade_ids = []
        if self.subject_ids is None:
            self.subject_ids = []

    def to_dict(self) -> dict[str, Any]:
        """转换为 dict（用于 JSON 序列化）."""
        return {
            "user_id": self.user_id,
            "school_id": self.school_id,
            "class_ids": self.class_ids,
            "grade_ids": self.grade_ids,
            "subject_ids": self.subject_ids,
            "role": self.role,
            "is_admin": self.is_admin,
        }


class IamClient(ABC):
    """IAM 服务客户端抽象接口（六边形端口）."""

    @abstractmethod
    async def get_effective_data_scope(
        self,
        user_id: str,
    ) -> DataScope:
        """查询用户有效数据范围.

        ISSUE-07: IAM P4 补全 GetEffectiveDataScope RPC 后启用真实调用。
        """
        ...

    @abstractmethod
    def is_available(self) -> bool:
        """客户端是否可用."""
        ...


class IamClientMock(IamClient):
    """IAM 客户端 Mock 实现（全并行模式）."""

    def __init__(self) -> None:
        self._available = True

    async def get_effective_data_scope(
        self,
        user_id: str,
    ) -> DataScope:
        logger.info("iam_mock_get_data_scope", user_id=user_id)
        return DataScope(
            user_id=user_id,
            school_id="school_mock_001",
            class_ids=["class_mock_001", "class_mock_002"],
            grade_ids=["grade_10"],
            subject_ids=["subject_math"],
            role="teacher",
            is_admin=False,
        )

    def is_available(self) -> bool:
        return self._available


class IamClientGrpc(IamClient):
    """IAM 服务 gRPC 客户端实现.

    ISSUE-07: IAM P4 补全 GetEffectiveDataScope RPC 后启用。
    全并行模式：当前使用 mock 数据。
    """

    def __init__(
        self,
        endpoint: str = "localhost:50052",
        request_id: str = "",
    ) -> None:
        self._endpoint = endpoint
        self._request_id = request_id
        self._channel: Any = None
        self._mock = IamClientMock()

    async def connect(self) -> None:
        """建立 gRPC 连接."""
        import grpc

        self._channel = grpc.aio.insecure_channel(self._endpoint)
        logger.info("iam_client_connected", endpoint=self._endpoint)

    async def close(self) -> None:
        """关闭 gRPC 连接."""
        if self._channel is not None:
            await self._channel.close()
            self._channel = None

    def is_available(self) -> bool:
        return self._channel is not None

    async def get_effective_data_scope(
        self,
        user_id: str,
    ) -> DataScope:
        # ISSUE-07: IAM P4 补全 GetEffectiveDataScope 后启用真实调用
        # 全并行模式：当前使用 mock
        return await self._mock.get_effective_data_scope(user_id)
