"""
Live Performance Dashboard API - Real-time plan monitoring and alerts
"""

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

from app.db.database import get_db
from app.models.models import DailyChecklist, UserProfile
from app.services.simulation_state import load_simulation_state

router = APIRouter(prefix="/api/live-dashboard", tags=["Live Dashboard"])


class DailyPlanStatus(BaseModel):
    """Current status of today's trading plan"""
    date: str
    target: float
    actual_pnl: float
    progress_percent: float
    max_loss: float
    current_drawdown: float
    max_trades: int
    actual_trades: int
    trades_remaining: int
    status: Literal["on-track", "near-limit", "limit-reached", "target-met"]
    alerts: List[str]


class PerformanceWidget(BaseModel):
    """Sticky dashboard widget data"""
    daily_plan: DailyPlanStatus
    position_summary: Dict
    risk_metrics: Dict
    alerts: List[Dict]
    recommendations: List[str]


class AlertConfig(BaseModel):
    """Alert configuration"""
    alert_type: str  # trade_limit, loss_limit, target_achieved, break_recommended
    enabled: bool
    threshold: Optional[float] = None
    message: str


# In-memory simulation state (shared with trading.py)


def _get_today_plan_from_storage() -> Optional[Dict]:
    """Get today's trading plan blueprint (defaults until persistence is added)."""
    # In production, this would query the database
    # For now, we'll use a default plan structure
    return {
        "date": date.today().isoformat(),
        "daily_target": 500.0,
        "max_loss": 250.0,
        "max_trades": 3,
        "bias": "NEUTRAL",
    }


def _calculate_daily_pnl(trades: List[Dict[str, Any]], target_date: date | None = None) -> float:
    """Calculate P&L for trades executed on the target date"""
    target_date = target_date or date.today()
    daily_pnl = 0.0
    for trade in trades:
        trade_ts = trade.get("timestamp", 0)
        trade_date = datetime.fromtimestamp(trade_ts, tz=timezone.utc).date()
        if trade_date == target_date:
            pnl = trade.get("pnl", 0.0)
            if pnl:
                daily_pnl += pnl
    return daily_pnl


def _count_today_trades(trades: List[Dict[str, Any]], target_date: date | None = None) -> int:
    """Count trades executed on the target date"""
    target_date = target_date or date.today()
    count = 0
    for trade in trades:
        trade_ts = trade.get("timestamp", 0)
        trade_date = datetime.fromtimestamp(trade_ts, tz=timezone.utc).date()
        if trade_date == target_date:
            count += 1
    return count


def _generate_alerts(plan: Dict, actual_pnl: float, trades_count: int) -> List[str]:
    """Generate smart alerts based on plan vs actual"""
    alerts = []
    
    target = plan.get("daily_target", 500.0)
    max_loss = plan.get("max_loss", 250.0)
    max_trades = plan.get("max_trades", 3)
    
    # Trade limit alerts
    trades_remaining = max_trades - trades_count
    if trades_remaining == 1:
        alerts.append(f"⚠️ Only 1 trade remaining before daily limit")
    elif trades_remaining <= 0:
        alerts.append(f"🛑 Daily trade limit reached ({max_trades} trades)")
    
    # Loss alerts
    if actual_pnl < 0:
        loss_percent = (abs(actual_pnl) / max_loss) * 100
        if loss_percent >= 100:
            alerts.append(f"🚨 Max loss limit reached (${abs(actual_pnl):.2f})")
        elif loss_percent >= 80:
            alerts.append(f"⚠️ Near max loss limit ({loss_percent:.0f}% of ${max_loss})")
        elif loss_percent >= 50:
            alerts.append(f"⚡ Drawdown at {loss_percent:.0f}% of max loss")
    
    # Target achievement alerts
    if actual_pnl > 0:
        progress_percent = (actual_pnl / target) * 100
        if progress_percent >= 100:
            alerts.append(f"🎉 Daily target achieved! (+${actual_pnl:.2f})")
        elif progress_percent >= 80:
            alerts.append(f"🎯 ${target - actual_pnl:.2f} away from daily target")
    
    # Trading duration alerts (if 2+ hours and significant losses)
    if trades_count >= 2 and actual_pnl < -100:
        alerts.append(f"💡 Consider taking a break. ${abs(actual_pnl):.2f} in losses after {trades_count} trades")
    
    return alerts


