"""FundamentalAnalyst agent implementation for OpenClaw trading system.

This module provides the FundamentalAnalyst class that performs fundamental
analysis on stocks, calculating valuation metrics, profitability ratios, and
growth indicators to generate a comprehensive fundamental score.
"""

from __future__ import annotations

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

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


class ValuationRecommendation(str, Enum):
    """Fundamental valuation recommendation."""

    UNDERVALUED = "undervalued"
    FAIR = "fair"
    OVERVALUED = "overvalued"


@dataclass
class FundamentalReport:
    """Fundamental analysis report for a stock.

    Attributes:
        symbol: Stock symbol
        valuation_metrics: Valuation metrics (PE, PB, etc.)
        profitability_metrics: Profitability metrics (ROE, ROA, etc.)
        growth_metrics: Growth metrics (revenue growth, etc.)
        overall_score: Overall fundamental score (0-100)
        recommendation: Valuation recommendation
        timestamp: Report generation timestamp
    """

    symbol: str
    valuation_metrics: Dict[str, float]
    profitability_metrics: Dict[str, float]
    growth_metrics: Dict[str, float]
    overall_score: float
    recommendation: str
    timestamp: str = ""

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


class FundamentalAnalyst(BaseAgent):
    """Fundamental analysis agent for evaluating stock fundamentals.

    The FundamentalAnalyst inherits from BaseAgent and provides comprehensive
    fundamental analysis including valuation metrics, profitability ratios,
    and growth indicators. It generates a fundamental score and recommendation.

    Decision cost: $0.10 per analysis

    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)
    """

    decision_cost = 0.10

    # Thresholds for valuation metrics
    PE_THRESHOLD_LOW = 15.0  # Considered undervalued below this
    PE_THRESHOLD_HIGH = 30.0  # Considered overvalued above this
    PB_THRESHOLD_LOW = 1.0  # Considered undervalued below this
    PB_THRESHOLD_HIGH = 3.0  # Considered overvalued above this
    ROE_THRESHOLD = 0.15  # 15% ROE considered good
    ROA_THRESHOLD = 0.08  # 8% ROA considered good
    GROWTH_THRESHOLD = 0.10  # 10% growth considered good

    def __init__(
        self,
        agent_id: str,
        initial_capital: float,
        skill_level: float = 0.5,
    ):
        super().__init__(agent_id, initial_capital, skill_level)
        self._last_report: Optional[FundamentalReport] = None

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

        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.PAPER_TRADE

        # Struggling - more paper trading, less real analysis
        if status == SurvivalStatus.STRUGGLING:
            if self.balance < self.decision_cost * 5:
                return ActivityType.LEARN
            return ActivityType.PAPER_TRADE

        # Stable and thriving - perform analysis
        if self.can_afford(self.decision_cost):
            return ActivityType.ANALYZE

        return ActivityType.REST

    async def analyze(self, symbol: str) -> Dict[str, Any]:
        """Analyze a stock's fundamentals and return the report.

        This is the standard BaseAgent analysis interface that calls
        analyze_fundamentals internally.

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

        Returns:
            Dictionary containing fundamental analysis results
        """
        report = await self.analyze_fundamentals(symbol)
        return {
            "symbol": report.symbol,
            "overall_score": report.overall_score,
            "recommendation": report.recommendation,
            "valuation_metrics": report.valuation_metrics,
            "profitability_metrics": report.profitability_metrics,
            "growth_metrics": report.growth_metrics,
            "cost": self.decision_cost,
        }

    async def analyze_fundamentals(self, symbol: str) -> FundamentalReport:
        """Perform fundamental analysis on a stock.

        Deducts the decision cost ($0.10) and generates a comprehensive
        fundamental analysis report including valuation metrics, profitability
        ratios, and growth indicators.

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

        Returns:
            FundamentalReport with analysis results
        """
        # Deduct decision cost for fundamental analysis
        self.economic_tracker.balance -= self.decision_cost
        self.logger.info(
            f"Fundamental analysis cost for {symbol}: ${self.decision_cost:.2f}"
        )

        # Fetch fundamental data (simulated for now)
        fundamental_data = self._fetch_fundamental_data(symbol)

        # Calculate metrics
        valuation_metrics = self._calculate_valuation_metrics(fundamental_data)
        profitability_metrics = self._calculate_profitability_metrics(fundamental_data)
        growth_metrics = self._calculate_growth_metrics(fundamental_data)

        # Calculate overall score
        overall_score = self._calculate_overall_score(
            valuation_metrics, profitability_metrics, growth_metrics
        )

        # Generate recommendation
        recommendation = self._generate_recommendation(
            overall_score, valuation_metrics
        )

        report = FundamentalReport(
            symbol=symbol,
            valuation_metrics=valuation_metrics,
            profitability_metrics=profitability_metrics,
            growth_metrics=growth_metrics,
            overall_score=overall_score,
            recommendation=recommendation,
        )

        self._last_report = report

        self.logger.info(
            f"Fundamental analysis for {symbol}: score={overall_score:.1f}, "
            f"recommendation={recommendation}"
        )

        return report

    def _fetch_fundamental_data(self, symbol: str) -> Dict[str, Any]:
        """Fetch fundamental data for a stock.

        This is a simplified implementation. In production, this would
        fetch real financial data from a data source.

        Args:
            symbol: The stock symbol

        Returns:
            Dictionary with fundamental data
        """
        # Simulate fundamental data based on symbol
        # Higher skill = more accurate data
        import random

        # Seed random with symbol for consistency
        random.seed(symbol + str(datetime.now().date()))

        # Base values with some randomness
        base_price = random.uniform(50, 500)
        eps = random.uniform(2, 20)
        book_value = random.uniform(20, 200)
        revenue = random.uniform(1e9, 1e12)
        net_income = revenue * random.uniform(0.05, 0.25)
        total_assets = revenue * random.uniform(0.5, 2.0)
        shareholders_equity = total_assets * random.uniform(0.3, 0.7)

        # Growth rates
        revenue_growth = random.uniform(-0.1, 0.3)
        earnings_growth = random.uniform(-0.1, 0.4)

        # Adjust by skill level (higher skill = more realistic data)
        accuracy_factor = 0.7 + self.skill_level * 0.3

        return {
            "symbol": symbol,
            "price": base_price,
            "eps": eps * accuracy_factor,
            "book_value": book_value * accuracy_factor,
            "revenue": revenue,
            "net_income": net_income * accuracy_factor,
            "total_assets": total_assets,
            "shareholders_equity": shareholders_equity * accuracy_factor,
            "revenue_growth": revenue_growth * accuracy_factor,
            "earnings_growth": earnings_growth * accuracy_factor,
            "debt_to_equity": random.uniform(0.1, 1.5),
        }

    def _calculate_valuation_metrics(self, data: Dict[str, Any]) -> Dict[str, float]:
        """Calculate valuation metrics from fundamental data.

        Args:
            data: Fundamental data dictionary

        Returns:
            Dictionary with valuation metrics (PE, PB, etc.)
        """
        price = data.get("price", 0)
        eps = data.get("eps", 0)
        book_value = data.get("book_value", 0)

        # Price to Earnings (PE)
        pe_ratio = price / eps if eps > 0 else float("inf")

        # Price to Book (PB)
        pb_ratio = price / book_value if book_value > 0 else float("inf")

        # Market Cap (approximate)
        shares_outstanding = data.get("revenue", 0) / price if price > 0 else 0
        market_cap = price * shares_outstanding

        return {
            "pe_ratio": round(pe_ratio, 2),
            "pb_ratio": round(pb_ratio, 2),
            "market_cap": round(market_cap, 0),
        }

    def _calculate_profitability_metrics(self, data: Dict[str, Any]) -> Dict[str, float]:
        """Calculate profitability metrics from fundamental data.

        Args:
            data: Fundamental data dictionary

        Returns:
            Dictionary with profitability metrics (ROE, ROA, etc.)
        """
        net_income = data.get("net_income", 0)
        total_assets = data.get("total_assets", 0)
        shareholders_equity = data.get("shareholders_equity", 0)
        revenue = data.get("revenue", 0)

        # Return on Equity (ROE)
        roe = net_income / shareholders_equity if shareholders_equity > 0 else 0

        # Return on Assets (ROA)
        roa = net_income / total_assets if total_assets > 0 else 0

        # Net Profit Margin
        profit_margin = net_income / revenue if revenue > 0 else 0

        return {
            "roe": round(roe, 4),
            "roa": round(roa, 4),
            "profit_margin": round(profit_margin, 4),
        }

    def _calculate_growth_metrics(self, data: Dict[str, Any]) -> Dict[str, float]:
        """Calculate growth metrics from fundamental data.

        Args:
            data: Fundamental data dictionary

        Returns:
            Dictionary with growth metrics
        """
        return {
            "revenue_growth": round(data.get("revenue_growth", 0), 4),
            "earnings_growth": round(data.get("earnings_growth", 0), 4),
        }

    def _calculate_overall_score(
        self,
        valuation: Dict[str, float],
        profitability: Dict[str, float],
        growth: Dict[str, float],
    ) -> float:
        """Calculate overall fundamental score (0-100).

        Args:
            valuation: Valuation metrics
            profitability: Profitability metrics
            growth: Growth metrics

        Returns:
            Overall score from 0 to 100
        """
        score = 50.0  # Start at neutral

        # Valuation scoring (lower PE/PB is generally better for value)
        pe = valuation.get("pe_ratio", 20)
        if pe < self.PE_THRESHOLD_LOW:
            score += 15  # Very attractive PE
        elif pe < 20:
            score += 10  # Reasonable PE
        elif pe > self.PE_THRESHOLD_HIGH:
            score -= 15  # Expensive PE
        elif pe > 25:
            score -= 10  # High PE

        pb = valuation.get("pb_ratio", 2)
        if pb < self.PB_THRESHOLD_LOW:
            score += 10  # Very attractive PB
        elif pb < 2:
            score += 5  # Reasonable PB
        elif pb > self.PB_THRESHOLD_HIGH:
            score -= 10  # Expensive PB

        # Profitability scoring
        roe = profitability.get("roe", 0)
        if roe > self.ROE_THRESHOLD:
            score += 15  # Strong ROE
        elif roe > 0.10:
            score += 10  # Good ROE
        elif roe < 0.05:
            score -= 10  # Weak ROE

        roa = profitability.get("roa", 0)
        if roa > self.ROA_THRESHOLD:
            score += 10  # Strong ROA
        elif roa > 0.05:
            score += 5  # Good ROA

        profit_margin = profitability.get("profit_margin", 0)
        if profit_margin > 0.20:
            score += 10  # Excellent margins
        elif profit_margin > 0.10:
            score += 5  # Good margins
        elif profit_margin < 0.05:
            score -= 5  # Thin margins

        # Growth scoring
        revenue_growth = growth.get("revenue_growth", 0)
        if revenue_growth > self.GROWTH_THRESHOLD:
            score += 10  # Strong growth
        elif revenue_growth > 0.05:
            score += 5  # Moderate growth
        elif revenue_growth < 0:
            score -= 10  # Declining revenue

        earnings_growth = growth.get("earnings_growth", 0)
        if earnings_growth > self.GROWTH_THRESHOLD:
            score += 10  # Strong earnings growth
        elif earnings_growth < 0:
            score -= 10  # Declining earnings

        # Clamp score to 0-100 range
        return max(0.0, min(100.0, score))

    def _generate_recommendation(
        self, score: float, valuation: Dict[str, float]
    ) -> str:
        """Generate valuation recommendation based on score and metrics.

        Args:
            score: Overall fundamental score
            valuation: Valuation metrics

        Returns:
            Recommendation string
        """
        pe = valuation.get("pe_ratio", 20)

        if score >= 70 and pe < self.PE_THRESHOLD_HIGH:
            return ValuationRecommendation.UNDERVALUED
        elif score <= 40 or pe > self.PE_THRESHOLD_HIGH * 1.5:
            return ValuationRecommendation.OVERVALUED
        else:
            return ValuationRecommendation.FAIR

    def get_last_report(self) -> Optional[FundamentalReport]:
        """Get the most recent fundamental report.

        Returns:
            The last FundamentalReport or None if no analysis performed
        """
        return self._last_report

    def get_report_history(self) -> list[FundamentalReport]:
        """Get history of all fundamental reports.

        Returns:
            List of FundamentalReport objects
        """
        # This could be extended to store full history
        if self._last_report:
            return [self._last_report]
        return []
