#!/usr/bin/env python3
"""对 binance/okx 应用与 gate 相同的时间平仓代码替换."""
from __future__ import annotations

from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
FILES = [
    ROOT / "crypto_monitor_binance" / "app.py",
    ROOT / "crypto_monitor_okx" / "app.py",
]

REPLACEMENTS: list[tuple[str, str]] = [
    (
        "def _market_open_for_key_monitor(\n    conn,\n    symbol,\n    direction,\n    exchange_symbol,\n    stop_loss,\n    take_profit,\n    key_signal_type=None,\n    breakeven_enabled=0,\n):",
        "def _market_open_for_key_monitor(\n    conn,\n    symbol,\n    direction,\n    exchange_symbol,\n    stop_loss,\n    take_profit,\n    key_signal_type=None,\n    breakeven_enabled=0,\n    time_close_enabled=0,\n    time_close_hours=None,\n):",
    ),
    (
        "def _add_false_breakout_key_monitor(\n    conn, symbol, direction_sel, upper_px, lower_px, key_px, breakeven_enabled=0,\n):",
        "def _add_false_breakout_key_monitor(\n    conn, symbol, direction_sel, upper_px, lower_px, key_px, breakeven_enabled=0,\n    time_close_enabled=0, time_close_hours=None,\n):",
    ),
    (
        "def _add_fib_key_monitor(conn, symbol, direction_sel, mt, upper_px, lower_px, breakeven_enabled=0):",
        "def _add_fib_key_monitor(\n    conn, symbol, direction_sel, mt, upper_px, lower_px, breakeven_enabled=0,\n    time_close_enabled=0, time_close_hours=None,\n):",
    ),
    (
        "        key_sig = typ if typ in KEY_MONITOR_AUTO_TYPES else None\n        be_on = breakeven_enabled_from_row(r, 0)\n        ok_trade, trade_err, det = _market_open_for_key_monitor(\n            conn,\n            sym,\n            direction,\n            exchange_symbol,\n            sl_raw,\n            tp_raw,\n            key_signal_type=key_sig,\n            breakeven_enabled=1 if be_on else 0,\n        )",
        "        key_sig = typ if typ in KEY_MONITOR_AUTO_TYPES else None\n        be_on = breakeven_enabled_from_row(r, 0)\n        tc_en, tc_h, _ = time_close_settings_from_row(r)\n        ok_trade, trade_err, det = _market_open_for_key_monitor(\n            conn,\n            sym,\n            direction,\n            exchange_symbol,\n            sl_raw,\n            tp_raw,\n            key_signal_type=key_sig,\n            breakeven_enabled=1 if be_on else 0,\n            time_close_enabled=tc_en,\n            time_close_hours=tc_h,\n        )",
    ),
    (
        "        res = None\n        # 做多\n        if direction == \"long\":\n            if p >= take_profit: res = \"止盈\"\n            elif p <= stop_loss: res = \"止损\"\n        # 做空\n        elif direction == \"short\":\n            if p <= take_profit: res = \"止盈\"\n            elif p >= stop_loss: res = \"止损\"",
        "        res = None\n        if should_trigger_time_close(r):\n            res = TIME_CLOSE_RESULT\n        # 做多\n        if not res and direction == \"long\":\n            if p >= take_profit: res = \"止盈\"\n            elif p <= stop_loss: res = \"止损\"\n        # 做空\n        elif not res and direction == \"short\":\n            if p <= take_profit: res = \"止盈\"\n            elif p >= stop_loss: res = \"止损\"",
    ),
    (
        '        "SELECT id,symbol,exchange_symbol,direction,trigger_price,stop_loss,initial_stop_loss,take_profit,margin_capital,leverage FROM order_monitors WHERE status=\'active\'"',
        '        "SELECT id,symbol,exchange_symbol,direction,trigger_price,stop_loss,initial_stop_loss,take_profit,margin_capital,leverage,"\n        "time_close_enabled,time_close_hours,time_close_at_ms,opened_at_ms FROM order_monitors WHERE status=\'active\'"',
    ),
    (
        "        apply_order_price_display_fields(\n            payload,\n            direction=r[\"direction\"],\n            entry_price=entry,\n            initial_stop_loss=r[\"initial_stop_loss\"],\n            stop_loss=r[\"stop_loss\"],\n            take_profit=r[\"take_profit\"],\n            calc_rr_ratio_fn=calc_rr_ratio,\n            exchange_tpsl=exchange_tpsl,\n            format_price_fn=format_price_for_symbol,\n            symbol=r[\"symbol\"],\n        )\n        new_sl, new_tp, changed = order_monitor_tpsl_needs_sync(",
        "        apply_order_price_display_fields(\n            payload,\n            direction=r[\"direction\"],\n            entry_price=entry,\n            initial_stop_loss=r[\"initial_stop_loss\"],\n            stop_loss=r[\"stop_loss\"],\n            take_profit=r[\"take_profit\"],\n            calc_rr_ratio_fn=calc_rr_ratio,\n            exchange_tpsl=exchange_tpsl,\n            format_price_fn=format_price_for_symbol,\n            symbol=r[\"symbol\"],\n        )\n        apply_time_close_to_payload(payload, r)\n        new_sl, new_tp, changed = order_monitor_tpsl_needs_sync(",
    ),
    (
        "        be_flag = parse_breakeven_enabled_form(d.get(\"breakeven_enabled\"))\n        if is_false_breakout_key_monitor_type(mt):",
        "        be_flag = parse_breakeven_enabled_form(d.get(\"breakeven_enabled\"))\n        tc_en = parse_time_close_enabled_form(d.get(\"time_close_enabled\"))\n        tc_h = parse_time_close_hours_form(d.get(\"time_close_hours\")) if tc_en else None\n        if tc_en and not tc_h:\n            tc_en = 0\n        if is_false_breakout_key_monitor_type(mt):",
    ),
    (
        "            ok_fb, err_fb = _add_false_breakout_key_monitor(\n                conn, symbol, direction_sel, upper_px, lower_px, key_px, breakeven_enabled=be_flag,\n            )",
        "            ok_fb, err_fb = _add_false_breakout_key_monitor(\n                conn, symbol, direction_sel, upper_px, lower_px, key_px, breakeven_enabled=be_flag,\n                time_close_enabled=tc_en, time_close_hours=tc_h,\n            )",
    ),
    (
        "                f\"｜有效期 {FALSE_BREAKOUT_VALIDITY_HOURS}h｜移动保本:{'开' if be_flag else '关'}\"\n            )",
        "                f\"｜有效期 {FALSE_BREAKOUT_VALIDITY_HOURS}h｜移动保本:{'开' if be_flag else '关'}\"\n                + (f\"｜{time_close_label(tc_h)}\" if tc_en else \"\")\n            )",
    ),
    (
        "            ok_fib, err_fib = _add_fib_key_monitor(\n                conn, symbol, direction_sel, mt, upper_px, lower_px, breakeven_enabled=be_flag,\n            )",
        "            ok_fib, err_fib = _add_fib_key_monitor(\n                conn, symbol, direction_sel, mt, upper_px, lower_px, breakeven_enabled=be_flag,\n                time_close_enabled=tc_en, time_close_hours=tc_h,\n            )",
    ),
    (
        "                f\"｜移动保本:{'开' if be_flag else '关'}\"\n            )\n            return redirect(\"/key_monitor\")",
        "                f\"｜移动保本:{'开' if be_flag else '关'}\"\n                + (f\"｜{time_close_label(tc_h)}\" if tc_en else \"\")\n            )\n            return redirect(\"/key_monitor\")",
    ),
    (
        "        if mt in KEY_MONITOR_AUTO_TYPES:\n            extra = f\"｜方案:{sl_tp_mode_label(sl_tp_mode)}｜移动保本:{'开' if be_flag else '关'}\"",
        "        if mt in KEY_MONITOR_AUTO_TYPES:\n            extra = f\"｜方案:{sl_tp_mode_label(sl_tp_mode)}｜移动保本:{'开' if be_flag else '关'}\"\n            if tc_en:\n                extra += f\"｜{time_close_label(tc_h)}\"",
    ),
]

