"""RiskManager agent implementation for OpenClaw trading system.

This module provides the RiskManager class that can assess trading risks,
calculate portfolio risk metrics, volatility, VaR (Value at Risk), and
generate comprehensive risk reports.
"""

from __future__ import annotations

import math
import random
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Dict, List, Optional

import numpy as np

from openclaw.agents.base import ActivityType, BaseAgent
from openclaw.core.economy import SurvivalStatus
from openclaw.utils.logging import get_logger


@dataclass
class RiskReport:
    """Comprehensive risk assessment report for a trading position.

    Attributes:
        symbol: Trading symbol being assessed
        risk_level: Risk classification ("low", "medium", "high", "extreme")
        volatility: Annualized volatility as a decimal
        var_95: 95% VaR (Value at Risk) - potential loss at 95% confidence
        var_99: 99% VaR (Value at Risk) - potential loss at 99% confidence
        max_drawdown_estimate: Estimated maximum drawdown based on volatility
        position_size_recommendation: Recommended position size in dollars
        warnings: List of risk warnings and concerns
    """

    symbol: str
    risk_level: str  # "low", "medium", "high", "extreme"
    volatility: float  # annualized volatility
    var_95: float  # 95% VaR
    var_99: float  # 99% VaR
    max_drawdown_estimate: float
    position_size_recommendation: float
    warnings: List[str] = field(default_factory=list)


@dataclass
class PortfolioRiskMetrics:
    """Risk metrics for an entire portfolio.

    Attributes:
        portfolio_id: Identifier for the portfolio
        total_exposure: Total portfolio exposure
        concentration_risk: Concentration risk score (0-1)
        correlation_risk: Correlation risk score (0-1)
        portfolio_var_95: Portfolio-level 95% VaR
        portfolio_var_99: Portfolio-level 99% VaR
        sector_exposure: Dictionary of sector exposures
        risk_adjusted_return: Risk-adjusted return estimate
    """

    portfolio_id: str
    total_exposure: float
    concentration_risk: float
    correlation_risk: float
    portfolio_var_95: float
    portfolio_var_99: float
    sector_exposure: Dict[str, float] = field(default_factory=dict)
    risk_adjusted_return: float = 0.0


