from __future__ import annotations

from pathlib import Path

from datahub.adapters.tushare import TushareAdapter
from datahub.admin_api import AdminAPI
from datahub.auth import AuthService
from datahub.crypto import SecretVault
from datahub.db import HubDB
from datahub.governance.circuit import CircuitBreaker
from datahub.governance.lkg import LastKnownGood
from datahub.governance.ratelimit import TokenBucket
from datahub.pipeline import Pipeline
from datahub.scheduler import Scheduler
from datahub.serving import V1API
from datahub.settings import Settings, load_settings


class Hub:
    def __init__(self, settings: Settings, adapter: TushareAdapter | None = None) -> None:
        if not settings.encryption_key:
            raise SystemExit("DATAHUB_ENCRYPTION_KEY 未配置")
        self.settings = settings
        self.db = HubDB(settings.db_path)
        self.vault = SecretVault(settings.encryption_key)
        self.auth = AuthService(self.db, self.vault, settings.api_token, settings.admin_password)
        token = settings.tushare_token or self.auth.load_credential("tushare_token")
        if settings.tushare_token:
            self.auth.store_credential("tushare_token", settings.tushare_token)
            token = settings.tushare_token
        self.adapter = adapter or TushareAdapter(token)
        self.pipeline = Pipeline(
            self.db,
            self.adapter,
            settings,
            bucket=TokenBucket(settings.tushare_rate_per_minute),
            breaker=CircuitBreaker(),
        )
        self.lkg = LastKnownGood(self.db)
        self.scheduler = Scheduler(self.db, self.pipeline)
        self.api = V1API(self.db, self.pipeline, settings)
        self.admin = AdminAPI(self.db, self.pipeline, self.scheduler, self.auth)
        self.static_dir = Path(__file__).resolve().parents[1] / "admin"

    def start(self) -> None:
        if self.settings.scheduler_enabled:
            self.scheduler.start()

    def stop(self) -> None:
        self.scheduler.stop()


def build_hub(settings: Settings | None = None) -> Hub:
    return Hub(settings or load_settings())
