"""
generate_historical_expected_move.py
--------------------------------------
Corre una vez por día (ej: via cron a las 17:00 NY).
Lee todos los CSVs históricos de predicción por símbolo,
calcula el promedio del movimiento_esperado por slot horario (HH:MM)
y guarda el resultado en:
  /var/www/html/backtestingmarket/predictor_data/data/{SYMBOL}/historical_expected_move_{SYMBOL}.csv

Uso:
  python generate_historical_expected_move.py
  python generate_historical_expected_move.py --symbols SPX RUT SPY QQQ XSP
"""

import os
import glob
import argparse
import pandas as pd


# ── Configuración ─────────────────────────────────────────────────────────────

BASE_PATH   = "/var/www/html/backtestingmarket/predictor_data/data/"
SYMBOLS     = ["SPX", "RUT", "SPY", "QQQ", "XSP"]
OUTPUT_NAME = "historical_expected_move_{symbol}.csv"


# ── Helpers ───────────────────────────────────────────────────────────────────

def symbol_folder(symbol: str) -> str:
    """SPX → SPX,  $SPX → SPX"""
    return symbol.replace("$", "")


def symbol_prefix(symbol: str) -> str:
    """Para buscar archivos: SPX puede tener prefijo $ o no."""
    base = symbol.replace("$", "")
    return base  # buscamos prediction_*{base}*


def load_all_csvs(symbol: str) -> pd.DataFrame:
    folder  = os.path.join(BASE_PATH, symbol_folder(symbol))
    pattern = os.path.join(folder, f"prediction_*{symbol_prefix(symbol)}*.csv")
    files   = sorted(glob.glob(pattern))

    if not files:
        print(f"  [!] No se encontraron archivos para {symbol} en {folder}")
        return pd.DataFrame()

    frames = []
    for f in files:
        try:
            df = pd.read_csv(f, usecols=["timestamp", "movimiento_esperado"],
                             parse_dates=["timestamp"])
            # Excluir el día de hoy (datos incompletos)
            today = pd.Timestamp.now().normalize()
            df = df[df["timestamp"].dt.normalize() < today]

            # Filtrar horario de mercado: 9:35 a 15:59
            t = df["timestamp"].dt.time
            df = df[
                (t >= pd.Timestamp("09:35:00").time()) &
                (t <= pd.Timestamp("15:59:59").time())
            ]

            frames.append(df)
        except Exception as e:
            print(f"  [!] Error leyendo {f}: {e}")

    if not frames:
        return pd.DataFrame()

    return pd.concat(frames, ignore_index=True)

def build_historical_avg(df: pd.DataFrame) -> pd.DataFrame:
    df = df.dropna(subset=["movimiento_esperado"])
    df["movimiento_esperado"] = pd.to_numeric(df["movimiento_esperado"], errors="coerce")
    df = df.dropna(subset=["movimiento_esperado"])

    df["time_slot"] = df["timestamp"].dt.strftime("%H:%M")

    # Filtrar outliers dentro de cada slot antes de agregar
    def remove_slot_outliers(group):
        if len(group) < 4:
            return group
        median = group.median()
        std    = group.std()
        if std == 0 or pd.isna(std):
            return group
        return group[abs(group - median) <= 3 * std]

    df = (
        df.groupby("time_slot")["movimiento_esperado"]
        .apply(remove_slot_outliers)
        .reset_index(level=0)
        .reset_index(drop=True)
    )

    result = (
        df.groupby("time_slot")["movimiento_esperado"]
        .agg(avg="mean", median="median", std="std", count="count")
        .reset_index()
        .sort_values("time_slot")
    )

    result["avg"]    = result["avg"].round(2)
    result["median"] = result["median"].round(2)
    result["std"]    = result["std"].round(2)

    # ── Rellenar slots faltantes con el valor anterior (ffill) ────────────────
    # Generar todos los slots del día 09:35 → 15:59
    all_slots = pd.date_range("09:35", "16:00", freq="1min").strftime("%H:%M").tolist()
    full = pd.DataFrame({"time_slot": all_slots})
    result = full.merge(result, on="time_slot", how="left")
    result[["avg", "median", "std"]] = result[["avg", "median", "std"]].ffill()
    result["count"] = result["count"].fillna(0).astype(int)
    # ─────────────────────────────────────────────────────────────────────────

    return result

def save_output(df: pd.DataFrame, symbol: str):
    folder   = os.path.join(BASE_PATH, symbol_folder(symbol))
    out_file = os.path.join(folder, OUTPUT_NAME.format(symbol=symbol_folder(symbol)))
    df.to_csv(out_file, index=False)
    print(f"  [✓] Guardado: {out_file}  ({len(df)} slots, {df['count'].max()} días max)")


# ── Main ──────────────────────────────────────────────────────────────────────

def process_symbol(symbol: str):
    print(f"\n── {symbol} ──────────────────────────────")
    df_raw = load_all_csvs(symbol)

    if df_raw.empty:
        print(f"  [!] Sin datos para {symbol}, se omite.")
        return

    days = df_raw["timestamp"].dt.normalize().nunique()
    print(f"  Días históricos encontrados: {days}")

    df_hist = build_historical_avg(df_raw)
    save_output(df_hist, symbol)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--symbols", nargs="+", default=SYMBOLS,
                        help="Símbolos a procesar (default: todos)")
    args = parser.parse_args()

    print("=" * 50)
    print("  Generando promedios históricos de Mov. Esperado")
    print("=" * 50)

    for sym in args.symbols:
        process_symbol(sym)

    print("\n[✓] Proceso finalizado.")


if __name__ == "__main__":
    main()