"""
telegram_cmd_bot.py
===================
Bot Telegram untuk monitoring akun trading via command.
Jalan terpisah dari signal_bot.py, menggunakan Bot API (polling).

Commands:
    /status  - Ringkasan lengkap (balance, posisi, history, profit)
    /pos     - Posisi terbuka saat ini
    /history - Riwayat trade hari ini
    /profit  - Profit/loss hari ini
    /score   - Scorecard per channel

Cara pakai:
    python telegram_cmd_bot.py
"""

import os
import json
import time
import logging
import requests
from datetime import datetime, timezone, timedelta
from dotenv import load_dotenv
import MetaTrader5 as mt5

load_dotenv()

# ============================================================
# KONFIGURASI
# ============================================================
BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
POLL_INTERVAL = 2  # Cek pesan baru setiap 2 detik
TRADE_LOG_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "trade_log.json")

# ============================================================
# LOGGING
# ============================================================
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)
log = logging.getLogger("cmd_bot")

# ============================================================
# MT5 HELPER FUNCTIONS
# ============================================================

def connect_mt5():
    """Koneksi ke MT5 terminal."""
    if not mt5.initialize():
        log.error(f"MT5 initialize gagal: {mt5.last_error()}")
        return False

    mt5_login = int(os.getenv("MT5_LOGIN", "0"))
    mt5_password = os.getenv("MT5_PASSWORD", "")
    mt5_server = os.getenv("MT5_SERVER", "")

    info = mt5.account_info()
    if info is None and mt5_login and mt5_password:
        if not mt5.login(mt5_login, password=mt5_password, server=mt5_server):
            log.error(f"MT5 login gagal: {mt5.last_error()}")
            return False

    info = mt5.account_info()
    if info is None:
        log.error("Gagal mendapatkan info akun MT5.")
        return False

    log.info(f"✅ MT5 terhubung! Balance: {info.balance} {info.currency}")
    return True


def get_account_info():
    """Ambil info akun."""
    info = mt5.account_info()
    if info is None:
        return None
    return {
        "balance": info.balance,
        "equity": info.equity,
        "margin": info.margin,
        "free_margin": info.margin_free,
        "currency": info.currency,
        "leverage": info.leverage,
        "profit": info.profit,
    }


def get_open_positions():
    """Ambil semua posisi terbuka."""
    positions = mt5.positions_get()
    if positions is None:
        return []
    return [{
        "ticket": p.ticket,
        "symbol": p.symbol,
        "type": "BUY" if p.type == 0 else "SELL",
        "volume": p.volume,
        "open_price": p.price_open,
        "current_price": p.price_current,
        "sl": p.sl,
        "tp": p.tp,
        "profit": p.profit,
        "swap": p.swap,
        "time": datetime.fromtimestamp(p.time).strftime("%H:%M:%S"),
    } for p in positions]


def get_deals_today():
    """Ambil deal history hari ini (yang sudah close)."""
    now = datetime.now(timezone.utc)
    start = now.replace(hour=0, minute=0, second=0, microsecond=0)

    deals = mt5.history_deals_get(start, now)
    if deals is None:
        return []
    return [{
        "ticket": d.ticket,
        "symbol": d.symbol,
        "type": "BUY" if d.type == 0 else "SELL",
        "volume": d.volume,
        "price": d.price,
        "profit": round(d.profit, 2),
        "commission": round(d.commission, 2),
        "swap": round(d.swap, 2),
        "time": datetime.fromtimestamp(d.time).strftime("%H:%M:%S"),
    } for d in deals if d.entry in [1, 2]]  # DEAL_ENTRY_OUT, DEAL_ENTRY_INOUT


def calc_daily_pnl():
    """Hitung profit/loss hari ini."""
    deals = get_deals_today()
    total_profit = sum(d["profit"] + d["commission"] + d["swap"] for d in deals)
    win_count = sum(1 for d in deals if d["profit"] > 0)
    loss_count = sum(1 for d in deals if d["profit"] < 0)
    be_count = sum(1 for d in deals if d["profit"] == 0)

    info = mt5.account_info()
    balance = info.balance if info else 0
    initial_balance = balance - total_profit
    pct = (total_profit / initial_balance * 100) if initial_balance > 0 else 0

    return {
        "total_profit": round(total_profit, 2),
        "pct": round(pct, 2),
        "total_trades": len(deals),
        "wins": win_count,
        "losses": loss_count,
        "breakeven": be_count,
    }


# ============================================================
# MESSAGE FORMATTERS
# ============================================================