class RiskManager(BaseAgent):
    """Risk management agent that assesses trading and portfolio risks.

    The RiskManager evaluates potential risks for individual positions
    and entire portfolios, calculating metrics like VaR, volatility,
    and providing position sizing recommendations.

    Args:
        agent_id: Unique identifier for this agent
        initial_capital: Starting balance for the agent
        skill_level: Initial skill level (0.0 to 1.0)
        max_risk_per_trade: Maximum risk per trade as percentage of portfolio
        max_portfolio_var: Maximum portfolio VaR limit
    """

    decision_cost = 0.20

    def __init__(
        self,
        agent_id: str,
        initial_capital: float,
        skill_level: float = 0.5,
        max_risk_per_trade: float = 0.02,
        max_portfolio_var: float = 0.05,
    ):
        super().__init__(agent_id, initial_capital, skill_level)
        self.max_risk_per_trade = max_risk_per_trade
        self.max_portfolio_var = max_portfolio_var
        self._risk_history: List[RiskReport] = []
        self._portfolio_risk_history: List[PortfolioRiskMetrics] = []

    async def decide_activity(self) -> ActivityType:
        """Decide what activity to perform based on economic status.

        Risk managers primarily analyze and assess risks. They focus on
        learning when their skill level is low or when economic status
        is critical.

        Returns:
            The activity type to perform
        """
        status = self.survival_status

        # Bankrupt agents can only rest
        if status == SurvivalStatus.BANKRUPT:
            self.logger.warning("Agent is bankrupt, resting...")
            return ActivityType.REST

        # Critical status - focus on learning
        if status == SurvivalStatus.CRITICAL:
            if self.skill_level < 0.7:
                return ActivityType.LEARN
            return ActivityType.ANALYZE

        # Struggling - more paper trading/analysis
        if status == SurvivalStatus.STRUGGLING:
            if self.skill_level < 0.6:
                return ActivityType.LEARN
            return ActivityType.ANALYZE

        # Stable and thriving - primarily analyze risks
        if status in [SurvivalStatus.STABLE, SurvivalStatus.THRIVING]:
            if self.skill_level < 0.5:
                return ActivityType.LEARN
            return ActivityType.ANALYZE

        # Default to analyze
        return ActivityType.ANALYZE

    async def analyze(self, symbol: str) -> Dict[str, Any]:
        """Analyze a trading symbol for risk assessment.

        This is a simplified analysis that provides basic risk metrics.
        For comprehensive risk assessment, use assess_risk() method.

        Args:
            symbol: The symbol to analyze (e.g., "AAPL")

        Returns:
            Dictionary containing risk analysis results
        """
        # Deduct decision cost for analysis
        cost = self.economic_tracker.calculate_decision_cost(
            tokens_input=300,
            tokens_output=150,
            market_data_calls=1,
        )
        self.logger.info(f"Risk analysis cost for {symbol}: ${cost:.4f}")

        # Calculate basic volatility estimate
        volatility = self._estimate_volatility(symbol)

        # Calculate simple VaR
        var_95 = self._calculate_var(volatility, confidence=0.95)
        var_99 = self._calculate_var(volatility, confidence=0.99)

        # Determine risk level
        risk_level = self._classify_risk_level(volatility)

        return {
            "symbol": symbol,
            "risk_level": risk_level,
            "volatility": round(volatility, 4),
            "var_95": round(var_95, 4),
            "var_99": round(var_99, 4),
            "cost": cost,
        }

    async def assess_risk(
        self,
        symbol: str,
        position_size: float,
        portfolio: Optional[Dict[str, Any]] = None,
    ) -> RiskReport:
        """Assess risk for a potential trade.

        This is the primary method for risk assessment. It evaluates
        the risk of a position, calculates VaR, and provides
        recommendations.

        Args:
            symbol: The trading symbol to assess
            position_size: Proposed position size in dollars
            portfolio: Optional portfolio context for portfolio risk

        Returns:
            RiskReport with comprehensive risk assessment
        """
        # Deduct decision cost for risk assessment
        cost = self._deduct_decision_cost()
        self.logger.info(f"Risk assessment cost for {symbol}: ${cost:.2f}")

        # Check if we can afford the assessment
        if cost == 0.0:
            return RiskReport(
                symbol=symbol,
                risk_level="extreme",
                volatility=1.0,
                var_95=position_size,
                var_99=position_size,
                max_drawdown_estimate=position_size,
                position_size_recommendation=0.0,
                warnings=["Cannot afford risk assessment - agent may be bankrupt"],
            )

        # Calculate volatility
        volatility = self._estimate_volatility(symbol)

        # Calculate VaR metrics
        var_95 = self._calculate_var(volatility, confidence=0.95, position_size=position_size)
        var_99 = self._calculate_var(volatility, confidence=0.99, position_size=position_size)

        # Estimate max drawdown
        max_drawdown = self._estimate_max_drawdown(volatility)

        # Assess portfolio risk if portfolio provided
        warnings = self._generate_risk_warnings(
            symbol, position_size, volatility, portfolio
        )

        # Calculate position size recommendation
        recommended_size = self._calculate_position_recommendation(
            position_size, volatility, portfolio
        )

        # Determine risk level
        risk_level = self._classify_risk_level(volatility)

        # Create and store report
        report = RiskReport(
            symbol=symbol,
            risk_level=risk_level,
            volatility=round(volatility, 4),
            var_95=round(var_95, 2),
            var_99=round(var_99, 2),
            max_drawdown_estimate=round(max_drawdown, 4),
            position_size_recommendation=round(recommended_size, 2),
            warnings=warnings,
        )

        self._risk_history.append(report)
        self.logger.info(
            f"Risk assessment for {symbol}: {risk_level} risk, "
            f"volatility={volatility:.2%}, VaR95=${var_95:.2f}"
        )

        return report

    def assess_portfolio_risk(
        self,
        portfolio_id: str,
        positions: Dict[str, float],
        correlations: Optional[Dict[str, Dict[str, float]]] = None,
    ) -> PortfolioRiskMetrics:
        """Assess risk for an entire portfolio.

        Args:
            portfolio_id: Identifier for the portfolio
            positions: Dictionary mapping symbols to position sizes
            correlations: Optional correlation matrix between symbols

        Returns:
            PortfolioRiskMetrics with portfolio-level risk assessment
        """
        if not positions:
            return PortfolioRiskMetrics(
                portfolio_id=portfolio_id,
                total_exposure=0.0,
                concentration_risk=0.0,
                correlation_risk=0.0,
                portfolio_var_95=0.0,
                portfolio_var_99=0.0,
            )

        # Calculate total exposure
        total_exposure = sum(abs(size) for size in positions.values())

        # Calculate concentration risk
        concentration_risk = self._calculate_concentration_risk(positions)

        # Calculate correlation risk
        correlation_risk = self._calculate_correlation_risk(positions, correlations)

        # Calculate portfolio VaR
        portfolio_var_95 = self._calculate_portfolio_var(
            positions, correlations, confidence=0.95
        )
        portfolio_var_99 = self._calculate_portfolio_var(
            positions, correlations, confidence=0.99
        )

        # Calculate risk-adjusted return estimate
        risk_adjusted_return = self._estimate_risk_adjusted_return(
            positions, portfolio_var_95
        )

        metrics = PortfolioRiskMetrics(
            portfolio_id=portfolio_id,
            total_exposure=round(total_exposure, 2),
            concentration_risk=round(concentration_risk, 4),
            correlation_risk=round(correlation_risk, 4),
            portfolio_var_95=round(portfolio_var_95, 2),
            portfolio_var_99=round(portfolio_var_99, 2),
            risk_adjusted_return=round(risk_adjusted_return, 4),
        )

        self._portfolio_risk_history.append(metrics)
        self.logger.info(
            f"Portfolio risk assessment for {portfolio_id}: "
            f"VaR95=${portfolio_var_95:.2f}, concentration={concentration_risk:.2%}"
        )

        return metrics

    def _deduct_decision_cost(self) -> float:
        """Deduct the fixed decision cost for risk assessment.

        Returns:
            Amount deducted, or 0.0 if couldn't afford
        """
        if self.balance < self.decision_cost:
            self.logger.warning(
                f"Cannot afford risk assessment cost of ${self.decision_cost:.2f}"
            )
            return 0.0

        # Deduct from balance
        self.economic_tracker._update_balance(
            -self.decision_cost,
            f"Risk assessment decision cost"
        )
        return self.decision_cost

    def _estimate_volatility(self, symbol: str) -> float:
        """Estimate annualized volatility for a symbol.

        In a real implementation, this would use historical price data.
        This simplified version uses skill-adjusted random estimation.

        Args:
            symbol: The trading symbol

        Returns:
            Annualized volatility as a decimal (e.g., 0.20 for 20%)
        """
        # Base volatility between 15% and 50%
        base_volatility = 0.15 + random.random() * 0.35

        # Higher skill = more accurate estimation (less variance)
        accuracy_factor = 0.7 + self.skill_level * 0.3

        # Some symbols have higher volatility (e.g., tech stocks)
        symbol_factor = 1.0
        high_vol_symbols = ["TSLA", "NVDA", "AMD", "GME", "AMC"]
        if any(s in symbol.upper() for s in high_vol_symbols):
            symbol_factor = 1.3

        volatility = base_volatility * accuracy_factor * symbol_factor
        return min(volatility, 1.0)  # Cap at 100%

    def _calculate_var(
        self,
        volatility: float,
        confidence: float = 0.95,
        position_size: Optional[float] = None,
    ) -> float:
        """Calculate Value at Risk (VaR).

        Uses parametric VaR calculation assuming normal distribution.

        Args:
            volatility: Annualized volatility as decimal
            confidence: Confidence level (0.95 or 0.99)
            position_size: Position size in dollars (defaults to balance)

        Returns:
            VaR amount in dollars
        """
        if position_size is None:
            position_size = self.balance

        # Z-scores for confidence levels
        z_scores = {0.95: 1.645, 0.99: 2.326}
        z_score = z_scores.get(confidence, 1.645)

        # VaR = Position * Z * Volatility
        # For daily VaR, divide volatility by sqrt(252)
        daily_volatility = volatility / math.sqrt(252)
        var = position_size * z_score * daily_volatility

        return var

    def _estimate_max_drawdown(self, volatility: float) -> float:
        """Estimate maximum drawdown based on volatility.

        Uses the formula: MaxDD ≈ -0.5 * volatility * sqrt(time_horizon)
        This is a simplified estimate.

        Args:
            volatility: Annualized volatility

        Returns:
            Estimated maximum drawdown as decimal
        """
        # Simplified estimate: higher volatility = larger drawdowns
        return -volatility * (1.5 + random.random())

    def _classify_risk_level(self, volatility: float) -> str:
        """Classify risk level based on volatility.

        Args:
            volatility: Annualized volatility as decimal

        Returns:
            Risk level string: "low", "medium", "high", or "extreme"
        """
        if volatility < 0.20:
            return "low"
        elif volatility < 0.35:
            return "medium"
        elif volatility < 0.50:
            return "high"
        else:
            return "extreme"

    def _generate_risk_warnings(
        self,
        symbol: str,
        position_size: float,
        volatility: float,
        portfolio: Optional[Dict[str, Any]],
    ) -> List[str]:
        """Generate risk warnings based on position and portfolio context.

        Args:
            symbol: Trading symbol
            position_size: Proposed position size
            volatility: Estimated volatility
            portfolio: Optional portfolio context

        Returns:
            List of warning strings
        """
        warnings = []

        # Volatility warnings
        if volatility > 0.50:
            warnings.append(f"Extreme volatility detected ({volatility:.1%})")
        elif volatility > 0.35:
            warnings.append(f"High volatility ({volatility:.1%})")

        # Position size warnings
        if self.balance > 0:
            position_pct = position_size / self.balance
            if position_pct > self.max_risk_per_trade * 5:
                warnings.append(
                    f"Position size ({position_pct:.1%}) exceeds safe limits"
                )
            elif position_pct > self.max_risk_per_trade * 2:
                warnings.append(f"Large position size ({position_pct:.1%})")

        # Portfolio concentration warning
        if portfolio and "positions" in portfolio:
            total_exposure = sum(
                abs(p.get("size", 0)) for p in portfolio["positions"].values()
            )
            if total_exposure > 0:
                new_exposure = total_exposure + position_size
                concentration = position_size / new_exposure
                if concentration > 0.25:
                    warnings.append(
                        f"High concentration risk ({concentration:.1%} of portfolio)"
                    )

        return warnings

    def _calculate_position_recommendation(
        self,
        requested_size: float,
        volatility: float,
        portfolio: Optional[Dict[str, Any]],
    ) -> float:
        """Calculate recommended position size based on risk parameters.

        Args:
            requested_size: Requested position size
            volatility: Estimated volatility
            portfolio: Optional portfolio context

        Returns:
            Recommended position size in dollars
        """
        # Base recommendation on volatility
        if volatility > 0.50:
            volatility_factor = 0.3  # Very risky - reduce significantly
        elif volatility > 0.35:
            volatility_factor = 0.5  # High risk - reduce
        elif volatility > 0.20:
            volatility_factor = 0.8  # Medium risk - slight reduction
        else:
            volatility_factor = 1.0  # Low risk - use requested size

        # Apply skill level adjustment (higher skill = more confidence)
        skill_factor = 0.7 + self.skill_level * 0.3

        # Maximum risk per trade
        max_risk_amount = self.balance * self.max_risk_per_trade

        # Calculate recommended size
        recommended = requested_size * volatility_factor * skill_factor

        # Cap at max risk
        if volatility > 0:
            var_at_requested = requested_size * volatility * 1.645
            if var_at_requested > max_risk_amount:
                recommended = min(recommended, max_risk_amount / (volatility * 1.645))

        return max(0, recommended)

    def _calculate_concentration_risk(
        self, positions: Dict[str, float]
    ) -> float:
        """Calculate portfolio concentration risk.

        Uses Herfindahl-Hirschman Index (HHI) normalized to 0-1 range.

        Args:
            positions: Dictionary of symbol to position size

        Returns:
            Concentration risk score (0-1, higher = more concentrated)
        """
        if not positions:
            return 0.0

        total = sum(abs(size) for size in positions.values())
        if total == 0:
            return 0.0

        # Calculate weights
        weights = [abs(size) / total for size in positions.values()]

        # HHI = sum of squared weights
        hhi = sum(w ** 2 for w in weights)

        # Normalize to 0-1 (max HHI is 1 for single position)
        return hhi

    def _calculate_correlation_risk(
        self,
        positions: Dict[str, float],
        correlations: Optional[Dict[str, Dict[str, float]]],
    ) -> float:
        """Calculate portfolio correlation risk.

        Args:
            positions: Dictionary of symbol to position size
            correlations: Optional correlation matrix

        Returns:
            Correlation risk score (0-1)
        """
        if not positions or not correlations:
            return 0.0

        symbols = list(positions.keys())
        if len(symbols) < 2:
            return 0.0

        # Calculate average correlation
        correlations_sum = 0.0
        count = 0

        for i, sym1 in enumerate(symbols):
            for sym2 in symbols[i + 1:]:
                corr = correlations.get(sym1, {}).get(sym2, 0.5)
                correlations_sum += abs(corr)
                count += 1

        if count == 0:
            return 0.0

        avg_correlation = correlations_sum / count

        # Risk increases with higher correlation
        return avg_correlation

    def _calculate_portfolio_var(
        self,
        positions: Dict[str, float],
        correlations: Optional[Dict[str, Dict[str, float]]],
        confidence: float = 0.95,
    ) -> float:
        """Calculate portfolio-level VaR using variance-covariance method.

        Args:
            positions: Dictionary of symbol to position size
            correlations: Optional correlation matrix
            confidence: Confidence level

        Returns:
            Portfolio VaR in dollars
        """
        if not positions:
            return 0.0

        # Z-score for confidence level
        z_scores = {0.95: 1.645, 0.99: 2.326}
        z_score = z_scores.get(confidence, 1.645)

        # Estimate volatilities for each position
        volatilities = {
            symbol: self._estimate_volatility(symbol)
            for symbol in positions.keys()
        }

        # Calculate portfolio variance
        portfolio_variance = 0.0
        symbols = list(positions.keys())

        for i, sym1 in enumerate(symbols):
            for j, sym2 in enumerate(symbols):
                weight_i = positions[sym1] / math.sqrt(252)  # Daily
                weight_j = positions[sym2] / math.sqrt(252)

                vol_i = volatilities[sym1]
                vol_j = volatilities[sym2]

                if i == j:
                    corr = 1.0
                else:
                    corr = correlations.get(sym1, {}).get(sym2, 0.5) if correlations else 0.5

                portfolio_variance += weight_i * weight_j * vol_i * vol_j * corr

        portfolio_volatility = math.sqrt(max(0, portfolio_variance))
        portfolio_var = portfolio_volatility * z_score

        return abs(portfolio_var)

    def _estimate_risk_adjusted_return(
        self,
        positions: Dict[str, float],
        portfolio_var: float,
    ) -> float:
        """Estimate risk-adjusted return (Sharpe-like ratio).

        Args:
            positions: Dictionary of symbol to position size
            portfolio_var: Portfolio VaR

        Returns:
            Estimated risk-adjusted return
        """
        if portfolio_var <= 0:
            return 0.0

        # Estimate expected return based on positions and skill
        total_exposure = sum(abs(size) for size in positions.values())
        if total_exposure == 0:
            return 0.0

        # Higher skill = better expected risk-adjusted return
        expected_return = self.skill_level * 0.1  # 0-10% based on skill

        return expected_return / (portfolio_var / total_exposure)

    def get_risk_history(self) -> List[RiskReport]:
        """Get historical risk assessments.

        Returns:
            List of RiskReport objects
        """
        return self._risk_history.copy()

    def get_portfolio_risk_history(self) -> List[PortfolioRiskMetrics]:
        """Get historical portfolio risk assessments.

        Returns:
            List of PortfolioRiskMetrics objects
        """
        return self._portfolio_risk_history.copy()

    def get_latest_risk_assessment(self, symbol: str) -> Optional[RiskReport]:
        """Get the most recent risk assessment for a symbol.

        Args:
            symbol: Trading symbol

        Returns:
            Most recent RiskReport or None
        """
        for report in reversed(self._risk_history):
            if report.symbol == symbol:
                return report
        return None

    def clear_history(self) -> None:
        """Clear all risk assessment history."""
        self._risk_history.clear()
        self._portfolio_risk_history.clear()


