"""TraderAgent implementation for OpenClaw trading system.

This module provides the TraderAgent class that can analyze markets,
generate trading signals, and execute trades with proper cost tracking.
"""

from __future__ import annotations

import random
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional

from openclaw.agents.base import ActivityType, BaseAgent
from openclaw.core.economy import SurvivalStatus
from openclaw.core.work_trade_balance import (
    ActivityDecision as WtbActivityDecision,
    WorkTradeBalance,
    WorkTradeConfig,
)


class SignalType(str, Enum):
    """Trading signal types."""

    BUY = "buy"
    SELL = "sell"
    HOLD = "hold"


@dataclass
class TradeSignal:
    """Trading signal generated by analysis."""

    symbol: str
    signal: SignalType
    confidence: float
    reason: str
    suggested_position: float = 0.0


@dataclass
class TradeResult:
    """Result of a trade execution."""

    symbol: str
    signal: SignalType
    success: bool
    pnl: float
    fee: float
    message: str
    timestamp: str = ""

    def __post_init__(self):
        """Set timestamp if not provided."""
        if not self.timestamp:
            self.timestamp = datetime.now().isoformat()


@dataclass
class MarketAnalysis:
    """Market analysis result."""

    symbol: str
    trend: str
    volatility: float
    volume_trend: str
    support_level: float
    resistance_level: float
    indicators: Dict[str, float]