def _determine_status(
    actual_pnl: float,
    target: float,
    max_loss: float,
    trades_count: int,
    max_trades: int
) -> Literal["on-track", "near-limit", "limit-reached", "target-met"]:
    """Determine overall plan status"""
    
    # Target met
    if actual_pnl >= target:
        return "target-met"
    
    # Limits reached
    if trades_count >= max_trades:
        return "limit-reached"
    
    if actual_pnl <= -max_loss:
        return "limit-reached"
    
    # Near limits
    loss_percent = (abs(actual_pnl) / max_loss) * 100 if actual_pnl < 0 else 0
    trades_percent = (trades_count / max_trades) * 100
    
    if loss_percent >= 80 or trades_percent >= 80:
        return "near-limit"
    
    # On track
    return "on-track"


@router.get("/status", response_model=DailyPlanStatus)
async def get_dashboard_status(db: Session = Depends(get_db)) -> DailyPlanStatus:
    """
    Get current status of today's trading plan with real-time metrics
    """
    try:
        plan = _get_today_plan_from_storage()
        if not plan:
            raise HTTPException(status_code=404, detail="No trading plan found for today")

        state = load_simulation_state(db)
        trades = state.get("trades", [])
        actual_pnl = _calculate_daily_pnl(trades)
        trades_count = _count_today_trades(trades)

        target = plan.get("daily_target", 500.0)
        max_loss = plan.get("max_loss", 250.0)
        max_trades = plan.get("max_trades", 3)

        progress_percent = (actual_pnl / target) * 100 if target > 0 else 0
        current_drawdown = abs(actual_pnl) if actual_pnl < 0 else 0
        trades_remaining = max(0, max_trades - trades_count)

        alerts = _generate_alerts(plan, actual_pnl, trades_count)
        status = _determine_status(actual_pnl, target, max_loss, trades_count, max_trades)

        return DailyPlanStatus(
            date=plan["date"],
            target=target,
            actual_pnl=actual_pnl,
            progress_percent=round(progress_percent, 1),
            max_loss=max_loss,
            current_drawdown=current_drawdown,
            max_trades=max_trades,
            actual_trades=trades_count,
            trades_remaining=trades_remaining,
            status=status,
            alerts=alerts,
        )
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Failed to get dashboard status: {str(e)}"
        )


@router.get("/widget", response_model=PerformanceWidget)
async def get_performance_widget(db: Session = Depends(get_db)) -> PerformanceWidget:
    """
    Get complete performance widget data for sticky dashboard
    """
    try:
        # Get daily plan status
        daily_plan = await get_dashboard_status(db=db)
        
        state = load_simulation_state(db)
        position = state.get("position")
        cash = float(state.get("cash", 100000.0))
        position_value = 0.0
        if position:
            position_value = float(position.get("quantity", 0.0)) * float(position.get("avg_price", 0.0))

        total_equity = cash + position_value
        position_summary = {
            "has_position": position is not None,
            "quantity": float(position.get("quantity", 0.0)) if position else 0,
            "avg_price": float(position.get("avg_price", 0.0)) if position else 0,
            "cash": cash,
            "total_equity": total_equity,
        }
        
        # Calculate risk metrics
        initial_capital = float(state.get("initial_capital", 100000.0))
        safe_equity = total_equity if total_equity != 0 else 1
        total_return = ((total_equity - initial_capital) / initial_capital) * 100 if initial_capital else 0
        
        risk_metrics = {
            "total_equity": total_equity,
            "total_return_percent": round(total_return, 2),
            "position_size_percent": round((position_value / safe_equity * 100), 2) if position else 0,
            "cash_percent": round((cash / safe_equity * 100), 2),
        }
        
        # Generate smart recommendations
        recommendations = []
        
        if daily_plan.status == "target-met":
            recommendations.append("🎉 Consider closing for the day - target achieved!")
        elif daily_plan.status == "limit-reached":
            recommendations.append("🛑 Trading halt recommended - daily limits reached")
        elif daily_plan.status == "near-limit":
            if daily_plan.trades_remaining == 1:
                recommendations.append("⚠️ Last trade available - make it count")
            if daily_plan.current_drawdown > daily_plan.max_loss * 0.8:
                recommendations.append("🔻 Consider defensive position sizing")
        else:
            if daily_plan.actual_pnl > daily_plan.target * 0.7:
                recommendations.append("🎯 Near target - consider taking profits")
        
        # Alert objects with metadata
        alert_objects = [
            {
                "type": "info",
                "message": alert,
                "timestamp": datetime.now(timezone.utc).isoformat(),
            }
            for alert in daily_plan.alerts
        ]
        
        return PerformanceWidget(
            daily_plan=daily_plan,
            position_summary=position_summary,
            risk_metrics=risk_metrics,
            alerts=alert_objects,
            recommendations=recommendations,
        )
    
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Failed to get performance widget: {str(e)}"
        )


