"""
SymbolRegistry — central lookup for per-instrument configuration.

Loads from config/instruments.json with hardcoded gold defaults as fallback.
"""

from __future__ import annotations

import json
import os
from pathlib import Path
from typing import Dict, Optional

from src.instruments.context import (
    AssetCategory,
    CorrelationSign,
    InstrumentContext,
    MacroDriverConfig,
)


# ── Hardcoded gold default (backward compatible) ──────────────────────

_GOLD_DEFAULT = InstrumentContext(
    symbol="XAUUSD",
    display_name="Gold vs US Dollar",
    asset_name="Gold",
    asset_category=AssetCategory.PRECIOUS_METAL,
    macro_driver=MacroDriverConfig(
        driver_symbol="DXY.f",
        correlation_sign=CorrelationSign.INVERSE,
        correlation_label="DXY USD Index",
        implication_lexicon={
            "favorable": "tailwind",
            "unfavorable": "headwind",
            "neutral": "neutral",
        },
        proxy_symbols=["USDJPY", "EURUSD", "USDCHF"],
        filter_params={
            "ema_smooth_period": 5,
            "roc_period": 20,
            "z_score_window": 50,
            "z_score_threshold": 0.8,
            "correlation_window": 50,
            "correlation_min_abs": 0.25,
            "direction_persistence": 3,
            "atr_period": 14,
        },
        session_weights={
            "ASIA": 0.5, "LONDON": 1.0, "NEW_YORK": 1.0,
            "ASIA_LONDON_OVERLAP": 1.2, "LONDON_NY_OVERLAP": 1.2,
            "WEEKEND_CLOSED": 0.0,
        },
    ),
    lot_step=0.01,
    min_lot=0.01,
    max_lot=0.20,
    slippage_points=10,
    atr_noise_threshold=1.0,
)


# ── Additional builtin instruments (extensible) ──────────────────────

_BUILTIN: Dict[str, InstrumentContext] = {
    "XAUUSD": _GOLD_DEFAULT,
    "EURUSD": InstrumentContext(
        symbol="EURUSD",
        display_name="Euro vs US Dollar",
        asset_name="Euro",
        asset_category=AssetCategory.FOREX_MAJOR,
        macro_driver=MacroDriverConfig(
            driver_symbol="DXY.f",
            correlation_sign=CorrelationSign.INVERSE,
            correlation_label="DXY USD Index",
            proxy_symbols=["USDJPY", "USDCHF"],
        ),
        lot_step=0.01, min_lot=0.01, max_lot=0.20, slippage_points=5,
    ),
    "US30": InstrumentContext(
        symbol="US30",
        display_name="Dow Jones Industrial Average",
        asset_name="US30 Index",
        asset_category=AssetCategory.INDEX,
        macro_driver=MacroDriverConfig(
            driver_symbol="TNX",
            correlation_sign=CorrelationSign.INVERSE,
            correlation_label="US 10Y Treasury Yield",
            proxy_symbols=["US10Y", "ZB"],
            filter_params={
                "ema_smooth_period": 5, "roc_period": 20,
                "z_score_window": 50, "z_score_threshold": 0.8,
                "correlation_window": 50, "correlation_min_abs": 0.2,
                "direction_persistence": 3, "atr_period": 14,
            },
        ),
        lot_step=1.0, min_lot=1.0, max_lot=5.0, slippage_points=3,
    ),
    "UKOIL": InstrumentContext(
        symbol="UKOIL",
        display_name="Brent Crude Oil",
        asset_name="Brent Oil",
        asset_category=AssetCategory.COMMODITY,
        macro_driver=MacroDriverConfig(
            driver_symbol="DXY.f",
            correlation_sign=CorrelationSign.INVERSE,
            correlation_label="DXY USD Index",
            proxy_symbols=["USDJPY", "EURUSD"],
        ),
        lot_step=0.01, min_lot=0.01, max_lot=0.10, slippage_points=5,
    ),
}


