"""Order processing logic"""

import time
from typing import Dict, List, Optional
from brokers.base_broker import BaseBroker
from config.config import Config
from utils.logger import TradingLogger

class OrderProcessor:
    """Handles order placement and profit booking logic"""
    
    def __init__(self, broker: BaseBroker, client_code: str, 
                 symbol_properties: Dict, config: Config):
        self.broker = broker
        self.client_code = client_code
        self.symbol_properties = symbol_properties
        self.config = config
        self.logger = TradingLogger(client_code)
        self.default_profit_margin = 20
    
    def calculate_quantity(self, base_symbol: str, no_lots: int) -> int:
        """Calculate final quantity with multiplier"""
        props = self.symbol_properties.get(base_symbol, {})
        base_quantity = props.get('quantity', 0)
        multiplier = props.get('multiplier', 1)
        return base_quantity * no_lots * multiplier
    
    def get_max_quantity(self, base_symbol: str) -> int:
        """Get maximum allowed quantity per order"""
        return self.config.get_max_quantity(base_symbol)
    
    def place_order_with_split(self, symbol: str, action: str, quantity: int, 
                               exchange: str, expiry: str, remarks: str) -> bool:
        """Place order with automatic splitting for large quantities"""
        max_qty = self.get_max_quantity(symbol)
        
        runtime_settings = self.config.get_runtime_settings()
        split_delay = runtime_settings.get('order_split_delay', 0.5)
        
        if quantity <= max_qty:
            order_id = self.broker.place_order(symbol, action, quantity, exchange, expiry, remarks)
            return order_id is not None
        
        chunks = self.broker.split_order_quantity(quantity, max_qty)
        success = True
        
        for i, chunk_qty in enumerate(chunks):
            chunk_remarks = f"{remarks}_part{i+1}"
            order_id = self.broker.place_order(symbol, action, chunk_qty, exchange, expiry, chunk_remarks)
            
            if order_id is None:
                success = False
                self.logger.error(f"Failed to place split order part {i+1}/{len(chunks)}")
            
            time.sleep(split_delay)
        
        return success
    
    def get_profit_margin(self, trading_symbol: str) -> float:
        """Get profit margin for a symbol"""
        for base_symbol, props in self.symbol_properties.items():
            if trading_symbol.startswith(base_symbol):
                margin = props.get('profit', self.default_profit_margin)
                self.logger.info(f"Profit margin for {trading_symbol}: {margin}")
                return margin
        
        self.logger.warning(f"Using default profit margin for {trading_symbol}")
        return self.default_profit_margin
    
    def process_profit_orders(self) -> None:
        """Process profit booking for all open positions"""
        try:
            positions = self.broker.get_positions()
            orders = self.broker.get_orders()
            
            for position in positions:
                quantity = self._get_position_quantity(position)
                if quantity == 0:
                    continue
                
                trading_symbol = self._get_symbol(position)
                exchange = self._get_exchange(position)
                
                avg_cost = self._calculate_average_cost(trading_symbol, quantity, orders, position)
                if avg_cost == 0:
                    continue
                
                quote = self.broker.get_quote(exchange, trading_symbol)
                ltp = quote.get('last_price', 0)
                
                if ltp == 0:
                    self.logger.warning(f"Cannot get LTP for {trading_symbol}")
                    continue
                
                profit_margin = self.get_profit_margin(trading_symbol)
                target_price = avg_cost + profit_margin
                
                self.logger.info(f"{trading_symbol} | Cost: {avg_cost:.2f} | Target: {target_price:.2f} | LTP: {ltp}")
                
                if ltp >= target_price:
                    transaction_type = 'SELL' if self.broker.__class__.__name__ == 'ZerodhaBroker' else 'S'
                    self._place_profit_order(trading_symbol, quantity, exchange, transaction_type)
                    
        except Exception as e:
            self.logger.error(f"Profit order processing failed: {e}")
    
    def _get_position_quantity(self, position: Dict) -> int:
        """Extract quantity from position dict"""
        if 'quantity' in position:
            return position.get('quantity', 0)
        elif 'netQuantity' in position:
            return int(position.get('netQuantity', 0))
        return 0
    
    def _get_symbol(self, position: Dict) -> str:
        """Extract symbol from position dict"""
        return position.get('tradingsymbol') or position.get('tradingSymbol', '')
    
    def _get_exchange(self, position: Dict) -> str:
        """Extract exchange from position dict"""
        return position.get('exchange', '')
    
    def _calculate_average_cost(self, trading_symbol: str, total_quantity: int, 
                                orders: List[Dict], position: Dict) -> float:
        """Calculate average cost price from buy orders"""
        buy_orders = []
        
        for order in orders:
            order_symbol = order.get('tradingsymbol') or order.get('tradingSymbol', '')
            order_status = order.get('status', '')
            order_type = order.get('transaction_type') or order.get('transactionType', '')
            
            if (order_symbol == trading_symbol and 
                order_status == 'COMPLETE' and 
                order_type == 'BUY'):
                buy_orders.append(order)
        
        buy_orders.sort(key=lambda x: x.get('order_timestamp', ''), reverse=True)
        
        remaining_qty = total_quantity
        cost_total = 0.0
        
        for order in buy_orders:
            if remaining_qty <= 0:
                break
            
            order_qty = int(order.get('filled_quantity', order.get('quantity', 0)))
            order_price = float(order.get('average_price', 0))
            
            qty_to_use = min(remaining_qty, order_qty)
            cost_total += qty_to_use * order_price
            remaining_qty -= qty_to_use
        
        if remaining_qty > 0:
            avg_price = float(position.get('average_price', 0))
            if avg_price > 0:
                cost_total += remaining_qty * avg_price
        
        if cost_total == 0:
            return 0
        
        return cost_total / total_quantity
    
    def _place_profit_order(self, trading_symbol: str, quantity: int, 
                           exchange: str, transaction_type: str) -> bool:
        """Place profit order with splitting if needed"""
        base_symbol = 'NIFTY' if 'NIFTY' in trading_symbol else 'SENSEX'
        max_qty = self.get_max_quantity(base_symbol)
        
        runtime_settings = self.config.get_runtime_settings()
        split_delay = runtime_settings.get('order_split_delay', 0.5)
        
        if quantity <= max_qty:
            order_id = self.broker.place_profit_order(
                trading_symbol, quantity, exchange, transaction_type, "Profit Target"
            )
            return order_id is not None
        
        chunks = self.broker.split_order_quantity(quantity, max_qty)
        success = True
        
        for i, chunk_qty in enumerate(chunks):
            remarks = f"Profit Target_{i+1}"
            order_id = self.broker.place_profit_order(
                trading_symbol, chunk_qty, exchange, transaction_type, remarks
            )
            
            if order_id is None:
                success = False
            
            time.sleep(split_delay)
        
        return success