#!/usr/bin/env python3
"""
浪浪AI 实时监控服务 — M1主循环

每小时执行:
1. 拉取所有币种最新K线
2. 聚合4H和日线
3. 对每个币种跑信号管线
4. 新信号 → 过滤 → 仓位计算 → Telegram推送
5. 记录日志

每日执行:
1. 推送日报
2. 推送心跳

用法:
    # 直接运行
    python main.py

    # 指定配置
    TELEGRAM_BOT_TOKEN=xxx TELEGRAM_CHAT_ID=yyy python main.py

    # 只扫描一次（不循环）
    python main.py --once

    # 指定余额
    python main.py --balance 5000

部署:
    # systemd service
    sudo cp langlang_ai.service /etc/systemd/system/
    sudo systemctl enable langlang_ai
    sudo systemctl start langlang_ai
"""

import os
import sys
import time
import logging
import argparse
import signal as signal_module
from datetime import datetime, timezone, timedelta

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from langlang_ai.config.coins import COINS
from langlang_ai.data.database import Database
from langlang_ai.live.fetcher import BinanceLiveFetcher
from langlang_ai.live.scanner import LiveScanner
from langlang_ai.notify.telegram_bot import TelegramNotifier
from langlang_ai.notify.templates import format_status_update

# ==================== Logging ====================
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler('langlang_ai.log', encoding='utf-8'),
    ]
)
logger = logging.getLogger('langlang_ai')

# ==================== Graceful shutdown ====================
running = True

def shutdown_handler(signum, frame):
    global running
    logger.info("Received shutdown signal, stopping gracefully...")
    running = False

signal_module.signal(signal_module.SIGINT, shutdown_handler)
signal_module.signal(signal_module.SIGTERM, shutdown_handler)


# ==================== Main Loop ====================

def run_hourly_scan(fetcher, scanner, notifier):
    """每小时执行的扫描任务"""
    scan_start = time.time()
    logger.info("=" * 50)
    logger.info("Starting hourly scan...")

    # 1. 拉取最新K线
    try:
        update_results = fetcher.update_all()
        total_new = sum(update_results.values())
        logger.info(f"Data update: {total_new} new bars across {len(update_results)} coins")
    except Exception as e:
        logger.error(f"Data fetch error: {e}")
        notifier.send_sync(f"⚠️ 数据拉取失败: {e}")
        return

    # 2. 加载所有时间周期数据
    all_tf_data = {}
    for symbol in COINS:
        try:
            tf = fetcher.get_all_timeframes(symbol)
            if tf:
                all_tf_data[symbol] = tf
        except Exception as e:
            logger.error(f"Timeframe aggregation error {symbol}: {e}")

    if not all_tf_data:
        logger.warning("No data available for any coin")
        return

    # 3. 扫描信号
    try:
        new_signals = scanner.scan_all(all_tf_data)
    except Exception as e:
        logger.error(f"Signal scan error: {e}")
        notifier.send_sync(f"⚠️ 信号扫描失败: {e}")
        return

    # 4. 推送新信号
    for sig in new_signals:
        try:
            notifier.send_signal_sync(sig)
            logger.info(f"Signal sent: {sig['coin']} {sig['direction']} {sig['signal_type']}")
        except Exception as e:
            logger.error(f"Notification error: {e}")

    scan_duration = time.time() - scan_start
    logger.info(f"Scan complete: {len(new_signals)} new signals, {scan_duration:.1f}s")


def run_daily_tasks(scanner, notifier, all_tf_data):
    """每日执行的任务"""
    logger.info("Running daily tasks...")

    # 状态概览
    try:
        status = scanner.get_coins_status(all_tf_data)
        if status:
            text = format_status_update(status)
            notifier.send_sync(text)
    except Exception as e:
        logger.error(f"Status update error: {e}")


def wait_for_next_hour():
    """等待到下一个整点 + 5分钟（等K线完成）"""
    now = datetime.now(timezone.utc)
    next_hour = (now + timedelta(hours=1)).replace(minute=5, second=0, microsecond=0)
    wait_seconds = (next_hour - now).total_seconds()

    if wait_seconds < 0:
        wait_seconds += 3600

    logger.info(f"Next scan at {next_hour.strftime('%H:%M UTC')} "
                f"(waiting {wait_seconds/60:.0f} min)")
    return wait_seconds


