from __future__ import annotations

import json
import os
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Mapping

from backend.bootstrap.config import APP_DIR


DATASETS = (
    "calendar",
    "stocks",
    "daily",
    "index_daily",
    "valuation",
    "moneyflow",
    "auction",
    "status",
)

ENV_DATASET = {
    "calendar": "CALENDAR",
    "stocks": "STOCKS",
    "daily": "DAILY",
    "index_daily": "INDEX_DAILY",
    "valuation": "VALUATION",
    "moneyflow": "MONEYFLOW",
    "auction": "AUCTION",
    "status": "STATUS",
}

DEFAULT_CONFIG_PATH = APP_DIR / "config" / "datahub.config.json"


def _truthy(value: Any) -> bool:
    return str(value or "").strip().lower() in {"1", "true", "yes", "on"}


def _int(value: Any, default: int) -> int:
    try:
        return int(value)
    except (TypeError, ValueError):
        return default


@dataclass(frozen=True)
class DatasetFlags:
    name: str
    read: bool = False
    shadow: bool = False


@dataclass(frozen=True)
class DatahubSettings:
    base_url: str
    token: str
    timeout_seconds: int = 8
    retries: int = 1
    page_limit: int = 5000
    stale_seconds_max: int = 86400
    datasets: dict[str, DatasetFlags] | None = None

    def flags(self, dataset: str) -> DatasetFlags:
        mapped = self.datasets or {}
        return mapped.get(dataset) or DatasetFlags(dataset)

    def any_enabled(self) -> bool:
        return any(item.read or item.shadow for item in (self.datasets or {}).values())

    def secrets(self) -> tuple[str, ...]:
        return tuple(item for item in (self.token,) if item)

    @classmethod
    def load(
        cls,
        path: Path | None = None,
        environ: Mapping[str, str] | None = None,
        credentials: Mapping[str, object] | None = None,
    ) -> "DatahubSettings":
        config_path = path or DEFAULT_CONFIG_PATH
        payload: dict[str, Any] = {}
        if config_path.is_file():
            payload = json.loads(config_path.read_text(encoding="utf-8"))
        env = dict(os.environ if environ is None else environ)
        creds = dict(credentials or {})
        dataset_flags: dict[str, DatasetFlags] = {}
        raw_datasets = payload.get("datasets") or {}
        for name in DATASETS:
            item = raw_datasets.get(name) or {}
            env_key = ENV_DATASET[name]
            read = _truthy(env.get(f"DATAHUB_READ_{env_key}")) if f"DATAHUB_READ_{env_key}" in env else bool(item.get("read"))
            shadow = (
                _truthy(env.get(f"DATAHUB_SHADOW_{env_key}"))
                if f"DATAHUB_SHADOW_{env_key}" in env
                else bool(item.get("shadow"))
            )
            dataset_flags[name] = DatasetFlags(name, read=read, shadow=shadow)
        token = str(
            env.get("DATAHUB_TOKEN")
            or creds.get("datahub_token")
            or payload.get("token")
            or ""
        ).strip()
        base_url = str(
            env.get("DATAHUB_BASE_URL")
            or creds.get("datahub_base_url")
            or payload.get("base_url")
            or "http://127.0.0.1:8766"
        ).strip().rstrip("/")
        return cls(
            base_url=base_url,
            token=token,
            timeout_seconds=_int(env.get("DATAHUB_TIMEOUT") or payload.get("timeout_seconds"), 8),
            retries=max(0, _int(env.get("DATAHUB_RETRIES") or payload.get("retries"), 1)),
            page_limit=max(1, _int(payload.get("page_limit"), 5000)),
            stale_seconds_max=max(0, _int(payload.get("stale_seconds_max"), 86400)),
            datasets=dataset_flags,
        )