MARKET_OPEN_OLD = """    breakeven_price = round_price_to_exchange(exchange_symbol, breakeven_raw)
    be_enabled = 1 if int(breakeven_enabled or 0) != 0 else 0

    conn.execute(
        "INSERT INTO order_monitors "
        "(symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, "
        "margin_capital, leverage, trade_style, risk_percent, risk_amount, "
        "breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, "
        "notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type, key_signal_type) "
        "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
        (
            symbol,
            exchange_symbol,
            direction,
            trigger_price,
            stop_loss,
            stop_loss,
            take_profit,
            margin_capital,
            leverage,
            trade_style,
            risk_percent,
            risk_amount_final,
            breakeven_rr_trigger,
            breakeven_offset_pct,
            breakeven_step_r,
            0,
            breakeven_price,
            be_enabled,
            notional_value,
            position_ratio,
            base_amount,
            amount,
            open_order_id,
            opened_at_bj,
            opened_at_ms,
            trading_day,
            ORDER_MONITOR_TYPE_KEY_AUTO,
            stored_key_signal_type(key_signal_type),
        ),
    )"""

MARKET_OPEN_NEW = """    breakeven_price = round_price_to_exchange(exchange_symbol, breakeven_raw)
    be_enabled = 1 if int(breakeven_enabled or 0) != 0 else 0
    tc_en, tc_h, tc_at = time_close_insert_values(
        time_close_enabled, time_close_hours, opened_at_ms
    )

    conn.execute(
        "INSERT INTO order_monitors "
        "(symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, "
        "margin_capital, leverage, trade_style, risk_percent, risk_amount, "
        "breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, "
        "notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type, key_signal_type, "
        "time_close_enabled, time_close_hours, time_close_at_ms) "
        "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
        (
            symbol,
            exchange_symbol,
            direction,
            trigger_price,
            stop_loss,
            stop_loss,
            take_profit,
            margin_capital,
            leverage,
            trade_style,
            risk_percent,
            risk_amount_final,
            breakeven_rr_trigger,
            breakeven_offset_pct,
            breakeven_step_r,
            0,
            breakeven_price,
            be_enabled,
            notional_value,
            position_ratio,
            base_amount,
            amount,
            open_order_id,
            opened_at_bj,
            opened_at_ms,
            trading_day,
            ORDER_MONITOR_TYPE_KEY_AUTO,
            stored_key_signal_type(key_signal_type),
            tc_en,
            tc_h,
            tc_at,
        ),
    )"""