@dataclass
class SurvivalRiskConfig:
    """Configuration for survival-based risk limits.

    Attributes:
        position_size_limits: Max position size by survival status
        single_trade_risk_limits: Max risk per trade by status
        stop_loss_multipliers: Stop loss adjustment by status
        min_skill_for_trade: Minimum skill level required to trade
    """

    # Position size limits as % of portfolio by status
    position_size_limits: Dict[str, float] = field(default_factory=lambda: {
        SurvivalStatus.THRIVING.value: 0.25,    # Can take bigger positions
        SurvivalStatus.STABLE.value: 0.20,      # Normal positions
        SurvivalStatus.STRUGGLING.value: 0.10,  # Smaller positions
        SurvivalStatus.CRITICAL.value: 0.05,    # Minimal positions
        SurvivalStatus.BANKRUPT.value: 0.0,     # No trading
    })

    # Single trade risk limits as % of portfolio by status
    single_trade_risk_limits: Dict[str, float] = field(default_factory=lambda: {
        SurvivalStatus.THRIVING.value: 0.03,    # 3% max risk per trade
        SurvivalStatus.STABLE.value: 0.02,      # 2% max risk per trade
        SurvivalStatus.STRUGGLING.value: 0.01,  # 1% max risk per trade
        SurvivalStatus.CRITICAL.value: 0.005,   # 0.5% max risk (minimal)
        SurvivalStatus.BANKRUPT.value: 0.0,     # No risk allowed
    })

    # Stop loss multipliers by status (tighter stops when struggling)
    stop_loss_multipliers: Dict[str, float] = field(default_factory=lambda: {
        SurvivalStatus.THRIVING.value: 1.5,     # Wider stops (2% * 1.5 = 3%)
        SurvivalStatus.STABLE.value: 1.0,       # Normal stops (2%)
        SurvivalStatus.STRUGGLING.value: 0.7,   # Tighter stops (1.4%)
        SurvivalStatus.CRITICAL.value: 0.5,     # Very tight stops (1%)
        SurvivalStatus.BANKRUPT.value: 0.0,     # No trading
    })

    min_skill_for_trade: float = 0.3


