"""Scanner d'opportunités court terme.

Filtre une watchlist sur deux axes :
  1. CAPACITÉ : le titre peut-il bouger de X% sur la semaine ? (volatilité)
  2. DIRECTION : le setup technique penche-t-il haussier ou baissier ?

Sert à objectiver un trade swing — PAS une reco d'achat. Un titre capable de
faire +8% est tout aussi capable de faire -8%.
"""
from __future__ import annotations

import math
import os
from pathlib import Path

import pandas as pd
import yaml

from . import data, indicators as ind

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


def load_theme(theme: str | None = None) -> list[str]:
    """Tickers d'un thème de watchlists.yaml. None ou 'all' = tous (dédupliqués)."""
    themes = yaml.safe_load(open(WATCHLISTS_FILE, encoding="utf-8"))["themes"]
    if theme and theme != "all":
        if theme not in themes:
            raise SystemExit(f"Thème inconnu: {theme}. Dispo: {', '.join(themes)}")
        return themes[theme]
    seen: dict[str, None] = {}
    for syms in themes.values():
        for s in syms:
            seen.setdefault(s, None)
    return list(seen)

# 5 séances pleines ; ajusté si semaine écourtée (férié)
SESSIONS_LEFT_DEFAULT = 4


def scan(symbols: list[str], target_pct: float = 5.0, sessions: int = SESSIONS_LEFT_DEFAULT) -> pd.DataFrame:
    rows = []
    for s in symbols:
        try:
            df = data.history(s, period="6mo")
            close = df["Close"]
            last = float(close.iloc[-1])

            rsi = float(ind.rsi(close).iloc[-1])
            macd = ind.macd(close)
            macd_up = macd["macd"].iloc[-1] > macd["signal"].iloc[-1]
            hist = macd["hist"]
            macd_turning_up = hist.iloc[-1] > hist.iloc[-2]  # histogramme qui se redresse
            sma50 = float(ind.sma(close, 50).iloc[-1])
            atr = float(ind.atr(df).iloc[-1])

            vol_day = atr / last * 100                       # amplitude journalière typique
            range_week = vol_day * math.sqrt(sessions)       # amplitude attendue sur la semaine
            can_hit = range_week >= target_pct               # capacité d'atteindre la cible

            # Score directionnel haussier (0-4) : empilement de confirmations
            score = sum([
                last > sma50,            # au-dessus MM50
                macd_up,                 # MACD haussier
                macd_turning_up,         # momentum qui se redresse
                30 < rsi < 70,           # pas en zone extrême (évite l'achat en surachat)
            ])
            if rsi < 30:
                bias = "survendu (rebond possible)"
            elif rsi > 70:
                bias = "surachat (essoufflement)"
            elif score >= 3:
                bias = "haussier"
            elif score <= 1:
                bias = "baissier"
            else:
                bias = "neutre"

            rows.append({
                "ticker": s,
                "cours": round(last, 2),
                "vol_j_%": round(vol_day, 2),
                "range_sem_%": round(range_week, 1),
                f"peut_{int(target_pct)}%": "OUI" if can_hit else "non",
                "RSI": round(rsi, 0),
                "MACD": "↑" if macd_up else "↓",
                "score": score,
                "biais": bias,
            })
        except Exception as e:
            rows.append({"ticker": s, "biais": f"erreur: {e}"})

    df = pd.DataFrame(rows)
    # Tri : d'abord ceux qui peuvent atteindre la cible, puis par score directionnel
    sort_col = f"peut_{int(target_pct)}%"
    df["_cap"] = (df[sort_col] == "OUI").astype(int)
    df = df.sort_values(["_cap", "score", "range_sem_%"], ascending=False).drop(columns="_cap")
    return df.reset_index(drop=True)


def scan_portfolio(target_pct: float = 5.0, sessions: int = SESSIONS_LEFT_DEFAULT, extra: list[str] | None = None) -> pd.DataFrame:
    syms = data.portfolio_tickers() + (extra or [])
    return scan(syms, target_pct, sessions)


def scan_theme(theme: str | None = None, target_pct: float = 5.0, sessions: int = SESSIONS_LEFT_DEFAULT,
               bullish_only: bool = False) -> pd.DataFrame:
    """Scanne un thème de watchlists.yaml (ou 'all')."""
    df = scan(load_theme(theme), target_pct, sessions)
    if bullish_only:
        df = df[df["biais"].isin(["haussier", "survendu (rebond possible)"])]
    return df.reset_index(drop=True)


if __name__ == "__main__":
    import sys
    args = sys.argv[1:]
    theme = args[0] if args else "all"
    target = float(args[1]) if len(args) > 1 else 5.0
    pd.set_option("display.max_columns", None, "display.width", 200)
    print(scan_theme(theme, target).to_string(index=False))