FIB_INSERT_OLD = """    opened_at_bj = app_now_str()
    opened_at_ms = _to_ms_with_fallback(None, opened_at_bj)
    conn.execute(
        "INSERT INTO order_monitors "
        "(symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, "
        "margin_capital, leverage, trade_style, risk_percent, risk_amount, "
        "breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, "
        "notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type, key_signal_type) "
        "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
        (
            symbol,
            exchange_symbol,
            direction,
            trigger_price,
            stop_loss,
            stop_loss,
            take_profit,
            margin_capital,
            leverage,
            trade_style,
            risk_percent,
            risk_amount_final,
            breakeven_rr_trigger,
            breakeven_offset_pct,
            breakeven_step_r,
            0,
            breakeven_price,
            1 if breakeven_enabled_from_row(row, 0) else 0,
            notional_value,
            position_ratio,
            base_amount,
            amount,
            exchange_order_id or "",
            opened_at_bj,
            opened_at_ms,
            trading_day,
            ORDER_MONITOR_TYPE_KEY_AUTO,
            stored_key_signal_type(typ),
        ),
    )"""

FIB_INSERT_NEW = """    opened_at_bj = app_now_str()
    opened_at_ms = _to_ms_with_fallback(None, opened_at_bj)
    tc_en, tc_h, _ = time_close_settings_from_row(row)
    tc_en, tc_h, tc_at = time_close_insert_values(tc_en, tc_h, opened_at_ms)
    conn.execute(
        "INSERT INTO order_monitors "
        "(symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, "
        "margin_capital, leverage, trade_style, risk_percent, risk_amount, "
        "breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, "
        "notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type, key_signal_type, "
        "time_close_enabled, time_close_hours, time_close_at_ms) "
        "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
        (
            symbol,
            exchange_symbol,
            direction,
            trigger_price,
            stop_loss,
            stop_loss,
            take_profit,
            margin_capital,
            leverage,
            trade_style,
            risk_percent,
            risk_amount_final,
            breakeven_rr_trigger,
            breakeven_offset_pct,
            breakeven_step_r,
            0,
            breakeven_price,
            1 if breakeven_enabled_from_row(row, 0) else 0,
            notional_value,
            position_ratio,
            base_amount,
            amount,
            exchange_order_id or "",
            opened_at_bj,
            opened_at_ms,
            trading_day,
            ORDER_MONITOR_TYPE_KEY_AUTO,
            stored_key_signal_type(typ),
            tc_en,
            tc_h,
            tc_at,
        ),
    )"""

