"""
Smart Trade Hub API - Unified trade entry system
Consolidates Simulator, Manual Logger, and Broker Bridge into one intelligent interface
"""

from fastapi import APIRouter, HTTPException, Depends, Query
from sqlalchemy.orm import Session
from typing import Any, Dict, List, Optional, Literal
from datetime import datetime, timezone
from pydantic import BaseModel, Field

from app.db.database import get_db
from app.services.simulation_state import load_simulation_state
from app.api.trading_persistent import (
    TradeRequest as PersistentTradeRequest,
    execute_trade as persistent_execute_trade,
)
from app.services.risk import validate_order
from app.services.ai_context_builder import ai_context_builder
from app.services.price_anchor import price_anchor_service

router = APIRouter(prefix="/api/smart-trade-hub", tags=["Smart Trade Hub"])


class TradeSource(str):
    """Enumeration of trade sources"""
    SIMULATOR = "simulator"
    MANUAL = "manual"
    BROKER = "broker"
    VOICE = "voice"
    OCR = "ocr"


class SmartTradeRequest(BaseModel):
    """Unified trade entry request with auto-detection"""
    action: Literal["BUY", "SELL", "CLOSE"]
    symbol: str = Field(default="XAU/USD", description="Trading symbol")
    quantity: Optional[float] = Field(None, description="Trade quantity (auto-filled if None)")
    price: Optional[float] = Field(None, description="Entry price (uses current market if None)")
    
    # Optional guards (auto-calculated if None)
    stop_loss: Optional[float] = None
    take_profit: Optional[float] = None
    risk_percent: Optional[float] = None
    
    # Source detection and metadata
    source: Optional[str] = Field(None, description="Trade source: simulator/manual/broker/voice/ocr")
    platform: Optional[str] = Field(None, description="Trading platform (e.g., MT5, TradingView)")
    notes: Optional[str] = Field(None, description="Trade notes or voice transcription")
    entry_time: Optional[str] = Field(None, description="Custom entry time (ISO format)")
    
    # OCR/Voice metadata
    image_data: Optional[str] = Field(None, description="Base64 encoded screenshot for OCR")
    voice_data: Optional[str] = Field(None, description="Voice memo data")
    
    # Pre-fill hints
    use_last_trade_defaults: bool = Field(True, description="Auto-fill from last trade")
    apply_smart_guards: bool = Field(True, description="Apply AI-suggested guards")


class SmartTradeResponse(BaseModel):
    """Response with executed trade and suggestions"""
    trade_id: int
    action: str
    symbol: str
    quantity: float
    price: float
    stop_loss: Optional[float]
    take_profit: Optional[float]
    risk_percent: Optional[float]
    
    # Execution details
    source: str
    executed_at: str
    total_cost: float
    
    # Smart suggestions applied
    guards_applied: bool
    guards_suggested: Optional[Dict] = None
    prefill_used: bool
    
    # Position state after trade
    remaining_cash: float
    total_equity: float
    position_size: Optional[float]
    unrealized_pnl: Optional[float]


class SmartPreFillResponse(BaseModel):
    """Pre-fill suggestions for trade entry"""
    symbol: str
    suggested_quantity: float
    current_price: float
    suggested_guards: Dict
    last_trade_context: Optional[Dict]
    market_context: Dict
    confidence: float


class SmartGuardSuggestion(BaseModel):
    """AI-suggested risk guards"""
    stop_loss_price: float
    stop_loss_percent: float
    take_profit_price: float
    take_profit_percent: float
    risk_percent: float
    position_size: float
    risk_reward_ratio: float
    reasoning: str
    confidence: float


def _get_current_market_price(symbol: str) -> float:
    """Get current market price from price anchor service"""
    try:
        anchor_price = price_anchor_service.get_anchor_price_sync(symbol.upper().replace("/", ""))
        if anchor_price and anchor_price > 0:
            return anchor_price
    except:
        pass
    
    # Fallback to a reasonable default for XAU/USD
    return 2034.0


def _compute_equity(state: Dict[str, Any], price_hint: Optional[float] = None) -> float:
    """Compute total equity using cash and current position."""
    cash = float(state.get("cash", 0.0) or 0.0)
    position = state.get("position") or {}

    if position:
        current_price = price_hint or position.get("current_price") or position.get("avg_price") or 0.0
        quantity = position.get("quantity", 0.0) or 0.0
        cash += float(quantity) * float(current_price)

    return cash


def _get_last_trade_defaults(state: Dict[str, Any]) -> Optional[Dict]:
    """Get defaults from the last trade"""
    trades = state.get("trades", [])
    if not trades:
        return None
    
    last_trade = trades[-1]
    return {
        "quantity": last_trade.get("quantity"),
        "symbol": last_trade.get("symbol", "XAU/USD"),
        "platform": last_trade.get("platform"),
        "stop_loss": last_trade.get("stop_loss"),
        "take_profit": last_trade.get("take_profit"),
        "risk_percent": last_trade.get("risk_percent"),
    }


