from __future__ import annotations

from dataclasses import dataclass

from backend.data.contracts import DataSource, DataUsage


class DataPolicyError(RuntimeError):
    pass


@dataclass(frozen=True, slots=True)
class DataSourcePolicy:
    calculation_sources: frozenset[DataSource] = frozenset(
        {DataSource.TUSHARE, DataSource.IFIND, DataSource.LOCAL}
    )
    display_sources: frozenset[DataSource] = frozenset(DataSource)

    def assert_allowed(self, source: DataSource, usage: DataUsage) -> None:
        allowed = (
            self.calculation_sources if usage is DataUsage.CALCULATION else self.display_sources
        )
        if source not in allowed:
            raise DataPolicyError(f"{source.value} cannot be used for {usage.value}")

    def candidates(self, dataset: str, usage: DataUsage) -> tuple[DataSource, ...]:
        routes = {
            ("calendar", DataUsage.CALCULATION): (DataSource.TUSHARE,),
            ("entities", DataUsage.CALCULATION): (DataSource.TUSHARE,),
            ("daily_chart", DataUsage.DISPLAY): (DataSource.IFIND, DataSource.TUSHARE),
            ("minute_chart", DataUsage.DISPLAY): (DataSource.IFIND, DataSource.EASTMONEY),
            ("realtime_quote", DataUsage.CALCULATION): (DataSource.IFIND, DataSource.TUSHARE),
            ("market_insight", DataUsage.CALCULATION): (DataSource.TUSHARE,),
            ("dynamic_auction", DataUsage.CALCULATION): (DataSource.IFIND,),
            ("screener_factors", DataUsage.CALCULATION): (DataSource.TUSHARE,),
        }
        return routes.get((dataset, usage), ())