KEY_FB_OLD = """    be_flag = 1 if int(breakeven_enabled or 0) != 0 else 0
    conn.execute(
        "INSERT INTO key_monitors "
        "(symbol, monitor_type, direction, upper, lower, "
        "fib_limit_order_id, fib_entry_price, fib_stop_loss, fib_take_profit, "
        "fib_order_amount, fib_margin_capital, fib_leverage, breakeven_enabled) "
        "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",
        (
            symbol, FALSE_BREAKOUT_MONITOR_TYPE, direction_sel, upper_px, lower_px,
            oid, entry, sl, tp, float(amount), margin_capital, leverage, be_flag,
        ),
    )"""

KEY_FB_NEW = """    be_flag = 1 if int(breakeven_enabled or 0) != 0 else 0
    tc_en, tc_h, _ = time_close_insert_values(time_close_enabled, time_close_hours, None)
    conn.execute(
        "INSERT INTO key_monitors "
        "(symbol, monitor_type, direction, upper, lower, "
        "fib_limit_order_id, fib_entry_price, fib_stop_loss, fib_take_profit, "
        "fib_order_amount, fib_margin_capital, fib_leverage, breakeven_enabled, time_close_enabled, time_close_hours) "
        "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
        (
            symbol, FALSE_BREAKOUT_MONITOR_TYPE, direction_sel, upper_px, lower_px,
            oid, entry, sl, tp, float(amount), margin_capital, leverage, be_flag, tc_en, tc_h,
        ),
    )"""

KEY_FIB_OLD = """    be_flag = 1 if int(breakeven_enabled or 0) != 0 else 0
    conn.execute(
        "INSERT INTO key_monitors "
        "(symbol, monitor_type, direction, upper, lower, "
        "fib_limit_order_id, fib_entry_price, fib_stop_loss, fib_take_profit, "
        "fib_order_amount, fib_margin_capital, fib_leverage, breakeven_enabled) "
        "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",
        (
            symbol, mt, direction_sel, upper_px, lower_px,
            oid, entry, sl, tp, float(amount), margin_capital, leverage, be_flag,
        ),
    )"""

KEY_FIB_NEW = """    be_flag = 1 if int(breakeven_enabled or 0) != 0 else 0
    tc_en, tc_h, _ = time_close_insert_values(time_close_enabled, time_close_hours, None)
    conn.execute(
        "INSERT INTO key_monitors "
        "(symbol, monitor_type, direction, upper, lower, "
        "fib_limit_order_id, fib_entry_price, fib_stop_loss, fib_take_profit, "
        "fib_order_amount, fib_margin_capital, fib_leverage, breakeven_enabled, time_close_enabled, time_close_hours) "
        "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
        (
            symbol, mt, direction_sel, upper_px, lower_px,
            oid, entry, sl, tp, float(amount), margin_capital, leverage, be_flag, tc_en, tc_h,
        ),
    )"""

ADD_KEY_RS_OLD = """            conn.execute(
                "INSERT INTO key_monitors "
                "(symbol,monitor_type,direction,upper,lower,sl_tp_mode,manual_take_profit,breakeven_enabled,"
                "max_notify,notify_interval_min) "
                "VALUES (?,?,?,?,?,?,?,?,?,?)",
                (
                    symbol,
                    mt,
                    direction_sel,
                    upper_px,
                    lower_px,
                    sl_tp_mode,
                    manual_tp,
                    be_flag,
                    KEY_ALERT_MAX_TIMES,
                    KEY_ALERT_INTERVAL_MINUTES,
                ),
            )
        else:
            conn.execute(
                "INSERT INTO key_monitors "
                "(symbol,monitor_type,direction,upper,lower,sl_tp_mode,manual_take_profit,breakeven_enabled) "
                "VALUES (?,?,?,?,?,?,?,?)",
                (symbol, mt, direction_sel, upper_px, lower_px, sl_tp_mode, manual_tp, be_flag),
            )"""