def format_status():
    """Format pesan /status — ringkasan lengkap."""
    acc = get_account_info()
    if not acc:
        return "❌ Gagal membaca info akun MT5."

    positions = get_open_positions()
    pnl = calc_daily_pnl()
    now = datetime.now().strftime("%d/%m/%Y %H:%M")

    msg = f"📊 <b>STATUS REPORT</b>\n"
    msg += f"🕐 {now}\n"
    msg += f"{'━' * 28}\n\n"

    # Account
    msg += f"💰 <b>AKUN</b>\n"
    msg += f"   Balance : <b>${acc['balance']:.2f}</b>\n"
    msg += f"   Equity  : ${acc['equity']:.2f}\n"
    msg += f"   Margin  : ${acc['margin']:.2f}\n"
    msg += f"   Free    : ${acc['free_margin']:.2f}\n"
    msg += f"   Floating: <b>${acc['profit']:.2f}</b>\n\n"

    # Daily P/L
    icon = "🟢" if pnl['total_profit'] >= 0 else "🔴"
    msg += f"{icon} <b>PROFIT HARI INI</b>\n"
    msg += f"   P/L     : <b>${pnl['total_profit']:.2f}</b> ({pnl['pct']:+.2f}%)\n"
    msg += f"   Trades  : {pnl['total_trades']} (W:{pnl['wins']} L:{pnl['losses']} BE:{pnl['breakeven']})\n\n"

    # Open Positions
    msg += f"📈 <b>POSISI TERBUKA ({len(positions)})</b>\n"
    if not positions:
        msg += "   Tidak ada posisi terbuka.\n"
    else:
        for p in positions:
            icon = "🟢" if p["profit"] >= 0 else "🔴"
            dir_icon = "⬆️" if p["type"] == "BUY" else "⬇️"
            msg += (
                f"   {dir_icon} {p['symbol']} {p['type']} {p['volume']}\n"
                f"      Open: {p['open_price']} → Now: {p['current_price']}\n"
                f"      SL: {p['sl']} | TP: {p['tp']}\n"
                f"      {icon} P/L: <b>${p['profit']:.2f}</b>\n\n"
            )

    # Recent deals
    deals = get_deals_today()
    msg += f"📜 <b>HISTORY HARI INI ({len(deals)})</b>\n"
    if not deals:
        msg += "   Belum ada trade tertutup.\n"
    else:
        for d in deals[-5:]:  # Max 5 terakhir
            icon = "💰" if d["profit"] > 0 else ("💔" if d["profit"] < 0 else "🛡️")
            msg += f"   {icon} {d['symbol']} {d['type']} {d['volume']} @ {d['price']} → ${d['profit']:.2f} ({d['time']})\n"
        if len(deals) > 5:
            msg += f"   ... dan {len(deals) - 5} trade lainnya\n"

    return msg


def format_positions():
    """Format pesan /pos — posisi terbuka."""
    positions = get_open_positions()
    if not positions:
        return "📈 Tidak ada posisi terbuka saat ini."

    msg = f"📈 <b>POSISI TERBUKA ({len(positions)})</b>\n{'━' * 28}\n\n"
    total_profit = 0

    for p in positions:
        icon = "🟢" if p["profit"] >= 0 else "🔴"
        dir_icon = "⬆️" if p["type"] == "BUY" else "⬇️"
        msg += (
            f"{dir_icon} <b>{p['symbol']} {p['type']}</b> | Lot: {p['volume']}\n"
            f"   Open: {p['open_price']} → Now: {p['current_price']}\n"
            f"   SL: {p['sl']} | TP: {p['tp']}\n"
            f"   {icon} P/L: <b>${p['profit']:.2f}</b> | Swap: ${p['swap']:.2f}\n"
            f"   ⏰ Opened: {p['time']}\n\n"
        )
        total_profit += p["profit"]

    icon = "🟢" if total_profit >= 0 else "🔴"
    msg += f"{icon} <b>Total Floating: ${total_profit:.2f}</b>"
    return msg


def format_history():
    """Format pesan /history — riwayat trade hari ini."""
    deals = get_deals_today()
    if not deals:
        return "📜 Belum ada trade tertutup hari ini."

    msg = f"📜 <b>TRADE HISTORY HARI INI</b>\n{'━' * 28}\n\n"
    total = 0

    for d in deals:
        icon = "💰" if d["profit"] > 0 else ("💔" if d["profit"] < 0 else "🛡️")
        net = d["profit"] + d["commission"] + d["swap"]
        msg += (
            f"{icon} <b>{d['symbol']} {d['type']}</b> {d['volume']} @ {d['price']}\n"
            f"   Profit: ${d['profit']:.2f} | Comm: ${d['commission']:.2f} | Swap: ${d['swap']:.2f}\n"
            f"   Net: <b>${net:.2f}</b> | ⏰ {d['time']}\n\n"
        )
        total += net

    icon = "🟢" if total >= 0 else "🔴"
    msg += f"{'━' * 28}\n"
    msg += f"{icon} <b>Total Closed P/L: ${total:.2f}</b> ({len(deals)} trades)"
    return msg


