import os, time, json, csv, requests
import ccxt
import pandas as pd
from ta.momentum import RSIIndicator
from ta.trend import EMAIndicator
from dotenv import load_dotenv
from datetime import datetime
from config import SYMBOL, TIMEFRAME, LEVERAGE, RISK_PERCENT, TAKE_PROFIT_PERCENT, STOP_LOSS_PERCENT, EMA_FAST, EMA_SLOW, RSI_PERIOD, HEARTBEAT_INTERVAL

# ================== SETUP ==================
os.environ["OPENBLAS_NUM_THREADS"] = "1"
os.environ["OMP_NUM_THREADS"] = "1"
os.environ["MKL_NUM_THREADS"] = "1"

load_dotenv()
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATE_FILE = os.path.join(BASE_DIR, "state.json")
TRADES_FILE = os.path.join(BASE_DIR, "trades_ethusdt.csv")
REPORT_FILE = os.path.join(BASE_DIR, "last_report.json")

exchange = ccxt.binance({
    "apiKey": os.getenv("BINANCE_FUTURES_KEY"),
    "secret": os.getenv("BINANCE_FUTURES_SECRET"),
    "enableRateLimit": True,
    "options": {"defaultType": "future"}
})

exchange.set_leverage(LEVERAGE, SYMBOL)
try:
    exchange.set_margin_mode('isolated', SYMBOL)
except Exception:
    pass
    #print(f"Advertencia: No se pudo cambiar a modo aislado: {e}")

#last_heartbeat = 0

# ================== UTILS ==================
def telegram(msg):
    url = f"https://api.telegram.org/bot{os.getenv('TELEGRAM_TOKEN')}/sendMessage"
    requests.post(url, data={
        "chat_id": os.getenv("TELEGRAM_CHAT_ID"),
        "text": msg
    })

def init_csv():
    if not os.path.exists(TRADES_FILE):
        with open(TRADES_FILE, "w", newline="") as f:
            writer = csv.writer(f)
            writer.writerow([
                "timestamp","symbol","side",
                "entry","exit","qty","pnl_pct",
                "pnl_usdt","result","sl","tp","rr"
            ])

def get_position():
    positions = exchange.fetch_positions([SYMBOL])
    for p in positions:
        if abs(float(p["contracts"])) > 0:
            return {
                "side": "long" if float(p["contracts"]) > 0 else "short",
                "qty": abs(float(p["contracts"])),
                "entry": float(p["entryPrice"])
            }
    return None

def load_state():
    if not os.path.exists(STATE_FILE):
        return {
            "position": False,
            "side": None,
            "entry_price": 0,
            "quantity": 0
        }
    with open(STATE_FILE, "r") as f:
        return json.load(f)
    
def save_state(state):
    with open(STATE_FILE, "w") as f:
        json.dump(state, f, indent=2)

# ================= REPORTE =================
def hourly_report():
    now = time.time()
    last = 0
    if os.path.exists(REPORT_FILE):
        with open(REPORT_FILE) as f:
            last = json.load(f).get("last", 0)

    if now - last < HEARTBEAT_INTERVAL:
        return
    
    ohlcv = exchange.fetch_ohlcv(SYMBOL, TIMEFRAME, limit=300)
    df = pd.DataFrame(ohlcv, columns=["t","o","h","l","c","v"])
    close = df["c"]
    last_price = close.iloc[-1]
        
    state = load_state()

    if state["position"]:
        entry = state["entry_price"]
        side = state["side"]
        qty = state.get("quantity", 0)
        entry_time = state.get("entry_time", 0)
        hold_time = int(now - entry_time) if entry_time else 0

        if side == "long":
            pnl_pct = ((last_price - entry) / entry) * 100
        else:
            pnl_pct = ((entry - last_price) / entry) * 100

        telegram(
            f"💓 Bot FUTURES activo\n"
            f"📍 EN POSICIÓN {side.upper()}\n"
            f"📥 Entrada: {entry:.6f}\n"
            f"📤 Precio: {last_price:.6f}\n"
            f"📦 Qty: {qty}\n"
            f"⏱️ Tiempo: {hold_time} s\n"
            f"⚙️ Leverage: {LEVERAGE}x\n"
            f"📈 PNL aprox: {pnl_pct:.6f}%"
        )
    else:
        telegram(
            f"💓 Bot FUTURES activo\n"
            f"⏳ Sin posición\n"
            f"📤 Precio: {last_price:.6f}"
        )
                
    with open(REPORT_FILE, "w") as f:
        json.dump({"last": now}, f)
        
