"""Advanced order types: take-profit, trailing stop, OCO, iceberg orders."""

from decimal import Decimal
from typing import Optional, Dict, Any, List
from datetime import datetime
from src.core.database import Order, OrderType, OrderSide, OrderStatus
from src.core.logger import get_logger
from .order_manager import get_order_manager

logger = get_logger(__name__)


class TakeProfitOrder:
    """Take-profit order - automatically sells when price reaches target."""
    
    def __init__(
        self,
        base_order_id: int,
        target_price: Decimal,
        quantity: Optional[Decimal] = None
    ):
        """Initialize take-profit order.
        
        Args:
            base_order_id: ID of the base position/order
            target_price: Target price to trigger take-profit
            quantity: Quantity to sell (None = all)
        """
        self.base_order_id = base_order_id
        self.target_price = target_price
        self.quantity = quantity
        self.triggered = False
    
    def check_trigger(self, current_price: Decimal) -> bool:
        """Check if take-profit should trigger.
        
        Args:
            current_price: Current market price
            
        Returns:
            True if should trigger
        """
        if self.triggered:
            return False
        
        # Trigger if price reaches or exceeds target
        if current_price >= self.target_price:
            self.triggered = True
            return True
        return False


class TrailingStopOrder:
    """Trailing stop-loss order - adjusts stop price as price moves favorably."""
    
    def __init__(
        self,
        base_order_id: int,
        initial_stop_price: Decimal,
        trail_percent: Decimal,
        quantity: Optional[Decimal] = None
    ):
        """Initialize trailing stop order.
        
        Args:
            base_order_id: ID of the base position/order
            initial_stop_price: Initial stop price
            trail_percent: Percentage to trail (e.g., 0.02 for 2%)
            quantity: Quantity to sell (None = all)
        """
        self.base_order_id = base_order_id
        self.current_stop_price = initial_stop_price
        self.trail_percent = trail_percent
        self.quantity = quantity
        self.triggered = False
        self.highest_price = initial_stop_price  # For long positions
    
    def update(self, current_price: Decimal, is_long: bool = True):
        """Update trailing stop based on current price.
        
        Args:
            current_price: Current market price
            is_long: True for long position, False for short
        """
        if self.triggered:
            return
        
        if is_long:
            # For long positions, trail upward
            if current_price > self.highest_price:
                self.highest_price = current_price
                # Adjust stop to trail below highest price
                self.current_stop_price = current_price * (1 - self.trail_percent)
        else:
            # For short positions, trail downward
            if current_price < self.highest_price or self.highest_price == self.current_stop_price:
                self.highest_price = current_price
                # Adjust stop to trail above lowest price
                self.current_stop_price = current_price * (1 + self.trail_percent)
    
    def check_trigger(self, current_price: Decimal, is_long: bool = True) -> bool:
        """Check if trailing stop should trigger.
        
        Args:
            current_price: Current market price
            is_long: True for long position, False for short
            
        Returns:
            True if should trigger
        """
        if self.triggered:
            return False
        
        if is_long:
            # Trigger if price falls below stop
            if current_price <= self.current_stop_price:
                self.triggered = True
                return True
        else:
            # Trigger if price rises above stop
            if current_price >= self.current_stop_price:
                self.triggered = True
                return True
        
        return False


class OCOOrder:
    """One-Cancels-Other order - two orders where one cancels the other."""
    
    def __init__(
        self,
        order1_id: int,
        order2_id: int
    ):
        """Initialize OCO order.
        
        Args:
            order1_id: First order ID
            order2_id: Second order ID
        """
        self.order1_id = order1_id
        self.order2_id = order2_id
        self.executed = False
    
    async def on_order_filled(self, filled_order_id: int):
        """Handle when one order is filled.
        
        Args:
            filled_order_id: ID of the filled order
        """
        if self.executed:
            return
        
        order_manager = get_order_manager()
        
        # Cancel the other order
        if filled_order_id == self.order1_id:
            await order_manager.cancel_order(self.order2_id)
        elif filled_order_id == self.order2_id:
            await order_manager.cancel_order(self.order1_id)
        
        self.executed = True
        logger.info(f"OCO order executed: order {filled_order_id} filled, other cancelled")


class IcebergOrder:
    """Iceberg order - large order split into smaller visible parts."""
    
    def __init__(
        self,
        total_quantity: Decimal,
        visible_quantity: Decimal,
        symbol: str,
        side: OrderSide,
        price: Optional[Decimal] = None
    ):
        """Initialize iceberg order.
        
        Args:
            total_quantity: Total quantity to execute
            visible_quantity: Visible quantity per order
            symbol: Trading symbol
            side: Buy or sell
            price: Limit price (None for market)
        """
        self.total_quantity = total_quantity
        self.visible_quantity = visible_quantity
        self.symbol = symbol
        self.side = side
        self.price = price
        self.remaining_quantity = total_quantity
        self.orders: List[int] = []
        self.completed = False
    
    async def create_next_order(self, exchange_id: int) -> Optional[int]:
        """Create next visible order.
        
        Args:
            exchange_id: Exchange ID
            
        Returns:
            Order ID or None if completed
        """
        if self.completed or self.remaining_quantity <= 0:
            return None
        
        order_manager = get_order_manager()
        order_type = OrderType.LIMIT if self.price else OrderType.MARKET
        
        quantity = min(self.visible_quantity, self.remaining_quantity)
        
        order = await order_manager.create_order(
            exchange_id=exchange_id,
            strategy_id=None,
            symbol=self.symbol,
            order_type=order_type,
            side=self.side,
            quantity=quantity,
            price=self.price
        )
        
        self.orders.append(order.id)
        self.remaining_quantity -= quantity
        
        if self.remaining_quantity <= 0:
            self.completed = True
        
        return order.id
    
    async def on_order_filled(self, order_id: int):
        """Handle when an order is filled.
        
        Args:
            order_id: Filled order ID
        """
        if order_id in self.orders:
            # Create next order if more quantity remains
            if not self.completed and self.remaining_quantity > 0:
                # This would need exchange_id - would need to store it
                logger.info(f"Iceberg order {order_id} filled, {self.remaining_quantity} remaining")