def format_profit():
    """Format pesan /profit — ringkasan P/L."""
    pnl = calc_daily_pnl()
    acc = get_account_info()
    if not acc:
        return "❌ Gagal membaca info akun."

    icon = "🟢" if pnl["total_profit"] >= 0 else "🔴"
    wr = (pnl["wins"] / pnl["total_trades"] * 100) if pnl["total_trades"] > 0 else 0

    msg = f"{icon} <b>PROFIT REPORT</b>\n{'━' * 28}\n\n"
    msg += f"💰 Balance: <b>${acc['balance']:.2f}</b>\n"
    msg += f"📊 Equity : ${acc['equity']:.2f}\n"
    msg += f"📈 Floating: ${acc['profit']:.2f}\n\n"
    msg += f"📅 <b>Hari Ini:</b>\n"
    msg += f"   Closed P/L: <b>${pnl['total_profit']:.2f}</b> ({pnl['pct']:+.2f}%)\n"
    msg += f"   Total Trades: {pnl['total_trades']}\n"
    msg += f"   Win/Loss/BE: {pnl['wins']}/{pnl['losses']}/{pnl['breakeven']}\n"
    msg += f"   Win Rate: {wr:.0f}%\n"

    return msg


def format_scorecard():
    """Format pesan /score — scorecard per channel."""
    # Baca trade log
    if not os.path.exists(TRADE_LOG_FILE):
        return "📋 Belum ada data trade. Scorecard akan terisi setelah ada trade."

    try:
        with open(TRADE_LOG_FILE, "r", encoding="utf-8") as f:
            logs = json.load(f)
    except Exception:
        return "❌ Gagal membaca trade_log.json."

    if not logs:
        return "📋 Belum ada data trade."

    # Ambil semua deals dari MT5 (30 hari terakhir)
    now = datetime.now(timezone.utc)
    start = now - timedelta(days=30)
    all_deals = mt5.history_deals_get(start, now)
    if all_deals is None:
        all_deals = []

    # Buat mapping: order_id → profit (dari deal ENTRY_OUT)
    deal_profit = {}
    for d in all_deals:
        if d.entry in [1, 2]:  # DEAL_ENTRY_OUT, DEAL_ENTRY_INOUT
            deal_profit[d.order] = round(d.profit + d.commission + d.swap, 2)
        # Juga cek position_id untuk matching
        if d.entry in [1, 2] and d.position_id:
            deal_profit[d.position_id] = round(d.profit + d.commission + d.swap, 2)

    # Hitung scorecard per channel
    channels = {}  # {channel_name: {trades, wins, losses, be, total_pnl, open}}

    for trade in logs:
        ch = trade.get("channel", "Unknown")
        if ch not in channels:
            channels[ch] = {"trades": 0, "wins": 0, "losses": 0, "be": 0, "total_pnl": 0.0, "open": 0, "pairs": set()}

        channels[ch]["trades"] += 1
        channels[ch]["pairs"].add(trade.get("pair", ""))

        order_id = trade.get("order_id")
        profit = deal_profit.get(order_id)

        if profit is not None:
            channels[ch]["total_pnl"] += profit
            if profit > 0:
                channels[ch]["wins"] += 1
            elif profit < 0:
                channels[ch]["losses"] += 1
            else:
                channels[ch]["be"] += 1
        else:
            # Posisi mungkin masih terbuka
            channels[ch]["open"] += 1

    # Format output
    msg = f"📋 <b>SIGNAL SCORECARD</b>\n{'━' * 28}\n\n"

    # Sort by total P/L descending
    sorted_channels = sorted(channels.items(), key=lambda x: x[1]["total_pnl"], reverse=True)

    for rank, (ch_name, data) in enumerate(sorted_channels, 1):
        closed = data["wins"] + data["losses"] + data["be"]
        wr = (data["wins"] / closed * 100) if closed > 0 else 0
        icon = "🏆" if rank == 1 else ("🥈" if rank == 2 else "🥉" if rank == 3 else "📊")
        pnl_icon = "🟢" if data["total_pnl"] >= 0 else "🔴"
        pairs = ", ".join(data["pairs"]) if data["pairs"] else "-"

        msg += f"{icon} <b>{ch_name}</b>\n"
        msg += f"   Trades: {data['trades']} | Closed: {closed}\n"
        msg += f"   W/L/BE: {data['wins']}/{data['losses']}/{data['be']}\n"
        msg += f"   Win Rate: <b>{wr:.0f}%</b>\n"
        msg += f"   {pnl_icon} P/L: <b>${data['total_pnl']:.2f}</b>\n"
        if data["open"] > 0:
            msg += f"   ⏳ Masih open: {data['open']}\n"
        msg += f"   Pairs: {pairs}\n\n"

    # Summary
    total_trades = sum(d["trades"] for d in channels.values())
    total_pnl = sum(d["total_pnl"] for d in channels.values())
    total_icon = "🟢" if total_pnl >= 0 else "🔴"
    msg += f"{'━' * 28}\n"
    msg += f"{total_icon} <b>TOTAL: ${total_pnl:.2f}</b> dari {total_trades} sinyal"

    return msg


