"""
=========================================
CV6 AI Trading OS
Broker Manager
Production Version
=========================================
"""

import logging
from app.broker.broker_factory import BrokerFactory

logger = logging.getLogger(__name__)


class BrokerManager:

    def __init__(self):

        self.broker = None
        self.broker_name = None
        self.connected = False
        # Secondary registry: name → authenticated broker instance
        # Allows multiple brokers to be connected simultaneously.
        self._extra_brokers: dict = {}

    def register(self, name: str, broker_instance) -> None:
        """Store an already-authenticated broker so get_broker() can find it."""
        self._extra_brokers[name.lower()] = broker_instance
        logger.info("[BrokerManager] Registered secondary broker: %s", name)

    def connect(self, broker_name: str):

        try:

            self.broker = BrokerFactory.get_broker(
                broker_name
            )

            result = self.broker.connect()

            if result.get("success"):

                self.connected = True
                self.broker_name = broker_name

                # Also register in secondary registry so get_broker() finds it
                self._extra_brokers[broker_name.lower()] = self.broker

                # ── Start live feed for Angel One ─────────────────────────
                if broker_name.lower() in ("angelone", "angel_one", "angel"):
                    try:
                        from app.market.live_feed import live_feed
                        feed_ok = live_feed.connected
                        if not live_feed.connected:
                            feed_ok = live_feed.connect(self.broker)
                            if feed_ok:
                                logger.info(
                                    "[BrokerManager] Live feed started after "
                                    "manual Angel One connect ✅"
                                )
                        # PHASE-2.5 FIX (Goal 3): Phase 2 only wired the real
                        # feed into the WebSocket layer from main.py's startup
                        # auto-connect thread — a broker connected manually
                        # here (e.g. the user clicks "Connect" in the UI
                        # because auto-connect wasn't configured/failed) never
                        # got the bridge wired, so /ws/* stayed simulated
                        # forever even with a fully live broker. Always
                        # (re)wire it here too — idempotent, safe to call
                        # every time this path connects.
                        if feed_ok:
                            from app.websocket.market_stream import connect_angel_one_feed
                            connect_angel_one_feed()
                    except Exception as fe:
                        logger.warning(
                            "[BrokerManager] Live feed start failed: %s", fe
                        )

            return result

        except Exception as e:

            self.connected = False

            return {
                "success": False,
                "message": str(e)
            }

    def disconnect(self):

        try:

            if self.broker:

                self.broker.disconnect()

            self.broker = None
            self.broker_name = None
            self.connected = False

            return {
                "success": True
            }

        except Exception as e:

            return {
                "success": False,
                "message": str(e)
            }

    def is_connected(self):

        return self.connected

    def get_broker_name(self):

        return self.broker_name

    def get_broker(self, broker_name: str = None):
        """Return connected broker instance by name.

        Priority:
        1. Primary broker (self.broker) if name matches
        2. Secondary registry (_extra_brokers) — authenticated instances
        3. BrokerFactory fallback — creates a NEW unauthenticated instance (last resort)
        """
        if broker_name:
            key = broker_name.lower()
            # 1. Primary broker match
            if self.connected and self.broker_name and self.broker_name.lower() == key:
                return self.broker
            # 2. Secondary registry (already authenticated)
            if key in self._extra_brokers:
                return self._extra_brokers[key]
            # 3. Factory fallback (unauthenticated — will likely fail at order time)
            try:
                logger.warning(
                    "get_broker(%s): no authenticated instance found, "
                    "creating unauthenticated fallback", broker_name
                )
                return BrokerFactory.get_broker(key)
            except Exception as e:
                logger.warning("get_broker(%s) failed: %s", broker_name, e)
        return self.broker

    def profile(self):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.profile()

    def funds(self):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.funds()

    def holdings(self):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.holdings()

    def positions(self):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.positions()

    def orders(self):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.orders()

    def place_order(self, order: dict):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.place_order(order)

    def modify_order(self, order_id: str, order: dict):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.modify_order(
            order_id,
            order
        )

    def cancel_order(self, order_id: str):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.cancel_order(order_id)

    def quotes(self, symbol: dict):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.quotes(symbol)

    def historical_data(self, params: dict):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.historical_data(params)

    def live_data(self, symbol: dict):

        if not self.connected:

            return {
                "success": False,
                "message": "Broker not connected"
            }

        return self.broker.live_data(symbol)