# src/metrics/equity_metrics.py
"""
Métricas basadas exclusivamente en equity curve.
Pensadas para portfolio, paper trading y UI.
"""

import numpy as np
import pandas as pd
from typing import List, Optional, Dict


# --------------------------------------------------
# Helpers
# --------------------------------------------------
def _to_series(
    equity_curve: List[float],
    timestamps: Optional[List[pd.Timestamp]] = None,
) -> pd.Series:
    if timestamps is None:
        return pd.Series(equity_curve)
    return pd.Series(equity_curve, index=pd.to_datetime(timestamps))


# --------------------------------------------------
# Core metrics
# --------------------------------------------------
def calculate_cagr(
    equity_curve: List[float],
    timestamps: List[pd.Timestamp],
) -> float:
    """
    CAGR real usando timestamps.
    """
    equity = _to_series(equity_curve, timestamps)

    if len(equity) < 2:
        return 0.0

    start, end = equity.iloc[0], equity.iloc[-1]
    years = (equity.index[-1] - equity.index[0]).days / 365.25

    if years <= 0:
        return 0.0

    return (end / start) ** (1 / years) - 1


def calculate_drawdown_series(equity: pd.Series) -> pd.Series:
    running_max = equity.cummax()
    return (equity - running_max) / running_max


def calculate_max_drawdown(
    equity_curve: List[float],
    timestamps: Optional[List[pd.Timestamp]] = None,
) -> float:
    equity = _to_series(equity_curve, timestamps)
    dd = calculate_drawdown_series(equity)
    return dd.min()


def calculate_time_in_drawdown(
    equity_curve: List[float],
    timestamps: List[pd.Timestamp],
) -> float:
    """
    % del tiempo que el sistema está bajo su máximo histórico.
    """
    equity = _to_series(equity_curve, timestamps)
    dd = calculate_drawdown_series(equity)
    return (dd < 0).mean()


def calculate_ulcer_index(
    equity_curve: List[float],
    timestamps: Optional[List[pd.Timestamp]] = None,
) -> float:
    """
    Ulcer Index: profundidad + duración del drawdown.
    """
    equity = _to_series(equity_curve, timestamps)
    dd = calculate_drawdown_series(equity)
    return np.sqrt(np.mean(np.square(dd * 100)))


def calculate_equity_volatility(
    equity_curve: List[float],
    timestamps: Optional[List[pd.Timestamp]] = None,
    annualize: bool = True,
) -> float:
    equity = _to_series(equity_curve, timestamps)
    returns = equity.pct_change().dropna()

    if returns.empty:
        return 0.0

    vol = returns.std()
    return vol * np.sqrt(252) if annualize else vol


def calculate_calmar_ratio(
    equity_curve: List[float],
    timestamps: List[pd.Timestamp],
) -> float:
    cagr = calculate_cagr(equity_curve, timestamps)
    max_dd = abs(calculate_max_drawdown(equity_curve, timestamps))

    if max_dd == 0:
        return 0.0

    return cagr / max_dd


# --------------------------------------------------
# Aggregator
# --------------------------------------------------
def compute_equity_metrics(
    equity_curve: List[float],
    timestamps: List[pd.Timestamp],
) -> Dict[str, float]:
    """
    Métricas clave para comparar sistemas y portfolios.
    """
    return {
        "cagr": calculate_cagr(equity_curve, timestamps),
        "max_drawdown": calculate_max_drawdown(equity_curve, timestamps),
        "calmar_ratio": calculate_calmar_ratio(equity_curve, timestamps),
        "volatility": calculate_equity_volatility(equity_curve, timestamps),
        "time_in_drawdown": calculate_time_in_drawdown(equity_curve, timestamps),
        "ulcer_index": calculate_ulcer_index(equity_curve, timestamps),
    }