class TraderAgent(BaseAgent):
    """Trading agent that can analyze markets and execute trades.

    The TraderAgent inherits from BaseAgent and implements the core trading
    logic including market analysis, signal generation, and trade execution.

    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_position_pct: Maximum position size as percentage of balance
    """

    def __init__(
        self,
        agent_id: str,
        initial_capital: float,
        skill_level: float = 0.5,
        max_position_pct: float = 0.2,
    ):
        super().__init__(agent_id, initial_capital, skill_level)
        self.max_position_pct = max_position_pct
        self._trade_history: List[TradeResult] = []
        self._paper_trade_history: List[TradeResult] = []
        self._last_analysis: Optional[MarketAnalysis] = None
        self._work_trade_balance: Optional[WorkTradeBalance] = None

    def set_work_trade_balance(self, balance: WorkTradeBalance) -> None:
        """Inject WorkTradeBalance for activity decisions (TASK-021)."""
        self._work_trade_balance = balance

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

        The decision logic considers:
        - WorkTradeBalance if set (TASK-021: work-learning decision)
        - Survival status (bankrupt agents can't trade)
        - Skill level (lower skill agents should paper trade more)
        - Balance state (struggling agents should rest/learn more)

        Returns:
            The activity type to perform
        """
        if self._work_trade_balance is not None:
            import random
            wtb_decision = self._work_trade_balance.decide_activity(
                skill_level=self.skill_level,
                win_rate=self.win_rate,
                random_draw=random.random(),
            )
            if wtb_decision == WtbActivityDecision.LEARN:
                return ActivityType.LEARN
            if wtb_decision == WtbActivityDecision.MINIMAL_TRADE:
                return ActivityType.PAPER_TRADE
            if wtb_decision == WtbActivityDecision.PAPER_TRADE:
                return ActivityType.PAPER_TRADE
            if wtb_decision == WtbActivityDecision.TRADE:
                return ActivityType.TRADE

        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, minimal paper trading
        if status == SurvivalStatus.CRITICAL:
            if self.skill_level < 0.7:
                return ActivityType.LEARN
            return ActivityType.PAPER_TRADE

        # Struggling - more paper trading, less real trading
        if status == SurvivalStatus.STRUGGLING:
            if random.random() < 0.6:  # 60% chance to paper trade
                return ActivityType.PAPER_TRADE
            if self.skill_level < 0.6:
                return ActivityType.LEARN
            return ActivityType.ANALYZE

        # Stable - balanced approach
        if status == SurvivalStatus.STABLE:
            if random.random() < 0.3:  # 30% chance to paper trade
                return ActivityType.PAPER_TRADE
            if self.skill_level < 0.5:
                return ActivityType.LEARN
            return ActivityType.TRADE

        # Thriving - can take more risks
        if status == SurvivalStatus.THRIVING:
            if random.random() < 0.1:  # 10% chance to paper trade
                return ActivityType.PAPER_TRADE
            return ActivityType.TRADE

        # Default to analyze
        return ActivityType.ANALYZE

    async def analyze(self, symbol: str) -> Dict[str, Any]:
        """Analyze a trading symbol and return comprehensive analysis.

        This method performs market analysis and generates a trading signal.

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

        Returns:
            Dictionary containing analysis results and trading signal
        """
        # Deduct decision cost for analysis
        cost = self.economic_tracker.calculate_decision_cost(
            tokens_input=500,
            tokens_output=200,
            market_data_calls=1,
        )
        self.logger.info(f"Analysis cost for {symbol}: ${cost:.4f}")

        # Perform market analysis
        market_analysis = self.analyze_market(symbol)
        self._last_analysis = market_analysis

        # Generate trading signal
        signal = self.generate_signal(market_analysis)

        return {
            "symbol": symbol,
            "signal": signal.signal.value,
            "confidence": signal.confidence,
            "reason": signal.reason,
            "suggested_position": signal.suggested_position,
            "market_analysis": {
                "trend": market_analysis.trend,
                "volatility": market_analysis.volatility,
                "volume_trend": market_analysis.volume_trend,
                "support_level": market_analysis.support_level,
                "resistance_level": market_analysis.resistance_level,
                "indicators": market_analysis.indicators,
            },
            "cost": cost,
        }

    def analyze_market(self, symbol: str) -> MarketAnalysis:
        """Analyze market conditions for a symbol.

        This is a simplified market analysis implementation. In production,
        this would fetch real market data and calculate technical indicators.

        Args:
            symbol: The symbol to analyze

        Returns:
            MarketAnalysis object with market conditions
        """
        # Simulate market analysis with some randomness
        # In production, this would use real market data

        # Randomize based on skill level (higher skill = more accurate analysis)
        accuracy_factor = self.skill_level

        # Generate simulated indicators
        rsi = 30 + random.random() * 40  # RSI between 30 and 70
        macd = (random.random() - 0.5) * 2  # MACD between -1 and 1
        sma_20 = 100 + random.random() * 10
        current_price = sma_20 * (0.95 + random.random() * 0.1)

        # Adjust by skill level (higher skill = closer to "true" values)
        if accuracy_factor > 0.7:
            rsi = 40 + random.random() * 20  # More accurate, less variance

        # Determine trend
        if current_price > sma_20 * 1.02:
            trend = "uptrend"
        elif current_price < sma_20 * 0.98:
            trend = "downtrend"
        else:
            trend = "sideways"

        # Determine volume trend
        volume_trend = "increasing" if random.random() > 0.5 else "decreasing"

        return MarketAnalysis(
            symbol=symbol,
            trend=trend,
            volatility=random.random() * 0.3,
            volume_trend=volume_trend,
            support_level=current_price * 0.95,
            resistance_level=current_price * 1.05,
            indicators={
                "rsi": round(rsi, 2),
                "macd": round(macd, 4),
                "sma_20": round(sma_20, 2),
                "current_price": round(current_price, 2),
            },
        )

    def generate_signal(self, analysis: MarketAnalysis) -> TradeSignal:
        """Generate a trading signal based on market analysis.

        Args:
            analysis: MarketAnalysis object with market conditions

        Returns:
            TradeSignal with buy/sell/hold recommendation
        """
        indicators = analysis.indicators
        rsi = indicators.get("rsi", 50)
        macd = indicators.get("macd", 0)

        # Signal logic based on RSI and MACD
        if rsi < 35 and macd > 0:
            signal = SignalType.BUY
            confidence = min(0.9, 0.6 + self.skill_level * 0.3)
            reason = f"Oversold (RSI: {rsi:.1f}) with positive momentum"
        elif rsi > 65 and macd < 0:
            signal = SignalType.SELL
            confidence = min(0.9, 0.6 + self.skill_level * 0.3)
            reason = f"Overbought (RSI: {rsi:.1f}) with negative momentum"
        else:
            signal = SignalType.HOLD
            confidence = 0.5
            reason = f"No clear signal (RSI: {rsi:.1f}, MACD: {macd:.4f})"

        # Calculate suggested position size
        if signal != SignalType.HOLD:
            # Base position on confidence and skill
            position_pct = self.max_position_pct * confidence * (0.5 + self.skill_level * 0.5)
            suggested_position = self.balance * position_pct
        else:
            suggested_position = 0.0

        return TradeSignal(
            symbol=analysis.symbol,
            signal=signal,
            confidence=confidence,
            reason=reason,
            suggested_position=round(suggested_position, 2),
        )

    def execute_trade(
        self,
        symbol: str,
        signal: SignalType,
        amount: float,
    ) -> TradeResult:
        """Execute a real trade with cost deduction.

        Args:
            symbol: The trading symbol
            signal: Buy or sell signal
            amount: Trade amount in dollars

        Returns:
            TradeResult with execution details
        """
        # Check if agent can afford this trade
        if not self.can_afford(amount):
            return TradeResult(
                symbol=symbol,
                signal=signal,
                success=False,
                pnl=0.0,
                fee=0.0,
                message=f"Insufficient funds for ${amount:.2f} trade",
            )

        # Calculate trade cost (fee)
        trade_value = amount

        # Simulate trade outcome with some randomness
        # Higher skill = higher probability of winning
        win_probability = 0.4 + self.skill_level * 0.3  # 0.4 to 0.7
        is_win = random.random() < win_probability

        # Simulate PnL based on win/loss and skill
        if is_win:
            pnl_pct = random.uniform(0.01, 0.05) * (1 + self.skill_level)
            gross_pnl = trade_value * pnl_pct
        else:
            pnl_pct = random.uniform(-0.05, -0.01)
            gross_pnl = trade_value * pnl_pct

        # Calculate and apply trade cost
        result = self.economic_tracker.calculate_trade_cost(
            trade_value=trade_value,
            is_win=is_win,
            win_amount=gross_pnl if gross_pnl > 0 else 0,
            loss_amount=abs(gross_pnl) if gross_pnl < 0 else 0,
        )

        # Record trade outcome
        self.record_trade(is_win=is_win, pnl=result.pnl)

        # Create trade result
        trade_result = TradeResult(
            symbol=symbol,
            signal=signal,
            success=True,
            pnl=result.pnl,
            fee=result.fee,
            message=f"Trade executed: {'WIN' if is_win else 'LOSS'} ${abs(result.pnl):.2f}",
        )

        self._trade_history.append(trade_result)

        self.logger.info(
            f"Trade executed: {symbol} {signal.value} ${amount:.2f} -> "
            f"{'WIN' if is_win else 'LOSS'} ${abs(result.pnl):.2f} (fee: ${result.fee:.2f})"
        )

        return trade_result

    def paper_trade(
        self,
        symbol: str,
        signal: SignalType,
        amount: float,
    ) -> TradeResult:
        """Execute a paper trade (simulation) without real cost.

        Paper trading allows agents to practice without risking real capital.
        Only small data costs are deducted, not trade fees or PnL.

        Args:
            symbol: The trading symbol
            signal: Buy or sell signal
            amount: Trade amount in dollars

        Returns:
            TradeResult with simulation results
        """
        # Deduct minimal cost for data/execution
        cost = self.economic_tracker.calculate_decision_cost(
            tokens_input=100,
            tokens_output=50,
            market_data_calls=1,
        )

        # Simulate trade outcome
        win_probability = 0.4 + self.skill_level * 0.3
        is_win = random.random() < win_probability

        if is_win:
            pnl_pct = random.uniform(0.01, 0.05) * (1 + self.skill_level)
            pnl = amount * pnl_pct
        else:
            pnl_pct = random.uniform(-0.05, -0.01)
            pnl = amount * pnl_pct

        # Calculate fee (for tracking only, not deducted from balance)
        fee = trade_value * self.economic_tracker.trade_fee_rate if (trade_value := amount) else 0

        # Don't record trade statistics for paper trades
        # But do record the result for analysis

        trade_result = TradeResult(
            symbol=symbol,
            signal=signal,
            success=True,
            pnl=pnl,  # Paper PnL, not realized
            fee=fee,  # Paper fee, not deducted
            message=f"Paper trade: {'WIN' if is_win else 'LOSS'} ${abs(pnl):.2f} (cost: ${cost:.4f})",
        )

        self._paper_trade_history.append(trade_result)

        self.logger.info(
            f"Paper trade: {symbol} {signal.value} ${amount:.2f} -> "
            f"{'WIN' if is_win else 'LOSS'} ${abs(pnl):.2f} (data cost: ${cost:.4f})"
        )

        return trade_result

    def get_trade_history(self) -> List[TradeResult]:
        """Get real trade history."""
        return self._trade_history.copy()

    def get_paper_trade_history(self) -> List[TradeResult]:
        """Get paper trade history."""
        return self._paper_trade_history.copy()

    def get_performance_stats(self) -> Dict[str, Any]:
        """Get trading performance statistics."""
        real_trades = self._trade_history
        paper_trades = self._paper_trade_history

        real_pnl = sum(t.pnl for t in real_trades)
        paper_pnl = sum(t.pnl for t in paper_trades)

        return {
            "total_real_trades": len(real_trades),
            "total_paper_trades": len(paper_trades),
            "real_pnl": round(real_pnl, 2),
            "paper_pnl": round(paper_pnl, 2),
            "win_rate": self.win_rate,
            "skill_level": self.skill_level,
            "balance": self.balance,
            "survival_status": self.survival_status.value,
        }