# ============================================================
# TELEGRAM BOT API (Simple Polling)
# ============================================================

def send_message(text):
    """Kirim pesan via Bot API."""
    url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
    try:
        resp = requests.post(url, json={
            "chat_id": CHAT_ID,
            "text": text,
            "parse_mode": "HTML"
        }, timeout=10)
        if resp.status_code != 200:
            log.error(f"Gagal kirim pesan: {resp.text}")
    except Exception as e:
        log.error(f"Error kirim pesan: {e}")


def get_updates(offset=None):
    """Ambil pesan terbaru dari Bot API."""
    url = f"https://api.telegram.org/bot{BOT_TOKEN}/getUpdates"
    params = {"timeout": 30, "allowed_updates": ["message"]}
    if offset:
        params["offset"] = offset

    try:
        resp = requests.get(url, params=params, timeout=35)
        if resp.status_code == 200:
            return resp.json().get("result", [])
    except Exception as e:
        log.error(f"Error get updates: {e}")

    return []


def handle_command(command):
    """Handle command dan return response text."""
    cmd = command.lower().strip()

    if cmd == "/status" or cmd == "/s":
        return format_status()
    elif cmd == "/pos" or cmd == "/p":
        return format_positions()
    elif cmd == "/history" or cmd == "/h":
        return format_history()
    elif cmd == "/profit" or cmd == "/pl":
        return format_profit()
    elif cmd == "/score" or cmd == "/sc":
        return format_scorecard()
    elif cmd == "/help":
        return (
            "🤖 <b>COMMAND LIST</b>\n"
            "━━━━━━━━━━━━━━━━\n\n"
            "/status (/s) — Ringkasan lengkap\n"
            "/pos (/p) — Posisi terbuka\n"
            "/history (/h) — Trade hari ini\n"
            "/profit (/pl) — Profit/loss summary\n"
            "/score (/sc) — Scorecard per channel\n"
            "/help — Daftar command"
        )
    else:
        return None  # Bukan command yang dikenal


# ============================================================
# MAIN LOOP
# ============================================================

def main():
    log.info("=" * 45)
    log.info("🤖 TELEGRAM COMMAND BOT")
    log.info("=" * 45)

    if not BOT_TOKEN or not CHAT_ID:
        log.error("❌ TELEGRAM_BOT_TOKEN atau TELEGRAM_CHAT_ID belum diset di .env!")
        return

    # Koneksi MT5
    if not connect_mt5():
        log.error("❌ Gagal koneksi MT5. Pastikan MT5 terminal sudah berjalan.")
        return

    log.info(f"📡 Bot aktif! Kirim /help untuk daftar command.")
    log.info(f"⏳ Listening for commands...")

    # Kirim notifikasi bot aktif
    send_message("🤖 <b>Command Bot AKTIF!</b>\nKetik /help untuk daftar command.")

    offset = None

    # Skip old messages — ambil semua pending messages lalu abaikan
    old_updates = get_updates(offset)
    if old_updates:
        offset = old_updates[-1]["update_id"] + 1
        log.info(f"⏭️ Skipped {len(old_updates)} old messages.")

    while True:
        try:
            updates = get_updates(offset)

            for update in updates:
                offset = update["update_id"] + 1

                # Pastikan hanya merespon dari CHAT_ID yang benar
                msg = update.get("message", {})
                chat_id = str(msg.get("chat", {}).get("id", ""))
                text = msg.get("text", "")

                if chat_id != str(CHAT_ID):
                    continue

                if not text.startswith("/"):
                    continue

                log.info(f"📩 Command: {text}")

                response = handle_command(text.split()[0])  # Ambil command saja
                if response:
                    send_message(response)
                    log.info(f"✅ Response sent for {text}")

        except KeyboardInterrupt:
            log.info("Bot dihentikan.")
            break
        except Exception as e:
            log.error(f"Error di main loop: {e}")
            time.sleep(5)

    mt5.shutdown()


if __name__ == "__main__":
    main()
