"""Évaluation des alertes : ne renvoie que les ÉVÉNEMENTS du jour (transitions).

Économe en tokens : au lieu de déverser tout l'état technique, on ne remonte
que ce qui vient de basculer (croisement MACD, cassure MM50, survente...).
"""
from __future__ import annotations

import os
from pathlib import Path

import pandas as pd
import yaml

from . import data, indicators as ind, scanner

# Config lue depuis FINLAB_HOME (workspace persistant) si défini — cf. data.ROOT.
ALERTS_FILE = Path(os.environ.get("FINLAB_HOME") or Path(__file__).resolve().parent.parent) / "alerts.yaml"


def _events(symbol: str) -> dict:
    """Calcule les flags d'événement (aujourd'hui vs hier) pour un titre."""
    df = data.history(symbol, period="1y")
    close = df["Close"]
    rsi = ind.rsi(close)
    macd = ind.macd(close)
    m, s = macd["macd"], macd["signal"]
    mm50 = ind.sma(close, 50)
    mm200 = ind.sma(close, 200)

    def crossed_up(a, b):
        return a.iloc[-2] <= b.iloc[-2] and a.iloc[-1] > b.iloc[-1]

    def crossed_down(a, b):
        return a.iloc[-2] >= b.iloc[-2] and a.iloc[-1] < b.iloc[-1]

    return {
        "rsi": float(rsi.iloc[-1]),
        "macd_cross_up": crossed_up(m, s),
        "macd_cross_down": crossed_down(m, s),
        "cross_above_mm50": crossed_up(close, mm50),
        "cross_below_mm50": crossed_down(close, mm50),
        "golden_cross": crossed_up(mm50, mm200) if mm200.notna().iloc[-1] else False,
        "death_cross": crossed_down(mm50, mm200) if mm200.notna().iloc[-1] else False,
        "price": round(float(close.iloc[-1]), 2),
    }


def _matches(rule: dict, ev: dict) -> bool:
    w = rule["when"]
    if w == "rsi_below":
        return ev["rsi"] < rule["value"]
    if w == "rsi_above":
        return ev["rsi"] > rule["value"]
    return bool(ev.get(w, False))


def _watchlist(name: str) -> list[str]:
    if name == "portfolio":
        return data.portfolio_tickers()  # union de tous les comptes
    return scanner.load_theme(name)  # 'all' ou un thème


def run(watch: str | None = None) -> list[dict]:
    """Renvoie la liste des alertes déclenchées : [{ticker, prix, alerte}]."""
    cfg = yaml.safe_load(open(ALERTS_FILE, encoding="utf-8"))
    rules = cfg["rules"]
    syms = _watchlist(watch or cfg.get("watch", "all"))

    hits = []
    for sym in syms:
        try:
            ev = _events(sym)
        except Exception:
            continue
        for rule in rules:
            if _matches(rule, ev):
                hits.append({"ticker": sym, "prix": ev["price"], "alerte": rule["name"]})
    return hits


def render(hits: list[dict]) -> str:
    if not hits:
        return "Aucune alerte déclenchée aujourd'hui."
    df = pd.DataFrame(hits).sort_values("alerte")
    return df.to_string(index=False)


if __name__ == "__main__":
    import sys
    print(render(run(sys.argv[1] if len(sys.argv) > 1 else None)))
