from __future__ import annotations

from dataclasses import asdict, dataclass, field
from datetime import datetime, timezone
from enum import StrEnum
from typing import Any


class Market(StrEnum):
    TASI = "TASI"
    SP500 = "SP500"


class Strategy(StrEnum):
    INVESTMENT = "investment"
    SWING = "swing"


class Action(StrEnum):
    BUY = "BUY"
    WATCH = "WATCH"
    HOLD = "HOLD"
    SELL = "SELL"
    AVOID = "AVOID"


class Verdict(StrEnum):
    RIGHT = "RIGHT"
    WRONG = "WRONG"
    OPEN = "STILL_OPEN"


@dataclass(frozen=True)
class Quote:
    market: Market
    symbol: str
    name: str
    price: float
    currency: str
    as_of: datetime
    source: str
    delayed: bool = False
    volume: float | None = None


@dataclass(frozen=True)
class Bar:
    ts: datetime
    open: float
    high: float
    low: float
    close: float
    volume: float


@dataclass(frozen=True)
class Fundamentals:
    symbol: str
    pe: float | None = None
    pb: float | None = None
    dividend_yield: float | None = None
    roe: float | None = None
    debt_to_equity: float | None = None
    revenue_growth: float | None = None
    earnings_growth: float | None = None
    source: str = "unknown"
    as_of: datetime = field(default_factory=lambda: datetime.now(timezone.utc))


@dataclass(frozen=True)
class RuleCitation:
    rule_id: str
    version: int
    reason: str


@dataclass
class Recommendation:
    recommendation_id: str
    run_id: str
    market: Market
    symbol: str
    name: str
    strategy: Strategy
    action: Action
    score: float
    confidence: float
    reference_price: float
    target: float | None
    stop: float | None
    horizon: str
    target_method: str
    invalidation_method: str
    profile: list[str]
    reasons_for: list[str]
    reasons_against: list[str]
    rules: list[RuleCitation]
    data_sources: list[str]
    evidence_snapshot: dict[str, Any]
    engine_version: str
    created_at: datetime

    def to_dict(self) -> dict[str, Any]:
        d = asdict(self)
        d["market"] = self.market.value
        d["strategy"] = self.strategy.value
        d["action"] = self.action.value
        d["created_at"] = self.created_at.isoformat()
        return d


@dataclass
class SimAction:
    action_id: str
    recommendation_id: str
    portfolio_id: str
    symbol: str
    action: str
    quantity: int
    price: float
    cash_before: float
    cash_after: float
    reason: str
    rules: list[RuleCitation]
    created_at: datetime
    portfolio_before: dict[str, Any] = field(default_factory=dict)
    portfolio_after: dict[str, Any] = field(default_factory=dict)
    legs: list[dict[str, Any]] = field(default_factory=list)


@dataclass
class Observation:
    recommendation_id: str
    symbol: str
    observed_at: datetime
    reference_price: float
    close: float
    high: float
    low: float
    target: float | None
    stop: float | None
    verdict: Verdict
    return_pct: float
    reason: str