@router.post("/check-limits")
async def check_trading_limits(db: Session = Depends(get_db)) -> Dict:
    """
    Check if trading should be halted based on plan limits
    Returns: {can_trade: bool, reason: str}
    """
    try:
        plan = _get_today_plan_from_storage()
        if not plan:
            return {"can_trade": True, "reason": "No plan configured"}

        state = load_simulation_state(db)
        trades = state.get("trades", [])
        actual_pnl = _calculate_daily_pnl(trades)
        trades_count = _count_today_trades(trades)

        max_loss = plan.get("max_loss", 250.0)
        max_trades = plan.get("max_trades", 3)
        target = plan.get("daily_target", 500.0)

        if actual_pnl <= -max_loss:
            return {
                "can_trade": False,
                "reason": f"Max loss limit reached (${abs(actual_pnl):.2f})",
                "limit_type": "loss",
            }

        if trades_count >= max_trades:
            return {
                "can_trade": False,
                "reason": f"Max trades limit reached ({trades_count}/{max_trades})",
                "limit_type": "trades",
            }

        if actual_pnl >= target:
            return {
                "can_trade": True,
                "reason": f"Target achieved (+${actual_pnl:.2f}) - consider closing for the day",
                "warning": True,
            }

        return {
            "can_trade": True,
            "reason": "Within limits",
            "remaining_trades": max_trades - trades_count,
            "remaining_loss_buffer": max_loss + actual_pnl,
        }
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Failed to check trading limits: {str(e)}"
        )


@router.get("/session-summary")
async def get_session_summary(db: Session = Depends(get_db)) -> Dict:
    """
    Get end-of-day session summary with AI coaching suggestions
    """
    try:
        plan = _get_today_plan_from_storage()
        state = load_simulation_state(db)
        trades = state.get("trades", [])
        actual_pnl = _calculate_daily_pnl(trades)
        trades_count = _count_today_trades(trades)

        if not plan:
            raise HTTPException(status_code=404, detail="No trading plan found")

        target = plan.get("daily_target", 500.0)
        max_loss = plan.get("max_loss", 250.0)

        target_achieved = actual_pnl >= target
        within_limits = actual_pnl > -max_loss and trades_count <= plan.get("max_trades", 3)

        today = date.today()
        today_trades = [
            t for t in trades
            if datetime.fromtimestamp(t.get("timestamp", 0), tz=timezone.utc).date() == today
        ]

        winning_trades = sum(1 for t in today_trades if t.get("pnl", 0) > 0)
        win_rate = (winning_trades / len(today_trades) * 100) if today_trades else 0

        coaching = []
        if target_achieved:
            coaching.append("✅ Excellent discipline - you met your daily target!")
        else:
            deficit = target - actual_pnl
            coaching.append(f"📊 ${deficit:.2f} short of target. Review your entry setups.")

        if win_rate >= 60:
            coaching.append(f"🎯 Strong win rate ({win_rate:.0f}%). Keep following your strategy.")
        elif win_rate < 40:
            coaching.append(f"⚠️ Low win rate ({win_rate:.0f}%). Review your trade selection criteria.")

        if not within_limits:
            coaching.append("🔻 Limits exceeded. Focus on risk management tomorrow.")
        if trades_count > plan.get("max_trades", 3):
            coaching.append("⚠️ Over-trading detected. Stick to your max trades limit.")

        return {
            "date": plan["date"],
            "summary": {
                "target": target,
                "actual_pnl": actual_pnl,
                "target_achieved": target_achieved,
                "within_limits": within_limits,
                "trades_count": trades_count,
                "win_rate": round(win_rate, 1),
            },
            "coaching": coaching,
            "next_session_suggestions": [
                "Review today's winning trades for patterns",
                "Adjust stop loss strategy if needed",
                "Focus on high-probability setups only",
            ],
        }
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=500,
            detail=f"Failed to generate session summary: {str(e)}"
        )