# ================== BOT ==================
def run_bot():
    start = time.time()
    init_csv()

    while time.time() - start < 57:
        try:
            ohlcv = exchange.fetch_ohlcv(SYMBOL, TIMEFRAME, limit=300)
            df = pd.DataFrame(ohlcv, columns=["t","o","h","l","c","v"])
            close = df["c"]

            rsi = RSIIndicator(close, RSI_PERIOD).rsi().iloc[-1]
            ema_fast = EMAIndicator(close, EMA_FAST).ema_indicator().iloc[-1]
            ema_slow = EMAIndicator(close, EMA_SLOW).ema_indicator().iloc[-1]

            last_price = close.iloc[-1]
            
            state = load_state()
            in_position = state["position"]

            # ================== ENTRADA ==================
            if not in_position:
                balance = exchange.fetch_balance()["USDT"]["free"]
                qty = (balance * RISK_PERCENT * LEVERAGE) / last_price
                qty = float(exchange.amount_to_precision(SYMBOL, qty))

                if qty * last_price < 20:
                    time.sleep(2)
                    continue

                # LONG - lógica mejorada
                ema_200 = EMAIndicator(close, 200).ema_indicator().iloc[-1]
                lookback_vol = 12  # últimas 20 velas (20 minutos)
                rango_volatilidad = (
                    df["h"].tail(lookback_vol).max() -
                    df["l"].tail(lookback_vol).min()
                )
                #rango_volatilidad = df["h"].max() - df["l"].min()
                filtro_volatilidad = rango_volatilidad > last_price * 0.0015  # antes 0.007
                filtro_ema = ema_fast > ema_slow * 1.0005  # antes 1.002
                filtro_tendencia = last_price > ema_200 * 0.999
                filtro_rsi = 40 <= rsi <= 50
                
                # 🔍 DEBUG (solo para pruebas)
                #telegram(
                #    f"DEBUG {SYMBOL}\n"
                #    f"RSI: {rsi:.6f}\n"
                #    f"EMA12: {ema_fast:.6f}\n"
                #    f"EMA50: {ema_slow:.6f}\n"
                #    f"EMA200: {ema_200:.6f}\n"
                #    f"Vol: {(rango_volatilidad / last_price) * 100:.3f}%\n"
                #    f"Filtros → RSI:{filtro_rsi} | EMA:{filtro_ema} | "
                #    f"TEND:{filtro_tendencia} | VOL:{filtro_volatilidad}"
                #)

                if filtro_rsi and filtro_ema and filtro_tendencia and filtro_volatilidad:
                    try:
                        exchange.set_margin_mode('isolated', SYMBOL)
                    except Exception:
                        pass
                    exchange.create_market_buy_order(SYMBOL, qty)
                    entry = last_price

                    # GENERA TP Y SL FIJOS SE REEMPLAZO POR TP DINAMICO LINEAS CONTINUAS
                    # tp = entry * (1 + TAKE_PROFIT_PERCENT)
                    # sl = entry * (1 - STOP_LOSS_PERCENT)
                    
                    sl = entry * (1 - STOP_LOSS_PERCENT)
                    risk = entry - sl
                    tp = entry + (risk * 1.6)

                    exchange.create_order(
                        SYMBOL, "TAKE_PROFIT_MARKET", "sell", qty,
                        params={"stopPrice": exchange.price_to_precision(SYMBOL, tp), "closePosition": True}
                    )

                    exchange.create_order(
                        SYMBOL, "STOP_MARKET", "sell", qty,
                        params={"stopPrice": exchange.price_to_precision(SYMBOL, sl), "closePosition": True}
                    )

                    telegram(
                        f"🟢 LONG {SYMBOL}\n"
                        f"📥 Entrada: {entry:.6f}\n"
                        f"🎯 TP: {tp:.6f}\n"
                        f"🛑 SL: {sl:.6f}\n"
                        f"📦 Qty: {qty}\n"
                        f"⚙️ Leverage: {LEVERAGE}x"
                    )
                    
                    entry = last_price

                    save_state({
                        "position": True,
                        "side": "long",
                        "entry_price": entry,
                        "quantity": qty,
                        "entry_time": time.time()  # Guardar tiempo de entrada
                    })
                    
                    in_position = True
                    state["position"] = True
                    continue

                # SHORT - lógica mejorada
                filtro_rsi_short = rsi >= 55
                filtro_ema_short = ema_fast < ema_slow * 0.9995  # antes 0.998
                filtro_tendencia_short = last_price < ema_200 * 1.001
                filtro_volatilidad_short = rango_volatilidad > last_price * 0.0015  # antes 0.01

                if filtro_rsi_short and filtro_ema_short and filtro_tendencia_short and filtro_volatilidad_short:
                    try:
                        exchange.set_margin_mode('isolated', SYMBOL)
                    except Exception:
                        pass
                    exchange.create_market_sell_order(SYMBOL, qty)
                    entry = last_price

                    # GENERA TP Y SL FIJOS SE REEMPLAZO POR TP DINAMICO LINEAS CONTINUAS
                    # tp = entry * (1 - TAKE_PROFIT_PERCENT)
                    # sl = entry * (1 + STOP_LOSS_PERCENT)
                    
                    sl = entry * (1 + STOP_LOSS_PERCENT)
                    risk = sl - entry
                    tp = entry - (risk * 1.6)

                    exchange.create_order(
                        SYMBOL, "TAKE_PROFIT_MARKET", "buy", qty,
                        params={"stopPrice": exchange.price_to_precision(SYMBOL, tp), "closePosition": True}
                    )

                    exchange.create_order(
                        SYMBOL, "STOP_MARKET", "buy", qty,
                        params={"stopPrice": exchange.price_to_precision(SYMBOL, sl), "closePosition": True}
                    )

                    telegram(
                        f"🔴 SHORT {SYMBOL}\n"
                        f"📥 Entrada: {entry:.6f}\n"
                        f"🎯 TP: {tp:.6f}\n"
                        f"🛑 SL: {sl:.6f}\n"
                        f"📦 Qty: {qty}\n"
                        f"⚙️ Leverage: {LEVERAGE}x"
                    )
                    
                    entry = last_price

                    save_state({
                        "position": True,
                        "side": "short",
                        "entry_price": entry,
                        "quantity": qty,
                        "entry_time": time.time()  # Guardar tiempo de entrada
                    })
                    
                    in_position = True
                    state["position"] = True
                    continue

            # ================== SALIDA ==================
            if in_position:
                positions = exchange.fetch_positions([SYMBOL])

                binance_qty = None
                for p in positions:
                    if SYMBOL in p.get("symbol", ""):
                        binance_qty = abs(float(p.get("contracts", 0)))
                
                #telegram(f"⚠️ positions: {positions}")

                # Si Binance aún no responde, NO hacer nada
                if binance_qty is None:
                    continue

                now = time.time()
                entry_time = state.get("entry_time", 0)

                # ⛔ Protección fuerte
                MIN_HOLD_TIME = 15  # segundos
                
                #telegram(f"⚠️ binance_qty: {binance_qty}")

                if binance_qty == 0 and now - entry_time > MIN_HOLD_TIME:
                    exit_price = last_price
                    entry = state["entry_price"]
                    side = state["side"]
                    qty = state.get("quantity", 0)
                    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    
                    if side == "long":
                        sl = entry * (1 - STOP_LOSS_PERCENT)
                        risk = entry - sl
                        tp = entry + (risk * 1.6)
                        pnl_pct = ((exit_price - entry) / entry) * 100
                        result = "TP 🎯" if pnl_pct > 0 else "SL 🛑"
                        pnl_usdt = (exit_price - entry) * state["quantity"]
                    else:
                        sl = entry * (1 + STOP_LOSS_PERCENT)
                        risk = sl - entry
                        tp = entry - (risk * 1.6)
                        pnl_pct = ((entry - exit_price) / entry) * 100
                        result = "TP 🎯" if pnl_pct > 0 else "SL 🛑"
                        pnl_usdt = (entry - exit_price) * state["quantity"]

                    telegram(
                        f"{result} {SYMBOL}\n"
                        f"📥 Entrada: {entry:.6f}\n"
                        f"📤 Salida aprox: {exit_price:.6f}\n"
                        f"📦 Qty: {qty}\n"
                        f"📈 Resultado: {pnl_pct:.6f}%"
                    )

                    # Guardar trade en CSV
                    rr1 = abs((tp - entry) / (entry - sl))
                    rr = round(rr1, 2)
                    with open(TRADES_FILE, "a", newline="") as f:
                        writer = csv.writer(f)
                        writer.writerow([
                            timestamp, SYMBOL, side, entry, exit_price, qty, f"{pnl_pct:.2f}", f"{pnl_usdt:.2f}", result, sl, tp, rr
                        ])

                    save_state({
                        "position": False,
                        "side": None,
                        "entry_price": 0,
                        "quantity": 0,
                        "entry_time": 0
                    })
                    
            hourly_report()  # Llama al reporte en cada ciclo
        except Exception as e:
            telegram(f"⚠️ Error bot futuros: {e}")

        time.sleep(3)

if __name__ == "__main__":
    run_bot()
