"""Chain 所需持久化端口的组合根注册表。

Chain 只依赖本模块声明的工厂，不再直接导入数据库 Oper 或 ORM 模型。
具体适配器由 ``app.startup`` 在进程启动时装配，测试也可以登记隔离替身。
"""

from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, Optional


OperFactory = Callable[[], Any]


@dataclass(frozen=True, slots=True)
class ChainDataPorts:
    """跨领域 Chain 使用的最小持久化端口工厂集合。"""

    site: OperFactory
    subscribe: OperFactory
    workflow: OperFactory
    download_history: OperFactory
    transfer_history: OperFactory
    transfer_pending: OperFactory
    media_server: OperFactory
    download_failure: OperFactory
    user: OperFactory


class _PortProxyMeta(type):
    """让迁移期的 Oper 名称支持按方法打桩，同时仍转发到组合根端口。"""

    def __getattr__(cls, name: str) -> Any:
        """把类级方法访问转发到一个新的端口实例。"""
        return getattr(cls(), name)


class _ChainDataPortProxy(metaclass=_PortProxyMeta):
    """将旧的 Oper 调用形态转发到 Chain 数据端口的内部代理。"""

    port_name: str

    def __getattr__(self, name: str) -> Any:
        """转发未被测试替换的数据操作。"""
        return getattr(getattr(get_chain_data_ports(), self.port_name)(), name)


class SitePortProxy(_ChainDataPortProxy):
    """站点数据端口代理。"""

    port_name = "site"


class SubscribePortProxy(_ChainDataPortProxy):
    """订阅数据端口代理。"""

    port_name = "subscribe"


class WorkflowPortProxy(_ChainDataPortProxy):
    """工作流数据端口代理。"""

    port_name = "workflow"


class DownloadHistoryPortProxy(_ChainDataPortProxy):
    """下载历史数据端口代理。"""

    port_name = "download_history"


class TransferHistoryPortProxy(_ChainDataPortProxy):
    """整理历史数据端口代理。"""

    port_name = "transfer_history"


class TransferPendingPortProxy(_ChainDataPortProxy):
    """待整理数据端口代理。"""

    port_name = "transfer_pending"


class MediaServerPortProxy(_ChainDataPortProxy):
    """媒体服务器数据端口代理。"""

    port_name = "media_server"


class DownloadFailurePortProxy(_ChainDataPortProxy):
    """下载失败数据端口代理。"""

    port_name = "download_failure"


class UserPortProxy(_ChainDataPortProxy):
    """用户数据端口代理。"""

    port_name = "user"


_ports: Optional[ChainDataPorts] = None


def configure_chain_data_ports(**factories: OperFactory) -> None:
    """由启动组合根登记 Chain 的数据端口实现。"""
    required = {
        "site",
        "subscribe",
        "workflow",
        "download_history",
        "transfer_history",
        "transfer_pending",
        "media_server",
        "download_failure",
        "user",
    }
    missing = sorted(required - factories.keys())
    if missing:
        raise ValueError(f"Chain 数据端口缺少实现: {', '.join(missing)}")
    global _ports
    _ports = ChainDataPorts(**{name: factories[name] for name in required})


def get_chain_data_ports() -> ChainDataPorts:
    """返回启动阶段登记的 Chain 数据端口。"""
    if _ports is None:
        raise RuntimeError("Chain 数据端口尚未配置")
    return _ports


def get_chain_site_port() -> Any:
    """创建站点数据端口实例。"""
    return get_chain_data_ports().site()


def get_chain_subscribe_port() -> Any:
    """创建订阅数据端口实例。"""
    return get_chain_data_ports().subscribe()


def get_chain_workflow_port() -> Any:
    """创建工作流数据端口实例。"""
    return get_chain_data_ports().workflow()


def get_chain_download_history_port() -> Any:
    """创建下载历史数据端口实例。"""
    return get_chain_data_ports().download_history()


def get_chain_transfer_history_port() -> Any:
    """创建整理历史数据端口实例。"""
    return get_chain_data_ports().transfer_history()


def get_chain_transfer_pending_port() -> Any:
    """创建待整理数据端口实例。"""
    return get_chain_data_ports().transfer_pending()


def get_chain_media_server_port() -> Any:
    """创建媒体服务器数据端口实例。"""
    return get_chain_data_ports().media_server()


def get_chain_download_failure_port() -> Any:
    """创建下载失败数据端口实例。"""
    return get_chain_data_ports().download_failure()


def get_chain_user_port() -> Any:
    """创建用户数据端口实例。"""
    return get_chain_data_ports().user()
