"""
Strategy context module for maintaining isolated strategy state
"""

import logging
import threading
from typing import Any, Dict, List, Optional

from openfund_agent.models.trading import Position, OrderAction

logger = logging.getLogger(__name__)


class StrategyContext:
    """
    Strategy execution context for maintaining isolated state

    This class provides thread-safe state management for individual strategies,
    ensuring that concurrent strategy executions don't interfere with each other.
    """

    def __init__(self, strategy_id: str):
        """
        Initialize strategy context

        Args:
            strategy_id: Unique identifier for the strategy
        """
        self.strategy_id = strategy_id
        self.state: Dict[str, Any] = {}
        self.positions: List[Position] = []
        self.orders: List[OrderAction] = []
        self.lock = threading.Lock()

        logger.info(f"StrategyContext initialized for strategy: {strategy_id}")

    def get_state(self, key: str) -> Any:
        """
        Get strategy state value

        Thread-safe method to retrieve state values.

        Args:
            key: State key to retrieve

        Returns:
            State value, or None if key doesn't exist
        """
        with self.lock:
            value = self.state.get(key)
            logger.debug(f"[{self.strategy_id}] Get state '{key}': {value}")
            return value

    def set_state(self, key: str, value: Any) -> None:
        """
        Set strategy state value

        Thread-safe method to update state values.

        Args:
            key: State key to set
            value: Value to store
        """
        with self.lock:
            self.state[key] = value
            logger.debug(f"[{self.strategy_id}] Set state '{key}': {value}")

    def get_all_state(self) -> Dict[str, Any]:
        """
        Get all strategy state

        Returns:
            Copy of the entire state dictionary
        """
        with self.lock:
            return self.state.copy()

    def clear_state(self) -> None:
        """
        Clear all strategy state

        Thread-safe method to reset the strategy state.
        """
        with self.lock:
            self.state.clear()
            logger.info(f"[{self.strategy_id}] State cleared")

    def add_position(self, position: Position) -> None:
        """
        Add a position to the context

        Args:
            position: Position to add
        """
        with self.lock:
            self.positions.append(position)
            logger.debug(
                f"[{self.strategy_id}] Added position: {position.symbol} "
                f"{position.side} @ {position.entry_price}"
            )

    def get_positions(self) -> List[Position]:
        """
        Get all positions

        Returns:
            Copy of the positions list
        """
        with self.lock:
            return self.positions.copy()

    def update_position(self, symbol: str, side: str, **kwargs) -> bool:
        """
        Update an existing position

        Args:
            symbol: Trading pair symbol
            side: Position side ('long' | 'short')
            **kwargs: Fields to update

        Returns:
            True if position was found and updated, False otherwise
        """
        with self.lock:
            for position in self.positions:
                if position.symbol == symbol and position.side == side:
                    for key, value in kwargs.items():
                        if hasattr(position, key):
                            setattr(position, key, value)
                    logger.debug(f"[{self.strategy_id}] Updated position: {symbol} {side}")
                    return True
            return False

    def remove_position(self, symbol: str, side: str) -> bool:
        """
        Remove a position from the context

        Args:
            symbol: Trading pair symbol
            side: Position side ('long' | 'short')

        Returns:
            True if position was found and removed, False otherwise
        """
        with self.lock:
            for i, position in enumerate(self.positions):
                if position.symbol == symbol and position.side == side:
                    removed = self.positions.pop(i)
                    logger.debug(f"[{self.strategy_id}] Removed position: {symbol} {side}")
                    return True
            return False

    def clear_positions(self) -> None:
        """
        Clear all positions
        """
        with self.lock:
            count = len(self.positions)
            self.positions.clear()
            logger.info(f"[{self.strategy_id}] Cleared {count} positions")

    def add_order(self, order: OrderAction) -> None:
        """
        Add an order action to the context

        Args:
            order: Order action to add
        """
        with self.lock:
            self.orders.append(order)
            logger.debug(
                f"[{self.strategy_id}] Added order: {order.action_type} "
                f"{order.symbol} {order.side}"
            )

    def get_orders(self) -> List[OrderAction]:
        """
        Get all order actions

        Returns:
            Copy of the orders list
        """
        with self.lock:
            return self.orders.copy()

    def clear_orders(self) -> None:
        """
        Clear all order actions
        """
        with self.lock:
            count = len(self.orders)
            self.orders.clear()
            logger.info(f"[{self.strategy_id}] Cleared {count} orders")

    def get_summary(self) -> Dict[str, Any]:
        """
        Get a summary of the strategy context

        Returns:
            Dictionary containing context summary
        """
        with self.lock:
            return {
                "strategy_id": self.strategy_id,
                "state_keys": list(self.state.keys()),
                "num_positions": len(self.positions),
                "num_orders": len(self.orders),
                "positions": [
                    {
                        "symbol": p.symbol,
                        "side": p.side,
                        "entry_price": p.entry_price,
                        "quantity": p.quantity,
                        "unrealized_pnl": p.unrealized_pnl,
                    }
                    for p in self.positions
                ],
            }


class StrategyContextManager:
    """
    Manager for multiple strategy contexts

    This class manages multiple strategy contexts and provides thread-safe
    access to them.
    """

    def __init__(self):
        """Initialize the context manager"""
        self.contexts: Dict[str, StrategyContext] = {}
        self.lock = threading.Lock()
        logger.info("StrategyContextManager initialized")

    def get_context(self, strategy_id: str) -> StrategyContext:
        """
        Get or create a strategy context

        Args:
            strategy_id: Strategy identifier

        Returns:
            StrategyContext for the given strategy
        """
        with self.lock:
            if strategy_id not in self.contexts:
                self.contexts[strategy_id] = StrategyContext(strategy_id)
                logger.info(f"Created new context for strategy: {strategy_id}")
            return self.contexts[strategy_id]

    def remove_context(self, strategy_id: str) -> bool:
        """
        Remove a strategy context

        Args:
            strategy_id: Strategy identifier

        Returns:
            True if context was removed, False if it didn't exist
        """
        with self.lock:
            if strategy_id in self.contexts:
                del self.contexts[strategy_id]
                logger.info(f"Removed context for strategy: {strategy_id}")
                return True
            return False

    def list_contexts(self) -> List[str]:
        """
        List all strategy IDs with active contexts

        Returns:
            List of strategy IDs
        """
        with self.lock:
            return list(self.contexts.keys())

    def clear_all(self) -> None:
        """
        Clear all strategy contexts
        """
        with self.lock:
            count = len(self.contexts)
            self.contexts.clear()
            logger.info(f"Cleared all {count} strategy contexts")