class SymbolRegistry:
    """Manages instrument configurations from builtins + JSON config."""

    def __init__(self):
        self._instruments: Dict[str, InstrumentContext] = dict(_BUILTIN)
        self._load_json_config()

    def _load_json_config(self) -> None:
        """Load additional instruments from config/instruments.json."""
        try:
            from config_manager import get_config_dir
            cfg_path = get_config_dir() / "instruments.json"
        except Exception:
            cfg_path = Path(os.environ.get(
                "GAT_INSTRUMENTS_CONFIG",
                str(Path.home() / "GoldAutoTradeData" / "config" / "instruments.json"),
            ))

        if not cfg_path.exists():
            return

        try:
            data = json.loads(cfg_path.read_text(encoding="utf-8"))
            instruments_list = data.get("instruments", [])
            if not isinstance(instruments_list, list):
                return
            for item in instruments_list:
                ctx = self._parse_instrument(item)
                if ctx:
                    self._instruments[ctx.symbol.upper()] = ctx
        except Exception:
            pass

    def _parse_instrument(self, data: dict) -> Optional[InstrumentContext]:
        """Parse a JSON instrument entry into an InstrumentContext."""
        try:
            symbol = str(data.get("symbol", "")).strip().upper()
            if not symbol:
                return None

            md_data = data.get("macro_driver")
            macro_driver = None
            if isinstance(md_data, dict) and md_data.get("driver_symbol"):
                macro_driver = MacroDriverConfig(
                    driver_symbol=str(md_data["driver_symbol"]),
                    correlation_sign=CorrelationSign(
                        str(md_data.get("correlation_sign", "inverse"))
                    ),
                    correlation_label=str(md_data.get("correlation_label", "")),
                    implication_lexicon=md_data.get("implication_lexicon", {
                        "favorable": "tailwind",
                        "unfavorable": "headwind",
                        "neutral": "neutral",
                    }),
                    proxy_symbols=md_data.get("proxy_symbols", []),
                    filter_params=md_data.get("filter_params", {}),
                    session_weights=md_data.get("session_weights", {}),
                )

            return InstrumentContext(
                symbol=symbol,
                display_name=str(data.get("display_name", symbol)),
                asset_name=str(data.get("asset_name", symbol)),
                asset_category=AssetCategory(
                    str(data.get("asset_category", "forex_major"))
                ),
                macro_driver=macro_driver,
                lot_step=float(data.get("lot_step", 0.01)),
                min_lot=float(data.get("min_lot", 0.01)),
                max_lot=float(data.get("max_lot", 0.20)),
                slippage_points=int(data.get("slippage_points", 10)),
                atr_noise_threshold=float(data.get("atr_noise_threshold", 1.0)),
                supported_timeframes=data.get("supported_timeframes", ["M5", "M15", "H1"]),
            )
        except Exception:
            return None

    def get(self, symbol: str) -> InstrumentContext:
        """Get instrument context for a symbol. Falls back to gold default."""
        key = str(symbol or "XAUUSD").strip().upper()
        return self._instruments.get(key, _GOLD_DEFAULT)

    def get_macro_driver(self, symbol: str) -> Optional[MacroDriverConfig]:
        """Get macro driver config for a symbol, or None."""
        ctx = self.get(symbol)
        return ctx.macro_driver

    def list_dxy_relevant(self) -> list[str]:
        """List all symbols that have DXY-based macro drivers."""
        return [
            sym for sym, ctx in self._instruments.items()
            if ctx.dxy_relevant
        ]

    def list_all(self) -> Dict[str, InstrumentContext]:
        return dict(self._instruments)

    @property
    def gold_default(self) -> InstrumentContext:
        return _GOLD_DEFAULT


# ── Singleton ──

_registry: Optional[SymbolRegistry] = None


def get_symbol_registry() -> SymbolRegistry:
    global _registry
    if _registry is None:
        _registry = SymbolRegistry()
    return _registry