class AdvancedOrderManager:
    """Manages advanced order types."""
    
    def __init__(self):
        """Initialize advanced order manager."""
        self.take_profit_orders: Dict[int, TakeProfitOrder] = {}
        self.trailing_stops: Dict[int, TrailingStopOrder] = {}
        self.oco_orders: Dict[int, OCOOrder] = {}
        self.iceberg_orders: Dict[int, IcebergOrder] = {}
    
    def create_take_profit(
        self,
        base_order_id: int,
        target_price: Decimal,
        quantity: Optional[Decimal] = None
    ) -> TakeProfitOrder:
        """Create a take-profit order.
        
        Args:
            base_order_id: Base order/position ID
            target_price: Target price
            quantity: Quantity (None = all)
            
        Returns:
            TakeProfitOrder instance
        """
        tp_order = TakeProfitOrder(base_order_id, target_price, quantity)
        self.take_profit_orders[base_order_id] = tp_order
        logger.info(f"Created take-profit for order {base_order_id} at {target_price}")
        return tp_order
    
    def create_trailing_stop(
        self,
        base_order_id: int,
        initial_stop_price: Decimal,
        trail_percent: Decimal,
        quantity: Optional[Decimal] = None
    ) -> TrailingStopOrder:
        """Create a trailing stop order.
        
        Args:
            base_order_id: Base order/position ID
            initial_stop_price: Initial stop price
            trail_percent: Trail percentage
            quantity: Quantity (None = all)
            
        Returns:
            TrailingStopOrder instance
        """
        trailing = TrailingStopOrder(base_order_id, initial_stop_price, trail_percent, quantity)
        self.trailing_stops[base_order_id] = trailing
        logger.info(f"Created trailing stop for order {base_order_id}")
        return trailing
    
    def create_oco(
        self,
        order1_id: int,
        order2_id: int
    ) -> OCOOrder:
        """Create an OCO order.
        
        Args:
            order1_id: First order ID
            order2_id: Second order ID
            
        Returns:
            OCOOrder instance
        """
        oco = OCOOrder(order1_id, order2_id)
        self.oco_orders[order1_id] = oco
        self.oco_orders[order2_id] = oco
        logger.info(f"Created OCO order: {order1_id} <-> {order2_id}")
        return oco
    
    def create_iceberg(
        self,
        total_quantity: Decimal,
        visible_quantity: Decimal,
        symbol: str,
        side: OrderSide,
        price: Optional[Decimal] = None
    ) -> IcebergOrder:
        """Create an iceberg order.
        
        Args:
            total_quantity: Total quantity
            visible_quantity: Visible quantity per order
            symbol: Trading symbol
            side: Buy or sell
            price: Limit price (None for market)
            
        Returns:
            IcebergOrder instance
        """
        iceberg = IcebergOrder(total_quantity, visible_quantity, symbol, side, price)
        # Store by a unique ID (could use a counter or hash)
        iceberg_id = id(iceberg)
        self.iceberg_orders[iceberg_id] = iceberg
        logger.info(f"Created iceberg order: {total_quantity} {symbol} ({visible_quantity} visible)")
        return iceberg
    
    def update_trailing_stops(self, prices: Dict[int, Decimal], is_long: Dict[int, bool]):
        """Update all trailing stops with current prices.
        
        Args:
            prices: Dictionary of order_id -> current_price
            is_long: Dictionary of order_id -> is_long_position
        """
        for order_id, trailing in self.trailing_stops.items():
            if order_id in prices:
                trailing.update(prices[order_id], is_long.get(order_id, True))
    
    def check_triggers(self, prices: Dict[int, Decimal], is_long: Dict[int, bool]) -> List[int]:
        """Check all triggers and return triggered order IDs.
        
        Args:
            prices: Dictionary of order_id -> current_price
            is_long: Dictionary of order_id -> is_long_position
            
        Returns:
            List of triggered order IDs
        """
        triggered = []
        
        # Check take-profit orders
        for order_id, tp in self.take_profit_orders.items():
            if order_id in prices and tp.check_trigger(prices[order_id]):
                triggered.append(order_id)
        
        # Check trailing stops
        for order_id, trailing in self.trailing_stops.items():
            if order_id in prices and trailing.check_trigger(
                prices[order_id],
                is_long.get(order_id, True)
            ):
                triggered.append(order_id)
        
        return triggered
    
    async def on_order_filled(self, order_id: int):
        """Handle order fill for advanced orders.
        
        Args:
            order_id: Filled order ID
        """
        # Check OCO orders
        if order_id in self.oco_orders:
            await self.oco_orders[order_id].on_order_filled(order_id)
        
        # Check iceberg orders
        for iceberg_id, iceberg in self.iceberg_orders.items():
            if order_id in iceberg.orders:
                await iceberg.on_order_filled(order_id)


# Global advanced order manager
_advanced_order_manager: Optional[AdvancedOrderManager] = None


def get_advanced_order_manager() -> AdvancedOrderManager:
    """Get global advanced order manager instance."""
    global _advanced_order_manager
    if _advanced_order_manager is None:
        _advanced_order_manager = AdvancedOrderManager()
    return _advanced_order_manager