@dataclass
class SurvivalRiskCheckResult:
    """Result of survival-based risk check.

    Attributes:
        is_allowed: Whether the trade is allowed
        reason: Reason for decision
        max_position_size: Maximum allowed position size
        max_risk_amount: Maximum risk amount allowed
        adjusted_stop_loss: Adjusted stop loss percentage
        risk_metrics: Additional risk metrics
    """

    is_allowed: bool
    reason: str
    max_position_size: float
    max_risk_amount: float
    adjusted_stop_loss: float
    risk_metrics: Dict[str, Any] = field(default_factory=dict)


class SurvivalRiskManager:
    """Risk manager that adapts limits based on survival status.

    Implements survival-based risk controls where stricter limits are applied
    when the agent is in critical or struggling states, and more freedom
    is given when thriving.

    Args:
        base_risk_manager: The underlying RiskManager instance
        config: Survival risk configuration
    """

    def __init__(
        self,
        base_risk_manager: RiskManager,
        config: Optional[SurvivalRiskConfig] = None,
    ):
        self.risk_manager = base_risk_manager
        self.config = config or SurvivalRiskConfig()
        self._interception_history: List[Dict[str, Any]] = []
        self.logger = get_logger(
            f"agents.survival_risk.{base_risk_manager.agent_id}"
        )

    @property
    def survival_status(self) -> SurvivalStatus:
        """Current survival status from the base risk manager."""
        return self.risk_manager.survival_status

    @property
    def balance(self) -> float:
        """Current balance from the base risk manager."""
        return self.risk_manager.balance

    def check_trade_allowed(
        self,
        symbol: str,
        position_size: float,
        stop_loss_pct: float = 0.02,
    ) -> SurvivalRiskCheckResult:
        """Check if a trade is allowed based on survival status.

        Args:
            symbol: Trading symbol
            position_size: Proposed position size
            stop_loss_pct: Default stop loss percentage (e.g., 0.02 = 2%)

        Returns:
            SurvivalRiskCheckResult with decision and adjusted parameters
        """
        status = self.survival_status
        status_value = status.value

        # Get limits for current status
        max_position_pct = self.config.position_size_limits.get(
            status_value, 0.05
        )
        max_risk_pct = self.config.single_trade_risk_limits.get(
            status_value, 0.005
        )
        stop_multiplier = self.config.stop_loss_multipliers.get(
            status_value, 0.5
        )

        # Calculate actual limits
        max_position_size = self.balance * max_position_pct
        max_risk_amount = self.balance * max_risk_pct
        adjusted_stop = stop_loss_pct * stop_multiplier

        # Build risk metrics
        risk_metrics = {
            "survival_status": status_value,
            "skill_level": self.risk_manager.skill_level,
            "max_position_pct": max_position_pct,
            "max_risk_pct": max_risk_pct,
            "stop_multiplier": stop_multiplier,
        }

        # Check survival status
        if status == SurvivalStatus.BANKRUPT:
            reason = "Trade blocked: Agent is bankrupt"
            self._log_interception(symbol, position_size, reason, risk_metrics)
            return SurvivalRiskCheckResult(
                is_allowed=False,
                reason=reason,
                max_position_size=0.0,
                max_risk_amount=0.0,
                adjusted_stop_loss=0.0,
                risk_metrics=risk_metrics,
            )

        if status == SurvivalStatus.CRITICAL:
            # In critical state, only allow minimal trades
            if position_size > max_position_size:
                reason = (
                    f"Trade blocked: Position size ${position_size:,.2f} exceeds "
                    f"critical state limit of ${max_position_size:,.2f}"
                )
                self._log_interception(symbol, position_size, reason, risk_metrics)
                return SurvivalRiskCheckResult(
                    is_allowed=False,
                    reason=reason,
                    max_position_size=max_position_size,
                    max_risk_amount=max_risk_amount,
                    adjusted_stop_loss=adjusted_stop,
                    risk_metrics=risk_metrics,
                )

            reason = (
                f"Trade allowed with critical state restrictions: "
                f"max_size=${max_position_size:,.2f}, max_risk={max_risk_pct:.2%}"
            )
            self.logger.warning(f"CRITICAL state trade: {symbol} ${position_size:,.2f}")

        elif status == SurvivalStatus.STRUGGLING:
            # In struggling state, reduce position sizes
            if position_size > max_position_size:
                reason = (
                    f"Trade blocked: Position size ${position_size:,.2f} exceeds "
                    f"struggling state limit of ${max_position_size:,.2f}"
                )
                self._log_interception(symbol, position_size, reason, risk_metrics)
                return SurvivalRiskCheckResult(
                    is_allowed=False,
                    reason=reason,
                    max_position_size=max_position_size,
                    max_risk_amount=max_risk_amount,
                    adjusted_stop_loss=adjusted_stop,
                    risk_metrics=risk_metrics,
                )

            reason = (
                f"Trade allowed with reduced risk: "
                f"max_size=${max_position_size:,.2f} ({max_position_pct:.0%})"
            )

        elif status == SurvivalStatus.STABLE:
            reason = "Trade allowed with normal risk limits"

        elif status == SurvivalStatus.THRIVING:
            # Thriving state - can take more risk
            reason = (
                f"Trade allowed with elevated risk tolerance: "
                f"max_size=${max_position_size:,.2f} ({max_position_pct:.0%})"
            )

        else:
            reason = "Trade allowed"

        # Check skill level
        if self.risk_manager.skill_level < self.config.min_skill_for_trade:
            skill_reason = (
                f"Trade blocked: Skill level {self.risk_manager.skill_level:.1%} "
                f"below minimum {self.config.min_skill_for_trade:.1%}"
            )
            self._log_interception(symbol, position_size, skill_reason, risk_metrics)
            return SurvivalRiskCheckResult(
                is_allowed=False,
                reason=skill_reason,
                max_position_size=max_position_size,
                max_risk_amount=max_risk_amount,
                adjusted_stop_loss=adjusted_stop,
                risk_metrics=risk_metrics,
            )

        return SurvivalRiskCheckResult(
            is_allowed=True,
            reason=reason,
            max_position_size=max_position_size,
            max_risk_amount=max_risk_amount,
            adjusted_stop_loss=adjusted_stop,
            risk_metrics=risk_metrics,
        )

    def calculate_position_size(
        self,
        symbol: str,
        volatility: float,
        target_risk_pct: Optional[float] = None,
    ) -> float:
        """Calculate recommended position size based on survival status.

        Args:
            symbol: Trading symbol
            volatility: Estimated volatility
            target_risk_pct: Target risk percentage (optional)

        Returns:
            Recommended position size
        """
        status = self.survival_status
        status_value = status.value

        # Get max position and risk limits
        max_position_pct = self.config.position_size_limits.get(status_value, 0.05)
        max_risk_pct = self.config.single_trade_risk_limits.get(status_value, 0.005)

        if target_risk_pct:
            max_risk_pct = min(max_risk_pct, target_risk_pct)

        max_position_size = self.balance * max_position_pct

        # Calculate position size based on volatility and risk limit
        # Position = Risk Amount / (Volatility * Z-score)
        if volatility > 0:
            z_score = 1.645  # 95% confidence
            risk_based_position = (self.balance * max_risk_pct) / (volatility * z_score)
            recommended_size = min(max_position_size, risk_based_position)
        else:
            recommended_size = max_position_size * 0.5  # Conservative default

        self.logger.info(
            f"Calculated position for {symbol}: ${recommended_size:,.2f} "
            f"(status={status_value}, vol={volatility:.1%})"
        )

        return recommended_size

    def adjust_stop_loss(
        self,
        base_stop_loss_pct: float = 0.02,
        volatility: Optional[float] = None,
    ) -> float:
        """Adjust stop loss based on survival status and volatility.

        Args:
            base_stop_loss_pct: Base stop loss percentage
            volatility: Optional volatility for adjustment

        Returns:
            Adjusted stop loss percentage
        """
        status = self.survival_status
        status_value = status.value

        # Get multiplier for current status
        multiplier = self.config.stop_loss_multipliers.get(status_value, 1.0)

        # Adjust for volatility if provided
        vol_adjustment = 1.0
        if volatility:
            if volatility > 0.5:
                vol_adjustment = 1.5  # Wider stops for high volatility
            elif volatility < 0.15:
                vol_adjustment = 0.8  # Tighter stops for low volatility

        adjusted_stop = base_stop_loss_pct * multiplier * vol_adjustment

        # Cap at reasonable limits
        adjusted_stop = max(0.005, min(0.1, adjusted_stop))

        return adjusted_stop

    def get_risk_limits(self) -> Dict[str, Any]:
        """Get current risk limits based on survival status.

        Returns:
            Dictionary with current risk limits
        """
        status = self.survival_status
        status_value = status.value

        return {
            "survival_status": status_value,
            "balance": self.balance,
            "skill_level": self.risk_manager.skill_level,
            "position_size_limit": self.config.position_size_limits.get(status_value, 0.0),
            "single_trade_risk_limit": self.config.single_trade_risk_limits.get(status_value, 0.0),
            "stop_loss_multiplier": self.config.stop_loss_multipliers.get(status_value, 1.0),
            "min_skill_for_trade": self.config.min_skill_for_trade,
        }

    def _log_interception(
        self,
        symbol: str,
        position_size: float,
        reason: str,
        risk_metrics: Dict[str, Any],
    ) -> None:
        """Log a risk interception event.

        Args:
            symbol: Trading symbol
            position_size: Attempted position size
            reason: Interception reason
            risk_metrics: Risk metrics at time of interception
        """
        interception = {
            "timestamp": datetime.now().isoformat(),
            "symbol": symbol,
            "attempted_position_size": position_size,
            "reason": reason,
            "survival_status": self.survival_status.value,
            "balance": self.balance,
            **risk_metrics,
        }

        self._interception_history.append(interception)
        self.logger.warning(f"Risk interception: {symbol} - {reason}")

    def get_interception_history(self) -> List[Dict[str, Any]]:
        """Get history of risk interceptions.

        Returns:
            List of interception records
        """
        return self._interception_history.copy()

    def clear_interception_history(self) -> None:
        """Clear interception history."""
        self._interception_history.clear()

    async def assess_risk_with_survival(
        self,
        symbol: str,
        position_size: float,
        portfolio: Optional[Dict[str, Any]] = None,
    ) -> RiskReport:
        """Assess risk with survival-based adjustments.

        This wraps the base RiskManager's assess_risk with additional
        survival-based checks and adjustments.

        Args:
            symbol: Trading symbol
            position_size: Proposed position size
            portfolio: Optional portfolio context

        Returns:
            RiskReport with survival-aware recommendations
        """
        # First, check survival-based limits
        survival_check = self.check_trade_allowed(symbol, position_size)

        # Get base risk assessment
        base_report = await self.risk_manager.assess_risk(
            symbol, position_size, portfolio
        )

        # Override recommendation with survival-based limits
        if not survival_check.is_allowed:
            # If survival check blocks, set recommendation to 0
            base_report.position_size_recommendation = 0.0
            base_report.warnings.append(
                f"SURVIVAL BLOCK: {survival_check.reason}"
            )
            base_report.risk_level = "extreme"
        else:
            # Apply survival-based position sizing
            recommended = min(
                base_report.position_size_recommendation,
                survival_check.max_position_size,
            )
            base_report.position_size_recommendation = recommended

            # Add survival info to warnings
            if self.survival_status in [SurvivalStatus.CRITICAL, SurvivalStatus.STRUGGLING]:
                base_report.warnings.append(
                    f"SURVIVAL MODE ({self.survival_status.value}): "
                    f"Adjusted stop loss to {survival_check.adjusted_stop_loss:.2%}"
                )

        return base_report