def _calculate_smart_guards(
    symbol: str,
    action: str,
    price: float,
    quantity: float,
    equity: float
) -> SmartGuardSuggestion:
    """
    Calculate optimal stop loss and take profit using ATR and risk management principles
    """
    try:
        # Get market metrics including ATR
        ctx = ai_context_builder.build_request(
            symbol.upper().replace("/", ""), 
            "1h",  # Use hourly for guard calculation
            100
        )
        metrics = ai_context_builder.build_metrics(
            symbol.upper().replace("/", ""),
            "1h",
            ctx.price_data
        )
        
        # Extract ATR value
        atr = metrics.atr_14 if hasattr(metrics, 'atr_14') else (price * 0.015)  # Default to 1.5%
        
        # Calculate stop loss (1.5x ATR from entry)
        sl_distance = atr * 1.5
        sl_percent = (sl_distance / price) * 100
        
        # Calculate take profit (2x stop loss for 1:2 risk/reward minimum)
        tp_distance = sl_distance * 2.0
        tp_percent = (tp_distance / price) * 100
        
        if action == "BUY":
            sl_price = price - sl_distance
            tp_price = price + tp_distance
        else:  # SELL
            sl_price = price + sl_distance
            tp_price = price - tp_distance
        
        # Calculate position risk as % of equity
        risk_amount = quantity * sl_distance
        risk_percent = (risk_amount / equity) * 100
        
        # Ensure risk doesn't exceed 2% of equity (conservative default)
        if risk_percent > 2.0:
            # Adjust quantity to maintain 2% risk
            adjusted_quantity = (equity * 0.02) / sl_distance
            risk_percent = 2.0
        else:
            adjusted_quantity = quantity
        
        return SmartGuardSuggestion(
            stop_loss_price=round(sl_price, 2),
            stop_loss_percent=round(sl_percent, 2),
            take_profit_price=round(tp_price, 2),
            take_profit_percent=round(tp_percent, 2),
            risk_percent=round(risk_percent, 2),
            position_size=round(adjusted_quantity, 2),
            risk_reward_ratio=2.0,
            reasoning=f"ATR-based guards: {atr:.2f} | 1.5x ATR stop | 1:2 R:R ratio | Max 2% risk",
            confidence=0.85
        )
    
    except Exception as e:
        # Fallback to simple percentage-based guards
        sl_percent = 2.0
        tp_percent = 4.0
        
        if action == "BUY":
            sl_price = price * (1 - sl_percent / 100)
            tp_price = price * (1 + tp_percent / 100)
        else:
            sl_price = price * (1 + sl_percent / 100)
            tp_price = price * (1 - tp_percent / 100)
        
        risk_amount = quantity * price * (sl_percent / 100)
        risk_percent = (risk_amount / equity) * 100
        
        return SmartGuardSuggestion(
            stop_loss_price=round(sl_price, 2),
            stop_loss_percent=round(sl_percent, 2),
            take_profit_price=round(tp_price, 2),
            take_profit_percent=round(tp_percent, 2),
            risk_percent=round(risk_percent, 2),
            position_size=quantity,
            risk_reward_ratio=2.0,
            reasoning="Fallback guards: 2% stop loss | 4% take profit | 1:2 ratio",
            confidence=0.60
        )


@router.post("/prefill", response_model=SmartPreFillResponse)
async def get_smart_prefill(
    symbol: str = Query("XAU/USD"),
    action: Optional[str] = Query(None),
    db: Session = Depends(get_db),
    user_id: str = "default",
) -> SmartPreFillResponse:
    """Get smart pre-fill suggestions based on last trade and current market context."""
    try:
        current_price = _get_current_market_price(symbol)
        state = load_simulation_state(db, user_id)
        last_trade = _get_last_trade_defaults(state)

        suggested_quantity = 1.0
        if last_trade and last_trade.get("quantity"):
            suggested_quantity = last_trade["quantity"]

        equity = _compute_equity(state, price_hint=current_price)
        trade_action = (action or "BUY").upper()
        guards = _calculate_smart_guards(
            symbol,
            trade_action,
            current_price,
            suggested_quantity,
            equity,
        )

        market_context = {
            "current_price": current_price,
            "equity": equity,
            "cash": state.get("cash", 0.0),
            "position": state.get("position"),
        }

        return SmartPreFillResponse(
            symbol=symbol,
            suggested_quantity=suggested_quantity,
            current_price=current_price,
            suggested_guards={
                "stop_loss": guards.stop_loss_price,
                "take_profit": guards.take_profit_price,
                "risk_percent": guards.risk_percent,
                "reasoning": guards.reasoning,
                "confidence": guards.confidence,
            },
            last_trade_context=last_trade,
            market_context=market_context,
            confidence=0.80,
        )
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Failed to generate pre-fill suggestions: {str(e)}",
        )


