# tasks_backtestingidea2.py
from celery_app import celery_app
import pandas as pd
import os
import sys

sys.path.insert(0, '/var/www/html/backtestingmarket')


def _get_desplazamiento(symbol, risk):
    if symbol in ["SPX", "RUT"]:
        desplazamientos = {
            'conservador': 0,
            'intermedio': -5,
            'agresivo': -10,
            'ultra_agresivo': -15
        }
    else:
        desplazamientos = {
            'conservador': 0,
            'intermedio': -1,
            'agresivo': -2,
            'ultra_agresivo': -3
        }
    return desplazamientos[risk]


def _cargar_strikes(symbol, estrategia, timeHour):
    archivo = f"/var/www/html/backtestingmarket/predictor_data/makekos/{symbol}/{symbol}_{estrategia}_strikes_{timeHour}.csv"
    if not os.path.exists(archivo):
        raise FileNotFoundError(f"Archivo de strikes no encontrado: {archivo}")
    return pd.read_csv(archivo)


def _run_backtesting_logic(symbol, estrategia, timeHour, risk, desde, hasta, modo='HORA_FIJA', credit_target=0):
    """Lógica pura — sin Celery. Llamable directamente desde scripts."""

    from backtestingIdea2 import (
        calcular_precios_verticales,
        calcular_precios_iron_condor,
        obtener_hora_desde_csv,
        PATH_UBUNTU_CHAINS
    )

    desplazamiento = _get_desplazamiento(symbol, risk)

    # =========================================================
    # MODO HORA FIJA: comportamiento original
    # =========================================================
    if modo == 'HORA_FIJA':
        df_strikes = _cargar_strikes(symbol, estrategia, timeHour)

        if estrategia.upper() == "VERTICAL":
            df_result, total, wins, losses = calcular_precios_verticales(
                df_strikes, PATH_UBUNTU_CHAINS, desplazamiento, desde, hasta, credit_target
            )
        elif estrategia.upper() == "IRONCONDOR":
            df_result, total, wins, losses = calcular_precios_iron_condor(
                df_strikes, PATH_UBUNTU_CHAINS, desplazamiento, desde, hasta, credit_target
            )
        else:
            raise ValueError("Estrategia no reconocida")

    # =========================================================
    # MODO MEJORES HORARIOS: horario dinámico por semana
    # =========================================================
    elif modo == 'MEJORES_HORARIOS':
        fechas = pd.bdate_range(start=desde, end=hasta)  # solo días hábiles
        semanas = {}
        for fecha in fechas:
            lunes = fecha - pd.Timedelta(days=fecha.weekday())
            if lunes not in semanas:
                semanas[lunes] = []
            semanas[lunes].append(fecha)

        frames = []
        for lunes, dias_semana in sorted(semanas.items()):
            hora_semana = obtener_hora_desde_csv(symbol, estrategia, risk, lunes.strftime('%Y-%m-%d'))

            if hora_semana is None:
                print(f"[MEJORES_HORARIOS] Sin hora para semana {lunes.date()} → se omite")
                continue

            try:
                df_strikes = _cargar_strikes(symbol, estrategia, hora_semana)
            except FileNotFoundError as e:
                print(f"[MEJORES_HORARIOS] {e} → se omite semana {lunes.date()}")
                continue

            desde_semana = dias_semana[0].strftime('%Y-%m-%d')
            hasta_semana = dias_semana[-1].strftime('%Y-%m-%d')

            if estrategia.upper() == "VERTICAL":
                df_res, _, _, _ = calcular_precios_verticales(
                    df_strikes, PATH_UBUNTU_CHAINS, desplazamiento, desde_semana, hasta_semana, credit_target
                )
            elif estrategia.upper() == "IRONCONDOR":
                df_res, _, _, _ = calcular_precios_iron_condor(
                    df_strikes, PATH_UBUNTU_CHAINS, desplazamiento, desde_semana, hasta_semana, credit_target
                )
            else:
                raise ValueError("Estrategia no reconocida")

            if not df_res.empty:
                df_res['hora_top1'] = hora_semana  # columna informativa
                frames.append(df_res)

        if not frames:
            return {"data": [], "profit_total": 0.0, "wins": 0, "losses": 0}

        df_result = pd.concat(frames, ignore_index=True)
        total = df_result['P/L'].sum(skipna=True)
        wins = int(df_result[df_result['P/L'] >= 0].shape[0])
        losses = int(df_result[df_result['P/L'] < 0].shape[0])

    else:
        raise ValueError(f"Modo no reconocido: {modo}")

    return {
        "data": df_result.astype(object).to_dict(orient="records"),
        "profit_total": float(round(total, 2)),
        "wins": int(wins),
        "losses": int(losses)
    }


@celery_app.task(bind=True, queue="backtesting_idea2")
def run_backtesting_idea(self, symbol, estrategia, timeHour, risk, desde, hasta, modo='HORA_FIJA', credit_target=0):
    return _run_backtesting_logic(symbol, estrategia, timeHour, risk, desde, hasta, modo, credit_target)