"""宿主 Module 的渐进式集成质量清单。"""

from __future__ import annotations

from dataclasses import dataclass
from enum import StrEnum


class ModuleQualityLevel(StrEnum):
    """描述模块当前接受的质量门禁等级。"""

    LEGACY = "legacy"
    ASSESSED = "assessed"


@dataclass(frozen=True, slots=True)
class ModuleQualityProfile:
    """记录一个模块已验证规则、维护者和精确豁免原因。"""

    module: str
    level: ModuleQualityLevel
    owner: str
    verified_rules: frozenset[str] = frozenset()
    exemption_reason: str | None = None


QUALITY_RULES = frozenset(
    {
        "fake-client-or-fixture",
        "zero-real-network-tests",
        "sync-async-boundary",
        "no-blocking-io-in-event-loop",
        "auth-rate-timeout-offline-semantics",
        "bounded-concurrency-or-polling",
        "reload-stop-idempotent",
        "module-contract-v2",
        "sensitive-log-redaction",
        "owner-declared",
    }
)

COMMON_ASSESSED_RULES = frozenset(
    {
        "zero-real-network-tests",
        "no-blocking-io-in-event-loop",
        "module-contract-v2",
        "owner-declared",
    }
)

# 这些模块均已纳入全局真实网络守卫、async 阻塞扫描和 V2 方法契约门禁。
# 模块专属的鉴权、限流、并发和生命周期规则仍按 profile 中的精确豁免逐项补强，
# 但不再使用无法区分“未审查”和“已审查有缺口”的 legacy 状态。
BASELINE_ASSESSED_MODULES = frozenset(
    {
        "acoustid",
        "anilist",
        "discord",
        "douban",
        "emby",
        "fanart",
        "feishu",
        "filemanager",
        "filter",
        "imdb",
        "indexer",
        "jellyfin",
        "listenbrainz",
        "lrclib",
        "musicbrainz",
        "navidrome",
        "plex",
        "postgresql",
        "qbittorrent",
        "qqbot",
        "redis",
        "rtorrent",
        "slack",
        "subtitle",
        "synologychat",
        "telegram",
        "theaudiodb",
        "themoviedb",
        "thetvdb",
        "transmission",
        "trimemedia",
        "ugreen",
        "vocechat",
        "webpush",
        "wechat",
        "wechatclawbot",
        "zspace",
    }
)

MODULE_QUALITY_PROFILES = {
    module: ModuleQualityProfile(
        module=module,
        level=ModuleQualityLevel.ASSESSED,
        owner="MoviePilot core",
        verified_rules=COMMON_ASSESSED_RULES,
        exemption_reason=(
            "已完成宿主通用网络、异步阻塞、V2 方法契约与维护责任门禁；"
            "模块专属鉴权、限流、并发、敏感日志及 reload/stop 语义只在有对应能力时适用，"
            "继续由各模块专项测试证明"
        ),
    )
    for module in BASELINE_ASSESSED_MODULES
}

MODULE_QUALITY_PROFILES.update({
    "bangumi": ModuleQualityProfile(
        module="bangumi",
        level=ModuleQualityLevel.ASSESSED,
        owner="MoviePilot core",
        verified_rules=frozenset(
            {
                "fake-client-or-fixture",
                "zero-real-network-tests",
                "sync-async-boundary",
                "reload-stop-idempotent",
                "module-contract-v2",
                "sensitive-log-redaction",
                "owner-declared",
            }
        ),
        exemption_reason=(
            "外部 Bangumi API 的限流与并发策略仍沿用通用 HTTP adapter；"
            "本轮仅对配置快照改动面启用 assessed 门禁"
        ),
    ),
    "dingtalk": ModuleQualityProfile(
        module="dingtalk",
        level=ModuleQualityLevel.ASSESSED,
        owner="MoviePilot core",
        verified_rules=frozenset(
            {
                "fake-client-or-fixture",
                "zero-real-network-tests",
                "reload-stop-idempotent",
                "module-contract-v2",
                "sensitive-log-redaction",
                "owner-declared",
            }
        ),
        exemption_reason=(
            "钉钉自定义机器人仅提供同步出站 Webhook，不包含长连接、轮询或入站回调"
        ),
    ),
})


def get_module_quality_profile(module: str) -> ModuleQualityProfile:
    """返回显式 profile；未迁移模块以带原因的 legacy 视图呈现。"""
    return MODULE_QUALITY_PROFILES.get(
        module,
        ModuleQualityProfile(
            module=module,
            level=ModuleQualityLevel.LEGACY,
            owner="MoviePilot core",
            exemption_reason="存量模块尚未在二阶段任务中修改，按渐进策略暂不提升门禁",
        ),
    )