def main():
    parser = argparse.ArgumentParser(description="浪浪AI 实时监控")
    parser.add_argument("--once", action="store_true",
                        help="只扫描一次，不循环")
    parser.add_argument("--balance", type=float, default=1000,
                        help="当前账户余额")
    parser.add_argument("--db", type=str, default="langlang.db",
                        help="数据库文件路径")
    parser.add_argument("--init", action="store_true",
                        help="首次运行：下载历史数据")
    parser.add_argument("--init-days", type=int, default=365,
                        help="初始化时下载多少天数据")
    parser.add_argument("--auto-trade", action="store_true",
                        help="启用自动交易（M3模式）")
    parser.add_argument("--testnet", action="store_true",
                        help="使用Binance测试网")
    args = parser.parse_args()

    # ===== 初始化组件 =====
    logger.info("=" * 60)
    mode = "自动交易" if args.auto_trade else "信号监控"
    logger.info(f"浪浪AI {mode}系统 启动")
    logger.info("=" * 60)

    db = Database(args.db)
    notifier = TelegramNotifier()
    fetcher = BinanceLiveFetcher(db)
    scanner = LiveScanner(db, notifier, balance=args.balance)

    # 自动交易组件
    order_manager = None
    risk_guard = None

    if args.auto_trade:
        from langlang_ai.execution.binance_client import BinanceClient
        from langlang_ai.execution.order_manager import OrderManager
        from langlang_ai.execution.risk_guard import RiskGuard

        try:
            client = BinanceClient.from_env(testnet=args.testnet)
            risk_guard = RiskGuard(db, notifier)
            order_manager = OrderManager(
                client, db, notifier, balance=args.balance
            )
            logger.info(f"Auto-trade enabled ({'testnet' if args.testnet else 'LIVE'})")
        except Exception as e:
            logger.error(f"Auto-trade init failed: {e}")
            logger.info("Falling back to signal-only mode")
            args.auto_trade = False

    # ===== 首次初始化 =====
    if args.init:
        logger.info(f"Initializing historical data ({args.init_days} days)...")
        notifier.send_sync("🚀 浪浪AI 初始化中，正在下载历史数据...")
        fetcher.initialize_all(days=args.init_days)
        logger.info("Initialization complete!")
        notifier.send_sync("✅ 历史数据初始化完成！")

    # ===== 启动通知 =====
    notifier.send_sync(
        f"🚀 浪浪AI {mode}启动\n"
        f"余额: ${args.balance:,.0f}\n"
        f"币种: {len(COINS)}个\n"
        f"模式: {mode} {'(testnet)' if args.testnet else ''}\n"
        f"运行: {'单次扫描' if args.once else '持续监控'}"
    )

    # ===== 主循环 =====
    last_daily = None
    trailing_check_counter = 0  # 每4次扫描(4小时)检查一次trailing

    if args.once:
        run_hourly_scan(fetcher, scanner, notifier)
        db.close()
        return

    while running:
        try:
            # 每小时扫描信号
            run_hourly_scan(fetcher, scanner, notifier)

            # 自动交易：执行新信号 + 检查trailing
            if args.auto_trade and order_manager and risk_guard:
                # 获取最新信号并执行
                all_tf = {}
                for sym in COINS:
                    tf = fetcher.get_all_timeframes(sym)
                    if tf:
                        all_tf[sym] = tf

                new_signals = scanner.scan_all(all_tf)
                for sig in new_signals:
                    if risk_guard.is_halted:
                        logger.warning(f"Risk halt, skipping signal {sig['coin']}")
                        break

                    ok, reason = risk_guard.pre_trade_check(
                        balance=order_manager.balance,
                        margin_needed=sig.get('notional', 0) / sig.get('leverage', 10),
                        symbol=sig['coin'],
                    )
                    if ok:
                        order_manager.open_position(sig)
                    else:
                        logger.info(f"Risk check blocked {sig['coin']}: {reason}")

                # 每4小时检查trailing
                trailing_check_counter += 1
                if trailing_check_counter >= 4:
                    trailing_check_counter = 0
                    order_manager.check_all_trailing()

            # 每日任务（UTC 0点执行）
            today = datetime.now(timezone.utc).date()
            if last_daily != today:
                all_tf = {}
                for sym in COINS:
                    tf = fetcher.get_all_timeframes(sym)
                    if tf:
                        all_tf[sym] = tf
                run_daily_tasks(scanner, notifier, all_tf)

                # 自动交易：每日对账
                if args.auto_trade and order_manager:
                    order_manager.reconcile()

                last_daily = today

            # 等待下一个整点
            wait = wait_for_next_hour()
            for _ in range(int(wait)):
                if not running:
                    break
                time.sleep(1)

        except Exception as e:
            logger.error(f"Main loop error: {e}", exc_info=True)
            try:
                notifier.send_sync(f"⚠️ 主循环异常: {e}")
            except:
                pass
            time.sleep(60)  # 异常后等1分钟再重试

    # ===== 清理 =====
    logger.info("Shutting down...")
    notifier.send_sync("🔴 浪浪AI 监控已停止")
    db.close()
    logger.info("Goodbye!")


if __name__ == "__main__":
    main()