ADD_KEY_RS_NEW = """            conn.execute(
                "INSERT INTO key_monitors "
                "(symbol,monitor_type,direction,upper,lower,sl_tp_mode,manual_take_profit,breakeven_enabled,"
                "max_notify,notify_interval_min,time_close_enabled,time_close_hours) "
                "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
                (
                    symbol,
                    mt,
                    direction_sel,
                    upper_px,
                    lower_px,
                    sl_tp_mode,
                    manual_tp,
                    be_flag,
                    KEY_ALERT_MAX_TIMES,
                    KEY_ALERT_INTERVAL_MINUTES,
                    tc_en,
                    tc_h,
                ),
            )
        else:
            conn.execute(
                "INSERT INTO key_monitors "
                "(symbol,monitor_type,direction,upper,lower,sl_tp_mode,manual_take_profit,breakeven_enabled,"
                "time_close_enabled,time_close_hours) "
                "VALUES (?,?,?,?,?,?,?,?,?,?)",
                (symbol, mt, direction_sel, upper_px, lower_px, sl_tp_mode, manual_tp, be_flag, tc_en, tc_h),
            )"""

ADD_ORDER_OLD = """    breakeven_enabled = 1 if (d.get("breakeven_enabled") or "").strip() in ("1", "true", "on", "yes") else 0
    conn.execute(
        "INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
        (
            symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
            margin_capital, leverage, trade_style, risk_percent_db, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
            breakeven_enabled,
            notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day,
            ORDER_MONITOR_TYPE_MANUAL,
        )
    )"""

ADD_ORDER_NEW = """    breakeven_enabled = 1 if (d.get("breakeven_enabled") or "").strip() in ("1", "true", "on", "yes") else 0
    tc_en = parse_time_close_enabled_form(d.get("time_close_enabled"))
    tc_h = parse_time_close_hours_form(d.get("time_close_hours")) if tc_en else None
    if tc_en and not tc_h:
        tc_en = 0
    tc_en, tc_h, tc_at = time_close_insert_values(tc_en, tc_h, opened_at_ms)
    conn.execute(
        "INSERT INTO order_monitors (symbol, exchange_symbol, direction, trigger_price, stop_loss, initial_stop_loss, take_profit, margin_capital, leverage, trade_style, risk_percent, risk_amount, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, breakeven_armed, breakeven_price, breakeven_enabled, notional_value, position_ratio, base_amount, order_amount, exchange_order_id, opened_at, opened_at_ms, session_date, monitor_type, time_close_enabled, time_close_hours, time_close_at_ms) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
        (
            symbol, exchange_symbol, direction, trigger_price, stop_loss, stop_loss, take_profit,
            margin_capital, leverage, trade_style, risk_percent_db, risk_amount_final, breakeven_rr_trigger, breakeven_offset_pct, breakeven_step_r, 0, breakeven_price,
            breakeven_enabled,
            notional_value, position_ratio, base_amount, amount, open_order_id, opened_at_bj, opened_at_ms, trading_day,
            ORDER_MONITOR_TYPE_MANUAL,
            tc_en, tc_h, tc_at,
        )
    )"""

BIG_BLOCKS = [
    (MARKET_OPEN_OLD, MARKET_OPEN_NEW),
    (FIB_INSERT_OLD, FIB_INSERT_NEW),
    (KEY_FB_OLD, KEY_FB_NEW),
    (KEY_FIB_OLD, KEY_FIB_NEW),
    (ADD_KEY_RS_OLD, ADD_KEY_RS_NEW),
    (ADD_ORDER_OLD, ADD_ORDER_NEW),
]


def patch(path: Path) -> None:
    text = path.read_text(encoding="utf-8")
    for old, new in REPLACEMENTS + BIG_BLOCKS:
        if old in text:
            text = text.replace(old, new, 1)
    path.write_text(text, encoding="utf-8")
    print("done", path.name)


def main() -> None:
    for f in FILES:
        patch(f)


if __name__ == "__main__":
    main()
