"""Proiezione a 3 anni del portafoglio live (PORT06) ESCLUDENDO il 2024.

Risponde a: "partendo da 1000 EUR, con capitale che compone e puntata che cresce
di conseguenza, quale guadagno giornaliero atteso e quale traiettoria a 3 anni?"

Punti chiave (perche' i numeri differiscono da report_families):
  - report_families/Portfolio.backtest usano le curve sleeve NATIVE a leva 3x.
  - Il container LIVE (src.portfolio.runner via portfolios.yml) gira a pos 0.15 x 2x.
  - Il PnL giornaliero scala ESATTAMENTE con la leva: pnl = cap * pos * lev * (ret - fee),
    stesso segnale -> ratio 2/3 per gli sleeve leverati.
  - ROT02 e TSM01 NON si riscalano: usano `gross` (0.45 / 0.30), indipendente dalla leva
    e identico fra backtest e worker live.
  - Il 2024 e' escluso perche' anno eccezionale (crypto +; gonfia ogni stima).

CAVEAT (le proiezioni sono OTTIMISTICHE):
  - 2021-2025 e' quasi tutto bull/recovery; poco orso/flat prolungato nel campione.
  - Dati alt = testnet (volume sottile, fill/slippage NON modellati).
  - OOS singolo (2024-25) = regime calmo -> ~50% ottimistico (vedi report_families (D)).
  Lo scenario SOBRIO (haircut ~50%) e' il numero prudente su cui pianificare.

Run: uv run python scripts/analysis/projection_3y.py
"""
from __future__ import annotations

import sys
from pathlib import Path

import numpy as np
import pandas as pd

PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))

from scripts.portfolios._defs import PORTFOLIOS
from src.portfolio.sleeves import all_sleeve_equities, sleeve_returns_df
from scripts.analysis.combine_portfolio import port_returns

# sleeve la cui esposizione NON dipende dalla leva (gross-based) -> non si riscalano
NOSCALE = {"ROT02_rot", "TSM01"}
NATIVE_LEV = 3.0          # leva delle curve sleeve in combine_portfolio
EXCLUDE_YEAR = 2024
START_CAPITAL = 1000.0


def live_portfolio_returns(live_leverage: float = 2.0) -> pd.Series:
    """Rendimenti giornalieri di PORT06 al sizing LIVE (pos 0.15 x `live_leverage`).
    Riscala gli sleeve leverati di live_leverage/NATIVE_LEV; ROT/TSM invariati."""
    p = PORTFOLIOS["PORT06"]
    p.leverage = live_leverage
    p.weighting = "cap"
    p.caps = {"PAIRS": 0.33}

    eq = all_sleeve_equities()
    dr = sleeve_returns_df(p.sleeve_ids)
    w = p.weight_vector(dr)

    scale = live_leverage / NATIVE_LEV
    eq_live = {}
    for sid in p.sleeve_ids:
        r = eq[sid].pct_change().fillna(0.0)
        r = r if sid in NOSCALE else r * scale
        eq_live[sid] = (1 + r).cumprod()
    pr = port_returns(eq_live, w)
    pr.index = pd.to_datetime(pr.index)
    return pr


def stats_ex_year(pr: pd.Series, exclude: int = EXCLUDE_YEAR) -> dict:
    ex = pr[pr.index.year != exclude]
    n = len(ex)
    years = n / 365.0
    tot = (1 + ex).prod() - 1
    cagr = (1 + tot) ** (1 / years) - 1
    yvals = [(1 + g).prod() - 1 for _, g in ex.groupby(ex.index.year)]
    return {
        "days": n, "years": years, "total": tot, "cagr": cagr,
        "year_median": float(np.median(yvals)), "year_mean": float(np.mean(yvals)),
        "daily_mean_eur": float(ex.mean() * START_CAPITAL),
        "daily_median_eur": float(ex.median() * START_CAPITAL),
        "daily_std_eur": float(ex.std() * START_CAPITAL),
        "pos_days": float((ex > 0).mean()),
        "per_year": {int(y): float((1 + g).prod() - 1) for y, g in pr.groupby(pr.index.year)},
    }


def project(annual: float, years: int = 3, start: float = START_CAPITAL) -> list[dict]:
    """Capitale che compone; la puntata cresce col capitale -> EUR/giorno cresce."""
    rows, cap = [], start
    for yr in range(1, years + 1):
        s = cap
        cap = cap * (1 + annual)
        rows.append({"year": yr, "start": s, "end": cap,
                     "gain": cap - s, "eur_per_day": (cap - s) / 365.0})
    return rows


def years_to_target(daily_target: float, annual: float, start: float = START_CAPITAL) -> float:
    """Anni per raggiungere un certo EUR/giorno componendo (capitale = target*365/cagr)."""
    cap_needed = daily_target * 365.0 / annual
    if cap_needed <= start:
        return 0.0
    return float(np.log(cap_needed / start) / np.log(1 + annual))


def main():
    pr = live_portfolio_returns(live_leverage=2.0)
    s = stats_ex_year(pr)

    print("=" * 72)
    print("  PORT06 LIVE (pos 0.15 x 2x) — proiezione 3 anni, ESCLUSO 2024")
    print("=" * 72)
    print("  Rendimento live per anno:")
    for y, v in s["per_year"].items():
        flag = "  <-- ESCLUSO" if y == EXCLUDE_YEAR else ""
        print(f"    {y}: {v * 100:+6.1f}%{flag}")
    print()
    print(f"  CAGR (escl 2024):    {s['cagr'] * 100:5.1f}%   "
          f"[{s['years']:.2f} anni di dati]")
    print(f"  anno mediano:        {s['year_median'] * 100:5.1f}%")
    print(f"  anno medio:          {s['year_mean'] * 100:5.1f}%")
    print(f"  EUR/giorno su 1000:  media {s['daily_mean_eur']:.2f} | "
          f"mediana {s['daily_median_eur']:.2f} | std {s['daily_std_eur']:.2f}")
    print(f"  giorni positivi:     {s['pos_days'] * 100:.1f}%")
    print()

    scenarios = [
        ("CAGR backtest escl-2024", s["cagr"]),
        ("anno mediano", s["year_median"]),
        ("SOBRIO (haircut ~50%)", s["cagr"] * 0.5),
    ]
    for name, g in scenarios:
        print(f"  -- 3 anni @ {g * 100:.0f}%/anno  ({name}) --")
        for r in project(g):
            print(f"     anno {r['year']}: {r['start']:7.0f} -> {r['end']:7.0f} EUR "
                  f"(+{r['gain']:5.0f}, ~{r['eur_per_day']:4.2f} EUR/g medi)")
        print()

    print("  -- Target 50 EUR/giorno (reality check) --")
    for name, g in scenarios[:1] + scenarios[2:]:
        cap_needed = 50.0 * 365.0 / g
        t = years_to_target(50.0, g)
        print(f"     @ {g * 100:.0f}%/anno: servono ~{cap_needed:,.0f} EUR schierati "
              f"-> da 1000 EUR, ~{t:.0f} anni componendo")
    print("  => il collo di bottiglia e' il CAPITALE iniziale, non la strategia.")


if __name__ == "__main__":
    main()
