import os
import pandas as pd
from flask import Blueprint, jsonify, request
from neutralEdge_tasks import process_backtesting_task
from datetime import datetime

neutralEdge_bp = Blueprint('neutralEdge', __name__, template_folder='templates')

# =============================
# POST: Guardar evolución intradía
# =============================
@neutralEdge_bp.route('/log_intraday', methods=['POST'])
def log_intraday():
    data = request.get_json()
    date_str = data.get('date')
    opening_time = data.get('openingTime')
    strikes = data.get('strikes', {})
    time_occur = data.get('occurTime')
    initial_credit = data.get('initialCredit')

    if len(opening_time.split(':')) == 2:
        opening_time += ":00"

    symbol = "SPX"
    csv_filename = f"optionChain_${symbol}_{date_str}.csv"
    csv_path = os.path.join('/var/www/html/flask_project/chains', csv_filename)

    try:
        credit, chosen_timestamp = get_initial_credit(
            csv_path, opening_time,
            strikes.get('sellCall'), strikes.get('buyCall'),
            strikes.get('sellPut'), strikes.get('buyPut')
        )

        if credit is None or chosen_timestamp is None:
            return jsonify({'status': 'error', 'message': 'No se pudo calcular el crédito inicial'}), 400

        initial_credit = float(initial_credit) * 100

        evolution = get_credit_evolution(
            csv_path, chosen_timestamp,
            strikes.get('sellCall'), strikes.get('buyCall'),
            strikes.get('sellPut'), strikes.get('buyPut'),
            initial_credit
        )

        evolution_serializable = [
            {'timestamp': rec['timestamp'].strftime('%Y-%m-%d %H:%M:%S'), 'credit': rec['credit'], 'profit_loss': rec['profit_loss']}
            for rec in evolution
        ]

        return jsonify({
            'status': 'success',
            'credit': initial_credit,
            'chosen_timestamp': chosen_timestamp.strftime('%Y-%m-%d %H:%M:%S'),
            'evolution': evolution_serializable,
            'message': 'Crédito inicial y evolución calculados correctamente'
        }), 200

    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

# =============================
# Funciones auxiliares
# =============================

def get_initial_credit(csv_file, target_time, sell_call, buy_call, sell_put, buy_put):
    df = pd.read_csv(csv_file)
    df['timestamp'] = pd.to_datetime(df['timestamp'])
    df['only_time'] = df['timestamp'].dt.time
    target = datetime.strptime(target_time, '%H:%M:%S').time()
    df_after = df[df['only_time'] >= target]

    if not df_after.empty:
        df_after['time_diff'] = df_after['only_time'].apply(lambda t: (datetime.combine(datetime.min, t) - datetime.combine(datetime.min, target)).total_seconds())
        chosen_rows = df_after[df_after['time_diff'] == df_after['time_diff'].min()]
    else:
        df['time_diff'] = df['only_time'].apply(lambda t: abs((datetime.combine(datetime.min, t) - datetime.combine(datetime.min, target)).total_seconds()))
        chosen_rows = df[df['time_diff'] == df['time_diff'].min()]

    chosen_timestamp = chosen_rows.iloc[0]['timestamp']

    def get_mid(df_rows, strike, bid_col, ask_col):
        row = df_rows[df_rows['strike'] == float(strike)]
        if row.empty:
            return None
        bid, ask = float(row.iloc[0][bid_col]), float(row.iloc[0][ask_col])
        return (bid + ask) / 2

    mid_sell_call = get_mid(chosen_rows, sell_call, 'bid_call', 'ask_call')
    mid_buy_call = get_mid(chosen_rows, buy_call, 'bid_call', 'ask_call')
    mid_sell_put = get_mid(chosen_rows, sell_put, 'bid_put', 'ask_put')
    mid_buy_put = get_mid(chosen_rows, buy_put, 'bid_put', 'ask_put')

    if None in [mid_sell_call, mid_buy_call, mid_sell_put, mid_buy_put]:
        return 0, chosen_timestamp

    credit = ((mid_sell_call - mid_buy_call) + (mid_sell_put - mid_buy_put)) * 100
    return credit, chosen_timestamp

def get_credit_evolution(csv_file, start_timestamp, sell_call, buy_call, sell_put, buy_put, initial_credit):
    df = pd.read_csv(csv_file)
    df['timestamp'] = pd.to_datetime(df['timestamp'])
    df = df[df['timestamp'] >= start_timestamp]

    evolution = []
    for ts, group in df.groupby('timestamp'):
        credit = compute_credit_for_group(group, sell_call, buy_call, sell_put, buy_put)
        if credit is not None:
            profit_loss = initial_credit - credit
            evolution.append({'timestamp': ts, 'credit': credit, 'profit_loss': profit_loss})

    df_evo = pd.DataFrame(evolution)
    df_evo['credit'] = df_evo['credit'].rolling(window=5, min_periods=1).mean()
    df_evo['profit_loss'] = initial_credit - df_evo['credit']

    return df_evo.to_dict(orient='records')

def compute_credit_for_group(group, sell_call, buy_call, sell_put, buy_put):
    def get_mid(series_bid, series_ask):
        return (float(series_bid.iloc[0]) + float(series_ask.iloc[0])) / 2

    try:
        mid_sell_call = get_mid(group[group['strike'] == float(sell_call)]['bid_call'], group[group['strike'] == float(sell_call)]['ask_call'])
        mid_buy_call = get_mid(group[group['strike'] == float(buy_call)]['bid_call'], group[group['strike'] == float(buy_call)]['ask_call'])
        mid_sell_put = get_mid(group[group['strike'] == float(sell_put)]['bid_put'], group[group['strike'] == float(sell_put)]['ask_put'])
        mid_buy_put = get_mid(group[group['strike'] == float(buy_put)]['bid_put'], group[group['strike'] == float(buy_put)]['ask_put'])
    except IndexError:
        return None

    credit = ((mid_sell_call - mid_buy_call) + (mid_sell_put - mid_buy_put)) * 100
    return credit

# =============================
# Procesar Backtesting con Celery
# =============================
@neutralEdge_bp.route('/process_form', methods=['POST'])
def process_form():
    data = request.get_json()
    task = process_backtesting_task.delay(data)
    return jsonify({"task_id": task.id, "status": "Procesando..."})

@neutralEdge_bp.route('/task_status/<task_id>', methods=['GET'])
def task_status(task_id):
    from neutralEdge_tasks import aggregate_results
    result = aggregate_results.AsyncResult(task_id)
    if result.state == 'SUCCESS':
        return jsonify({"state": result.state, "result": result.result})
    else:
        return jsonify({"state": result.state, "result": None})
