"""Module Registry - 模块注册中心

提供功能模块的动态注册、发现和管理能力。所有扩展模块（如 AI 配音、
多平台发布、去重检测等）通过此注册中心声明自身能力、依赖和配额消耗规则。

设计原则：
- 模块自描述：每个模块声明自己的能力、依赖、配额规则
- 松耦合：模块间通过注册中心间接通信，不直接依赖
- 可扩展：新模块只需注册即可被系统识别，无需修改核心代码
"""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Callable, Dict, List, Optional, Set

logger = logging.getLogger(__name__)


class ModuleStatus(str, Enum):
    """模块运行状态"""

    REGISTERED = "registered"  # 已注册，未激活
    ACTIVE = "active"  # 已激活，可用
    DISABLED = "disabled"  # 已禁用（管理员/Feature Flag 控制）
    ERROR = "error"  # 注册或初始化出错


@dataclass
class QuotaRule:
    """模块定义的配额消耗规则

    描述该模块消耗哪些配额维度，以及每个操作消耗多少。
    例如：AI 配音模块每生成一条配音消耗 1 个 ai_voice_credit。
    """

    dimension: str  # 配额维度名，如 "ai_voice_credits", "storage_gb"
    per_operation: float  # 每次操作消耗量
    description: str = ""  # 人类可读描述


@dataclass
class ModuleCapability:
    """模块声明的一个能力

    能力是模块对外暴露的可调用功能单元。
    """

    name: str  # 能力名，如 "generate_voice"
    description: str = ""  # 人类可读描述
    quota_rules: List[QuotaRule] = field(default_factory=list)  # 该能力消耗的配额规则
    metadata: Dict[str, Any] = field(default_factory=dict)  # 扩展元数据


@dataclass
class Module:
    """模块注册信息

    每个扩展模块通过 Module 描述自身，注册到 ModuleRegistry。
    """

    name: str  # 模块唯一标识，如 "ai_voice"
    version: str = "1.0.0"  # 模块版本
    description: str = ""  # 人类可读描述
    capabilities: List[ModuleCapability] = field(default_factory=list)
    dependencies: List[str] = field(default_factory=list)  # 依赖的其他模块名
    status: ModuleStatus = ModuleStatus.REGISTERED
    config: Dict[str, Any] = field(default_factory=dict)  # 模块配置
    _init_func: Optional[Callable] = field(default=None, repr=False)  # 初始化回调

    def activate(self) -> None:
        """激活模块"""
        if self.status == ModuleStatus.ERROR:
            logger.error(f"Cannot activate module '{self.name}': in error state")
            return
        self.status = ModuleStatus.ACTIVE
        logger.info(f"Module '{self.name}' v{self.version} activated")

    def disable(self) -> None:
        """禁用模块"""
        self.status = ModuleStatus.DISABLED
        logger.info(f"Module '{self.name}' disabled")


class ModuleRegistry:
    """模块注册中心

    单例模式，全局唯一实例（module_registry）。
    提供模块注册、发现、依赖检查、能力查询等功能。

    Usage:
        from packages.infrastructure.module_registry import module_registry

        # 注册模块
        module_registry.register(Module(
            name="ai_voice",
            version="1.0.0",
            description="AI 配音生成模块",
            capabilities=[
                ModuleCapability(
                    name="generate_voice",
                    description="文本转配音",
                    quota_rules=[QuotaRule("ai_voice_credits", 1.0, "每次配音消耗 1 积分")],
                ),
            ],
        ))

        # 查询
        mod = module_registry.get("ai_voice")
        has_cap = module_registry.has_capability("generate_voice")
    """

    def __init__(self) -> None:
        self._modules: Dict[str, Module] = {}

    def register(self, module: Module) -> None:
        """注册一个模块

        Args:
            module: 要注册的模块

        Raises:
            ValueError: 模块名已存在
        """
        if module.name in self._modules:
            raise ValueError(f"Module '{module.name}' already registered")

        # 检查依赖是否已注册
        for dep in module.dependencies:
            if dep not in self._modules:
                logger.warning(
                    f"Module '{module.name}' depends on '{dep}' which is not yet registered. "
                    f"Call check_dependencies() after all modules are registered."
                )

        self._modules[module.name] = module
        logger.info(f"Module '{module.name}' v{module.version} registered")

        # 自动尝试激活
        if self.check_dependencies(module.name):
            module.activate()

    def unregister(self, name: str) -> None:
        """注销一个模块"""
        if name not in self._modules:
            raise KeyError(f"Module '{name}' not found")

        # 检查是否有其他模块依赖它
        dependents = [m.name for m in self._modules.values() if name in m.dependencies and m.name != name]
        if dependents:
            raise ValueError(f"Cannot unregister module '{name}': depended on by {dependents}")

        del self._modules[name]
        logger.info(f"Module '{name}' unregistered")

    def get(self, name: str) -> Optional[Module]:
        """按名称获取模块，不存在返回 None"""
        return self._modules.get(name)

    def list_modules(self, status: Optional[ModuleStatus] = None) -> List[Module]:
        """列出所有模块，可按状态过滤"""
        modules = list(self._modules.values())
        if status is not None:
            modules = [m for m in modules if m.status == status]
        return modules

    def has_capability(self, capability_name: str) -> bool:
        """检查是否有任何已激活模块提供指定能力"""
        for module in self._modules.values():
            if module.status != ModuleStatus.ACTIVE:
                continue
            for cap in module.capabilities:
                if cap.name == capability_name:
                    return True
        return False

    def get_capability(self, capability_name: str) -> Optional[ModuleCapability]:
        """获取指定能力的定义，返回第一个匹配的"""
        for module in self._modules.values():
            if module.status != ModuleStatus.ACTIVE:
                continue
            for cap in module.capabilities:
                if cap.name == capability_name:
                    return cap
        return None

    def get_quota_rules(self, capability_name: str) -> List[QuotaRule]:
        """获取指定能力的配额消耗规则"""
        cap = self.get_capability(capability_name)
        if cap is None:
            return []
        return cap.quota_rules

    def check_dependencies(self, module_name: str) -> bool:
        """检查指定模块的所有依赖是否都已注册且激活"""
        module = self._modules.get(module_name)
        if module is None:
            return False
        for dep in module.dependencies:
            dep_module = self._modules.get(dep)
            if dep_module is None or dep_module.status != ModuleStatus.ACTIVE:
                return False
        return True

    def get_active_capabilities(self) -> Dict[str, List[str]]:
        """获取所有已激活模块的能力列表

        Returns:
            {module_name: [capability_name, ...]}
        """
        result = {}
        for module in self._modules.values():
            if module.status == ModuleStatus.ACTIVE and module.capabilities:
                result[module.name] = [cap.name for cap in module.capabilities]
        return result

    def clear(self) -> None:
        """清空所有注册（仅用于测试）"""
        self._modules.clear()


# 全局单例
module_registry = ModuleRegistry()