@router.post("/execute", response_model=SmartTradeResponse)
async def execute_smart_trade(
    request: SmartTradeRequest,
    db: Session = Depends(get_db),
    user_id: str = "default",
) -> SmartTradeResponse:
    """Execute a trade through the unified smart trade hub using the persistent state."""
    try:
        source = request.source or TradeSource.MANUAL
        if request.image_data:
            source = TradeSource.OCR
        elif request.voice_data:
            source = TradeSource.VOICE

        price = request.price or _get_current_market_price(request.symbol)
        state = load_simulation_state(db, user_id)

        last_trade = _get_last_trade_defaults(state) if request.use_last_trade_defaults else None
        quantity = request.quantity
        if quantity is None:
            if last_trade and last_trade.get("quantity"):
                quantity = last_trade["quantity"]
            else:
                quantity = 1.0

        equity = _compute_equity(state, price_hint=price)

        guards_applied = False
        guards_suggested: Optional[Dict[str, Any]] = None
        guards: Optional[SmartGuardSuggestion] = None

        if request.apply_smart_guards:
            guards = _calculate_smart_guards(
                request.symbol,
                request.action,
                price,
                quantity,
                equity,
            )

            if request.stop_loss is None:
                request.stop_loss = guards.stop_loss_price
                guards_applied = True

            if request.take_profit is None:
                request.take_profit = guards.take_profit_price
                guards_applied = True

            if request.risk_percent is None:
                request.risk_percent = guards.risk_percent
                guards_applied = True

            if guards.position_size != quantity:
                quantity = guards.position_size
                guards_applied = True

            guards_suggested = guards.model_dump()

        if request.action == "CLOSE":
            position = state.get("position")
            if not position:
                raise HTTPException(status_code=400, detail="No position to close")

            request.action = "SELL"
            quantity = position.get("quantity", 0.0) or 0.0

        try:
            validate_order(state, request.action, quantity, price)
        except ValueError as ve:
            raise HTTPException(status_code=400, detail=str(ve))

        persistent_request = PersistentTradeRequest(
            action=request.action,
            quantity=quantity,
            price=price,
            symbol=request.symbol,
            notes=request.notes,
            stop_loss=request.stop_loss,
            take_profit=request.take_profit,
            source=source,
            platform=request.platform,
            risk_percent=request.risk_percent,
            entry_time=request.entry_time,
        )

        result = await persistent_execute_trade(persistent_request, db=db, user_id=user_id)
        trade_info = result["trade"]
        portfolio = result["portfolio"]

        total_cost = trade_info.get("total", quantity * price)
        executed_ts = trade_info.get("timestamp")
        executed_at = (
            datetime.fromtimestamp(executed_ts, tz=timezone.utc).isoformat()
            if executed_ts
            else datetime.now(timezone.utc).isoformat()
        )

        position_after = portfolio.get("position") or {}
        position_size = position_after.get("quantity")
        unrealized_pnl = position_after.get("unrealized_pnl")
        total_equity = _compute_equity(portfolio, price_hint=price)

        return SmartTradeResponse(
            trade_id=trade_info["id"],
            action=trade_info["action"],
            symbol=request.symbol,
            quantity=trade_info["quantity"],
            price=trade_info["price"],
            stop_loss=trade_info.get("stop_loss"),
            take_profit=trade_info.get("take_profit"),
            risk_percent=trade_info.get("risk_percent"),
            source=source,
            executed_at=executed_at,
            total_cost=total_cost,
            guards_applied=guards_applied,
            guards_suggested=guards_suggested,
            prefill_used=request.use_last_trade_defaults,
            remaining_cash=portfolio.get("cash", 0.0),
            total_equity=total_equity,
            position_size=position_size,
            unrealized_pnl=unrealized_pnl,
        )

    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Failed to execute smart trade: {str(e)}",
        )


@router.get("/suggestions", response_model=SmartGuardSuggestion)
async def get_guard_suggestions(
    symbol: str = Query("XAU/USD"),
    action: str = Query("BUY"),
    quantity: float = Query(1.0),
    price: Optional[float] = Query(None),
    db: Session = Depends(get_db),
    user_id: str = "default",
) -> SmartGuardSuggestion:
    """Get AI-suggested stop loss and take profit guards using persistent state."""
    try:
        if price is None:
            price = _get_current_market_price(symbol)

        state = load_simulation_state(db, user_id)
        equity = _compute_equity(state, price_hint=price)

        return _calculate_smart_guards(symbol, action, price, quantity, equity)

    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Failed to calculate guard suggestions: {str(e)}",
        )


@router.get("/history")
async def get_trade_history(
    limit: int = Query(50, ge=1, le=500),
    source: Optional[str] = Query(None),
    db: Session = Depends(get_db),
    user_id: str = "default",
) -> Dict:
    """Get trade history with optional source filtering from persisted trades."""
    try:
        state = load_simulation_state(db, user_id)
        trades = state.get("trades", [])

        if source:
            trades = [t for t in trades if t.get("source") == source]

        trades = trades[-limit:]

        sources = {
            (t.get("source") or "unknown")
            for t in state.get("trades", [])
        }

        return {
            "trades": trades,
            "total": len(trades),
            "sources": sorted(sources),
        }

    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Failed to retrieve trade history: {str(e)}",
        )
