"""MT5 Data Hub — single entry point for all MT5 data access.

Eliminates the 15+ scattered terminal_status.json / market_snapshot.json
readers. All modules get MT5 data through this hub.

Usage:
    from src.mt5_data_hub import hub
    price = hub.get_price()
    positions = hub.get_positions()
    is_connected = hub.is_connected()
"""

from __future__ import annotations

import json
import threading
import time
from pathlib import Path
from typing import Any, Optional


def _resolve_mt5_common_files() -> Optional[Path]:
    """Single path resolution: from config_manager, no fallback spaghetti."""
    try:
        from config_manager import get_mt5_dir
        p = Path(get_mt5_dir())
        if p.exists():
            return p
    except Exception:
        pass
    return None


class MT5DataHub:
    """Thread-safe cached access to MT5 bridge data."""

    def __init__(self):
        self._lock = threading.Lock()
        self._cache: dict[str, Any] = {}
        self._cache_ts = 0.0
        self._ttl = 2.0  # max 2s cache for prices, 10s for positions

    def _mt5_dir(self) -> Optional[Path]:
        return _resolve_mt5_common_files()

    def _read_snapshot(self) -> Optional[dict[str, Any]]:
        """Read terminal_status.json from the resolved MT5 dir."""
        mt5 = self._mt5_dir()
        if not mt5:
            return None
        ts = mt5 / "gold_autotrade" / "bridge" / "terminal_status.json"
        if not ts.exists():
            ts = mt5 / "gold_autotrade" / "bridge" / "market_snapshot.json"
        if not ts.exists():
            return None
        try:
            return json.loads(ts.read_text(encoding="utf-8"))
        except Exception:
            return None

    def _cached_snapshot(self, force: bool = False) -> Optional[dict[str, Any]]:
        with self._lock:
            if not force and self._cache and time.time() - self._cache_ts < self._ttl:
                return self._cache
            snap = self._read_snapshot()
            if snap:
                self._cache = snap
                self._cache_ts = time.time()
            return snap

    # ── Public API ──

    def is_connected(self) -> bool:
        """Check if MT5 bridge data is available and fresh."""
        mt5 = self._mt5_dir()
        if not mt5:
            return False
        ts = mt5 / "gold_autotrade" / "bridge" / "terminal_status.json"
        if ts.exists():
            return (time.time() - ts.stat().st_mtime) < 120
        return False

    def get_symbol(self) -> str:
        """Get the active trading symbol from EA chart."""
        snap = self._cached_snapshot()
        if snap:
            return str(snap.get("symbol", "XAUUSD") or "XAUUSD").strip().upper()
        return "XAUUSD"

    def get_price(self) -> tuple[Optional[float], Optional[float], Optional[float], str, Optional[float]]:
        """Return (bid, ask, spread, source, age_seconds)."""
        snap = self._cached_snapshot()
        if not snap:
            return None, None, None, "error", None
        bid = float(snap.get("bid", 0) or 0)
        ask = float(snap.get("ask", 0) or 0)
        if bid <= 0 or ask <= 0:
            return None, None, None, "error", None
        spread = round(ask - bid, 5)
        age = time.time() - snap.get("_ts", self._cache_ts)
        return bid, ask, spread, "mt5", min(age, 999)

    def get_positions(self) -> list[dict[str, Any]]:
        """Get all open positions from MT5."""
        snap = self._cached_snapshot()
        if not snap:
            return []
        positions = snap.get("positions", [])
        positions_all = snap.get("positions_all", positions)
        return positions_all if isinstance(positions_all, list) else []

    def get_account(self) -> dict[str, Any]:
        """Get account info (balance, equity, login)."""
        snap = self._cached_snapshot()
        if not snap:
            return {}
        account_str = str(snap.get("account", "0") or "0")
        # Try to parse login from account field
        equity = 0.0
        try:
            import MetaTrader5 as mt5
            if mt5.initialize():
                acct = mt5.account_info()
                if acct:
                    equity = float(acct.equity)
        except Exception:
            pass
        return {
            "login": account_str,
            "equity": equity,
        }

    def get_bars(self, count: int = 200) -> list[dict[str, Any]]:
        """Get recent bar data."""
        snap = self._cached_snapshot()
        if not snap:
            return []
        bars = snap.get("bars", [])
        return (bars[-count:] if isinstance(bars, list) else [])

    def get_instruments(self) -> dict[str, Any]:
        """Get multi-instrument tick data."""
        snap = self._cached_snapshot()
        if not snap:
            return {}
        inst = snap.get("instruments", {})
        return inst if isinstance(inst, dict) else {}

    def refresh(self) -> None:
        """Force refresh the cached snapshot."""
        self._cached_snapshot(force=True)


# Global singleton
hub = MT5DataHub()
