# -*- coding: utf-8 -*-
"""Apply binance app.py risk/layout changes to gate app.py (pattern replace)."""
from pathlib import Path

binance = Path(__file__).resolve().parent.parent / "app.py"
gate = Path(r"c:\Users\dekun\Desktop\crypto_monitor\crypto_monitor_gate\app.py")

b = binance.read_text(encoding="utf-8")
g = gate.read_text(encoding="utf-8")

# 1) env block
old_env = """KEY_BREAKOUT_LIMIT_PCT = float(os.getenv("KEY_BREAKOUT_LIMIT_PCT", "1.5"))
KEY_AUTO_MIN_PLANNED_RR = float(os.getenv("KEY_AUTO_MIN_PLANNED_RR", "1.5"))
KEY_STOP_OUTSIDE_BREAKOUT_PCT = float(os.getenv("KEY_STOP_OUTSIDE_BREAKOUT_PCT", "0.5"))"""

new_env = """KEY_AUTO_MIN_PLANNED_RR = float(os.getenv("KEY_AUTO_MIN_PLANNED_RR", "1.5"))
KEY_STOP_OUTSIDE_BREAKOUT_PCT = float(os.getenv("KEY_STOP_OUTSIDE_BREAKOUT_PCT", "0.5"))
MANUAL_MIN_PLANNED_RR = float(os.getenv("MANUAL_MIN_PLANNED_RR", "1.4"))
MAX_ACTIVE_POSITIONS = max(1, int(os.getenv("MAX_ACTIVE_POSITIONS", "1")))
KEY_VOLUME_MA_BARS = max(1, int(os.getenv("KEY_VOLUME_MA_BARS", "20")))
KEY_VOLUME_RATIO_MIN = float(os.getenv("KEY_VOLUME_RATIO_MIN", "1.3"))
KEY_BREAKOUT_AMP_MIN_PCT = float(os.getenv("KEY_BREAKOUT_AMP_MIN_PCT", "0.03"))
KEY_BREAKOUT_AMP_MAX_PCT = float(os.getenv("KEY_BREAKOUT_AMP_MAX_PCT", "0.5"))
KEY_DAILY_VOLUME_RANK_MAX = max(1, int(os.getenv("KEY_DAILY_VOLUME_RANK_MAX", "30")))
KEY_CONFIRM_BREAKOUT_BAR = int(os.getenv("KEY_CONFIRM_BREAKOUT_BAR", "-2"))
KEY_CONFIRM_BAR = int(os.getenv("KEY_CONFIRM_BAR", "-1"))
KEY_SIZING_USE_ZERO_POSITION_SNAPSHOT = os.getenv("KEY_SIZING_USE_ZERO_POSITION_SNAPSHOT", "true").lower() == "true")"""

if old_env in g:
    g = g.replace(old_env, new_env)

# 2) DB migration snippet
snip = """    try:
        c.execute("ALTER TABLE trading_sessions ADD COLUMN key_sizing_capital_snapshot REAL")
    except Exception:
        pass

    c.execute("""
if snip not in g and 'key_sizing_capital_snapshot' not in g:
    g = g.replace(
        '    c.execute(\n        """CREATE TABLE IF NOT EXISTS key_monitor_history',
        """    try:
        c.execute("ALTER TABLE trading_sessions ADD COLUMN key_sizing_capital_snapshot REAL")
    except Exception:
        pass

    c.execute(
        \"\"\"CREATE TABLE IF NOT EXISTS key_monitor_history""",
        1,
    )

# 3) precheck block - extract from binance
import re
m = re.search(
    r"def get_active_position_count\(conn\):.*?return True, \"\"\n\n\ndef prepare_order_amount",
    b,
    re.S,
)
if m and "get_active_position_count" not in g:
    g = g.replace(
        "def precheck_risk(conn, symbol, direction):\n    now = app_now()\n    if not trading_day_reset_allows_new_open(now):\n        return False, f\"北京时间 {TRADING_DAY_RESET_HOUR}:00 前不允许持仓\"\n    active_count = conn.execute(\"SELECT COUNT(*) FROM order_monitors WHERE status='active'\").fetchone()[0]\n    if active_count > 0:\n        return False, \"一次只能持有一个仓位\"\n    if direction not in (\"long\", \"short\"):\n        return False, \"方向必须为 long 或 short\"\n    if symbol.upper().startswith(\"BTC\") or symbol.upper().startswith(\"ETH\"):\n        expected = BTC_LEVERAGE\n    else:\n        expected = ALT_LEVERAGE\n    if expected <= 0:\n        return False, \"杠杆配置异常\"\n    return True, \"\"\n\n\ndef prepare_order_amount",
        m.group(0),
    )

# 4) render_main_page can_trade + template vars + route
if "key_monitor_page" not in g:
    g = g.replace(
        "    can_trade = trading_day_reset_allows_new_open(now) and active_count == 0\n    conn.close()\n    return render_template(",
        """    can_trade = trading_day_reset_allows_new_open(now) and active_count < MAX_ACTIVE_POSITIONS
    key_gate_rule_text = (
        f"周期 {KLINE_TIMEFRAME}｜确认K:突破棒偏移 {KEY_CONFIRM_BREAKOUT_BAR},确认棒偏移 {KEY_CONFIRM_BAR}｜"
        f"量能:突破量 > 前{KEY_VOLUME_MA_BARS}均量×{KEY_VOLUME_RATIO_MIN}｜"
        f"自动开仓盈亏比 > {KEY_AUTO_MIN_PLANNED_RR}:1｜日成交量排名前 {KEY_DAILY_VOLUME_RANK_MAX}"
    )
    conn.close()
    return render_template(""",
    )
    g = g.replace(
        "        exchange_display=EXCHANGE_DISPLAY_NAME,\n    )\n\n\n@app.route(\"/\")\n@login_required\ndef index():\n    return redirect(\"/trade\")\n\n\n@app.route(\"/trade\")",
        """        exchange_display=EXCHANGE_DISPLAY_NAME,
        max_active_positions=MAX_ACTIVE_POSITIONS,
        manual_min_planned_rr=MANUAL_MIN_PLANNED_RR,
        key_auto_min_planned_rr=KEY_AUTO_MIN_PLANNED_RR,
        key_gate_rule_text=key_gate_rule_text,
        kline_timeframe=KLINE_TIMEFRAME,
    )


@app.route("/")
@login_required
def index():
    return redirect("/trade")


@app.route("/key_monitor")
@login_required
def key_monitor_page():
    return render_main_page("key_monitor")


@app.route("/trade")""",
    )

# api account
g = g.replace(
    "    active_count = conn.execute(\"SELECT COUNT(*) FROM order_monitors WHERE status='active'\").fetchone()[0]\n    conn.close()\n    can_trade = trading_day_reset_allows_new_open(now) and active_count == 0",
    "    active_count = get_active_position_count(conn)\n    conn.close()\n    can_trade = trading_day_reset_allows_new_open(now) and active_count < MAX_ACTIVE_POSITIONS",
)
if '"max_active_positions"' not in g:
    g = g.replace(
        '"can_trade": can_trade,\n        "trading_day": trading_day\n    })',
        '"can_trade": can_trade,\n        "max_active_positions": MAX_ACTIVE_POSITIONS,\n        "manual_min_planned_rr": MANUAL_MIN_PLANNED_RR,\n        "trading_day": trading_day\n    })',
    )

gate.write_text(g, encoding="utf-8")
print("gate app partially synced; manual review _key_hard_checks add_order still needed")
