# -*- coding: utf-8 -*-
"""Patch index.html layout for key_monitor / trade split."""
from pathlib import Path
import re

TAG = "div"

PATHS = [
    Path(__file__).resolve().parent.parent / "templates" / "index.html",
    Path(r"c:\Users\dekun\Desktop\crypto_monitor\crypto_monitor_gate\templates\index.html"),
]

KEY_START = "        {% if page == 'key_monitor' %}"
KEY_START_ALT = "        {% if page == 'trade' %}"
RECORDS_START = "        {% if page == 'records' %}"


def build_section(order_loop: str) -> str:
    t = TAG
    return f"""        {{% if page == 'key_monitor' %}}
        <{t} class="dual-panel-grid" style="grid-column:1/-1">
        <{t} class="card">
            <{t} style="display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap;margin-bottom:8px">
                <h2 style="margin-bottom:0">关键位监控</h2>
                {{% if focus_key_id %}}
                <a href="/key_focus?key_id={{{{ focus_key_id }}}}" class="btn-del" style="text-decoration:none;background:#1f3a5a;color:#8fc8ff">放大查看K线(默认200根)</a>
                {{% else %}}
                <a href="/key_focus" class="btn-del" style="text-decoration:none;background:#1f3a5a;color:#8fc8ff">输入币种查看K线</a>
                {{% endif %}}
            </{t}>
            <form id="key-form" action="/add_key" method="post" class="form-row">
                <input name="symbol" placeholder="BTC 或 BTC/USDT" required>
                <select name="type" required>
                    <option value="箱体突破">箱体突破</option>
                    <option value="收敛突破">收敛突破</option>
                    <option value="关键阻力位">关键阻力位</option>
                    <option value="关键支撑位">关键支撑位</option>
                </select>
                <select name="direction" required>
                    <option value="">方向</option><option value="long">做多</option><option value="short">做空</option>
                </select>
                <input name="upper" step="0.0001" placeholder="上沿/阻力" required>
                <input name="lower" step="0.0001" placeholder="下沿/支撑" required>
                <button type="submit">添加</button>
            </form>
            <{t} class="rule-tip">{{{{ key_gate_rule_text }}}}</{t}>
            <{t} class="panel-scroll pos-list">
                {{% for k in key %}}
                <{t} class="pos-card" id="key-row-{{{{ k.id }}}}">
                    <{t} class="pos-card-head">
                        <{t} class="pos-card-symbol">
                            <strong>{{{{ k.symbol }}}}</strong>
                            <span class="pos-side-badge {{{{ 'pos-side-long' if k.direction == 'long' else 'pos-side-short' }}}}">{{{{ '做多' if k.direction == 'long' else '做空' }}}}</span>
                            <span class="badge direction" style="margin-left:4px">{{{{ k.monitor_type }}}}</span>
                        </{t}>
                        <button type="button" class="pos-close-btn" style="border:none;cursor:pointer" onclick="deleteKeyMonitor({{{{ k.id }}}})">删</button>
                    </{t}>
                    <{t} class="pos-meta">
                        <span class="pos-meta-item">上沿: {{{{ k.upper }}}}</span>
                        <span class="pos-meta-item">下沿: {{{{ k.lower }}}}</span>
                        <span class="pos-meta-item">已提醒: {{{{ k.notification_count or 0 }}}}/{{{{ k.max_notify or 3 }}}}</span>
                    </{t}>
                    <{t} class="pos-grid">
                        <{t} class="pos-cell"><span class="pos-label">现价</span><span class="pos-value" id="key-price-{{{{ k.id }}}}">-</span></{t}>
                        <{t} class="pos-cell"><span class="pos-label">距上沿</span><span class="pos-value" id="key-up-diff-{{{{ k.id }}}}">-</span></{t}>
                        <{t} class="pos-cell"><span class="pos-label">距下沿</span><span class="pos-value" id="key-low-diff-{{{{ k.id }}}}">-</span></{t}>
                        <{t} class="pos-cell"><span class="pos-label">门控</span><span class="pos-value" id="key-gate-{{{{ k.id }}}}" style="color:#9aa">-</span></{t}>
                    </{t}>
                    <{t} class="pos-meta" style="margin-top:8px"><span class="pos-meta-item" id="key-gate-metrics-{{{{ k.id }}}}" style="color:#8fc8ff"></span></{t}>
                </{t}>
                {{% else %}}
                <{t} class="pos-empty">暂无监控中的关键位</{t}>
                {{% endfor %}}
            </{t}>
        </{t}>
        <{t} class="card">
            <h2 style="margin-bottom:8px">关键位历史</h2>
            <{t} class="sub" style="font-size:.72rem;color:#8892b0;margin-bottom:8px">失效或已结案的关键位</{t}>
            <{t} class="panel-scroll pos-list">
                {{% for h in key_history %}}
                <{t} class="pos-card">
                    <{t} class="pos-card-head">
                        <{t} class="pos-card-symbol">
                            <strong>{{{{ h.symbol }}}}</strong>
                            <span class="pos-side-badge {{{{ 'pos-side-long' if h.direction == 'long' else 'pos-side-short' }}}}">{{{{ '做多' if h.direction == 'long' else '做空' }}}}</span>
                        </{t}>
                        <button type="button" class="table-del" onclick="deleteKeyHistory({{{{ h.id }}}})">删除</button>
                    </{t}>
                    <{t} class="pos-meta">
                        <span class="pos-meta-item">{{{{ h.monitor_type }}}}</span>
                        <span class="pos-meta-item">{{{{ h.close_reason }}}}</span>
                        <span class="pos-meta-item">{{{{ (h.closed_at or '-')[:16] }}}}</span>
                    </{t}>
                    <{t} class="pos-meta">
                        <span class="pos-meta-item">上: {{{{ h.upper }}}} 下: {{{{ h.lower }}}}</span>
                        <span class="pos-meta-item">提醒: {{{{ h.notification_count }}}}</span>
                    </{t}>
                    {{% if h.last_alert_message %}}<{t} style="font-size:.75rem;color:#aab;margin-top:6px;white-space:pre-wrap">{{{{ h.last_alert_message[:180] }}}}{{% if h.last_alert_message|length > 180 %}}…{{% endif %}}</{t}>{{% endif %}}
                </{t}>
                {{% else %}}
                <{t} class="pos-empty">暂无历史</{t}>
                {{% endfor %}}
            </{t}>
        </{t}>
        </{t}>
        {{% elif page == 'trade' %}}
        <{t} class="dual-panel-grid" style="grid-column:1/-1">
        <{t} class="card">
            <{t} style="display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap;margin-bottom:8px">
                <h2 style="margin-bottom:0">实盘下单监控</h2>
                {{% if focus_order_id %}}
                <a href="/order_focus?order_id={{{{ focus_order_id }}}}" class="btn-del" style="text-decoration:none;background:#1f3a5a;color:#8fc8ff">放大查看K线(100根)</a>
                {{% else %}}
                <span class="btn-del" style="background:#2f2f44;color:#9aa;cursor:not-allowed">暂无持仓可放大</span>
                {{% endif %}}
            </{t}>
            <{t} class="rule-tip" id="order-rule-tip">
                规则:最多 {{{{ max_active_positions }}}} 仓;BTC {{{{ btc_leverage }}}}x / 山寨 {{{{ alt_leverage }}}}x;
                {{% if can_trade %}}可开仓{{% else %}}不可开仓(持仓已满或未到北京时间 {{{{ reset_hour }}}}:00){{% endif %}};
                人工开仓盈亏比不得低于 {{{{ manual_min_planned_rr }}}}:1
            </{t}>
            <{t} class="rule-tip">
                以损定仓:风险 {{{{ risk_percent }}}}% ｜移动保本:下单可勾选关闭;开启时 {{{{ breakeven_rr_trigger }}}}R 触发(每 1R 阶梯上移),偏移 {{{{ breakeven_offset_pct }}}}%
            </{t}>
            <{t} class="rule-tip">
                划转:自动划转 {{{{ '开启' if auto_transfer_enabled else '关闭' }}}}(每天<strong>北京时间 {{{{ auto_transfer_bj_hour }}}}:00</strong>起该整点小时内尝试;账簿按 <strong>UTC 自然日</strong>去重;界面时间为北京;将 {{{{ auto_transfer_to }}}} 补足到 {{{{ auto_transfer_amount }}}}U,来自 {{{{ auto_transfer_from }}}})
            </{t}>
            <form action="/manual_transfer" method="post" class="form-row">
                <input name="amount" type="number" min="0.01" step="0.01" placeholder="手动划转金额U" required>
                <select name="from_account">
                    <option value="funding" {{% if auto_transfer_from == 'funding' %}}selected{{% endif %}}>from: funding</option>
                    <option value="swap" {{% if auto_transfer_from == 'swap' %}}selected{{% endif %}}>from: swap</option>
                    <option value="spot" {{% if auto_transfer_from == 'spot' %}}selected{{% endif %}}>from: spot</option>
                </select>
                <select name="to_account">
                    <option value="swap" {{% if auto_transfer_to == 'swap' %}}selected{{% endif %}}>to: swap</option>
                    <option value="funding" {{% if auto_transfer_to == 'funding' %}}selected{{% endif %}}>to: funding</option>
                    <option value="spot" {{% if auto_transfer_to == 'spot' %}}selected{{% endif %}}>to: spot</option>
                </select>
                <button type="submit">手动划转</button>
            </form>
            <form id="add-order-form" action="/add_order" method="post" class="form-row">
                <input id="order-symbol" name="symbol" placeholder="BTC 或 BTC/USDT" required>
                <select id="order-direction" name="direction" required>
                    <option value="">方向</option><option value="long">做多</option><option value="short">做空</option>
                </select>
                <select id="sltp-mode" name="sltp_mode">
                    <option value="price">止盈止损:价格模式</option>
                    <option value="pct">止盈止损:百分比模式</option>
                </select>
                <select name="trade_style" required>
                    <option value="trend">趋势单</option>
                    <option value="swing">波段单</option>
                </select>
                <input id="order-leverage" name="leverage" type="number" min="1" step="1" placeholder="杠杆(可选)">
                <label style="display:flex;align-items:center;gap:4px;font-size:.82rem;color:#cfd3ef">
                    <input type="checkbox" name="breakeven_enabled" value="1" checked> 启用移动保本(关闭则仅保留初始止损与交易所挂单)
                </label>
                <label style="display:flex;align-items:center;gap:4px;font-size:.82rem;color:#cfd3ef">
                    <input type="checkbox" name="order_chart" value="true"> 开仓后生成多周期K线图(各周期100根,含开平仓标记)
                </label>
                <span style="display:flex;align-items:center;padding:0 10px;font-size:.8rem;color:#8fc8ff">成交价自动取交易所实时+成交回报</span>
                <input id="order-sl" name="sl" step="any" placeholder="止损价格" required>
                <input id="order-tp" name="tgt" step="any" placeholder="止盈价格" required>
                <input id="order-sl-pct" name="sl_pct" type="number" min="0.01" step="0.01" placeholder="止损%" style="display:none">
                <input id="order-tp-pct" name="tp_pct" type="number" min="0.01" step="0.01" placeholder="止盈%" style="display:none">
                <button type="submit">开仓(以损定仓)</button>
            </form>
        </{t}>
        <{t} class="card">
            <h2 style="margin-bottom:8px">实时持仓</h2>
            <{t} class="panel-scroll pos-list">
                {order_loop}
            </{t}>
        </{t}>
        </{t}>
        {{% endif %}}

"""


def patch_nav(text: str) -> str:
    old = '<a href="/trade" class="{% if page == \'trade\' %}active{% endif %}">交易执行</a>'
    new = (
        '<a href="/key_monitor" class="{% if page == \'key_monitor\' %}active{% endif %}">关键位监控</a>\n'
        '        <a href="/trade" class="{% if page == \'trade\' %}active{% endif %}">实盘下单</a>'
    )
    if "关键位监控" not in text:
        text = text.replace(old, new)
    return text


def patch_js(text: str) -> str:
  # page id on body
    if 'id="page-trade"' not in text:
        text = text.replace("<body>", '<body data-page="{{ page }}">', 1)
    if "MANUAL_MIN_PLANNED_RR" not in text:
        insert = """
const MANUAL_MIN_PLANNED_RR = {{ manual_min_planned_rr }};
function calcClientRr(direction, entry, sl, tp){
    const e = Number(entry), s = Number(sl), t = Number(tp);
    if(!Number.isFinite(e) || !Number.isFinite(s) || !Number.isFinite(t)) return null;
    if(direction === 'short'){
        if(s <= e || t >= e) return null;
        return (e - t) / (s - e);
    }
    if(s >= e || t <= e) return null;
    return (t - e) / (e - s);
}
"""
        text = text.replace("let latestAvailableUsdt = null;", insert + "\nlet latestAvailableUsdt = null;")
    if "add-order-form" not in text or "calcClientRr" in text and "addOrderForm" not in text:
        hook = """
const addOrderForm = document.getElementById("add-order-form");
if(addOrderForm){
    addOrderForm.addEventListener("submit", function(ev){
        const direction = (document.getElementById("order-direction")||{}).value || "long";
        const mode = (document.getElementById("sltp-mode")||{}).value || "price";
        let sl, tp, entry;
        if(mode === "pct"){
            alert("百分比模式请确认盈亏比后再提交;建议使用价格模式以便校验.");
            return;
        }
        sl = Number((document.getElementById("order-sl")||{}).value);
        tp = Number((document.getElementById("order-tp")||{}).value);
        entry = sl;
        fetch(`/api/order_defaults?symbol=${encodeURIComponent((document.getElementById("order-symbol")||{}).value||"")}&direction=${encodeURIComponent(direction)}`)
            .then(r=>r.json())
            .then(data=>{
                const px = data.last_price || data.price;
                if(px) entry = Number(px);
                const rr = calcClientRr(direction, entry, sl, tp);
                if(rr === null || rr < MANUAL_MIN_PLANNED_RR){
                    alert(`计划盈亏比 ${rr === null ? '无效' : rr.toFixed(2)}:1 低于最低要求 ${MANUAL_MIN_PLANNED_RR}:1,已阻止人工下单.`);
                    return;
                }
                addOrderForm.submit();
            })
            .catch(()=>{ ev.preventDefault(); alert("无法校验盈亏比,请稍后重试"); });
        ev.preventDefault();
    });
}
"""
        text = text.replace("refreshOrderDefaults();", hook + "\nrefreshOrderDefaults();")
    if "max_active_positions" not in text and "order-rule-tip" in text:
        text = text.replace(
            "规则:单仓;",
            "规则:最多 {{ max_active_positions }} 仓;",
        )
    # account snapshot tip
    old_tip = '`规则:单仓;BTC {{ btc_leverage }}x'
    if old_tip in text:
        text = text.replace(
            old_tip,
            "`规则:最多 ${data.max_active_positions || {{ max_active_positions }}} 仓;BTC {{ btc_leverage }}x",
        )
    text = text.replace(
        'const canTradeText = data.can_trade ? "可开仓" : "不可开仓(有持仓或未到北京时间 {{ reset_hour }}:00)";',
        'const canTradeText = data.can_trade ? "可开仓" : `不可开仓(持仓 ${data.active_count||0}/${data.max_active_positions||{{ max_active_positions }}} 或未到北京时间 {{ reset_hour }}:00)`;',
    )
    text = text.replace(
        "if(!data.in_top30){",
        "const rankMax = data.rank_max || 30;\n                if(!data.in_top30){",
    )
    text = text.replace(
        "不在前30,已拦截",
        "不在前${rankMax},已拦截",
    )
    # conditional price refresh
    if "data-page" in text and "refreshPriceSnapshotConditional" not in text:
        text = text.replace(
            "setInterval(refreshPriceSnapshot, {{ price_refresh_seconds * 1000 }});",
            """function refreshPriceSnapshotConditional(){
    const page = document.body.getAttribute("data-page") || "";
    fetch("/api/price_snapshot").then(r=>r.json()).then(data=>{
        const updatedEl = document.getElementById("price-last-updated");
        if(data.updated_at && updatedEl) updatedEl.innerText = data.updated_at;
        if(page === "key_monitor"){
            (data.key_prices || []).forEach(k=>{
                const pEl = document.getElementById(`key-price-${k.id}`);
                if(pEl){ pEl.innerText = k.price_display || (Number.isFinite(Number(k.price)) ? Number(k.price).toFixed(6) : "-"); paintPriceTrend(pEl, `k-${k.id}`, Number(k.price)); }
                const upEl = document.getElementById(`key-up-diff-${k.id}`);
                if(upEl) upEl.innerText = `${formatSigned(k.upper_diff, 4)} (${formatSigned(k.upper_pct, 2)}%)`;
                const lowEl = document.getElementById(`key-low-diff-${k.id}`);
                if(lowEl) lowEl.innerText = `${formatSigned(k.lower_diff, 4)} (${formatSigned(k.lower_pct, 2)}%)`;
                const gateEl = document.getElementById(`key-gate-${k.id}`);
                if(gateEl){ gateEl.innerText = k.gate_summary || "-"; gateEl.style.color = k.gate_ok ? "#4cd97f" : "#ff8f8f"; }
                const gateMetricEl = document.getElementById(`key-gate-metrics-${k.id}`);
                if(gateMetricEl) gateMetricEl.innerText = k.gate_metrics || "";
            });
        }
        if(page === "trade"){
            (data.order_prices || []).forEach(o=>{
                const pEl = document.getElementById(`order-price-${o.id}`);
                if(pEl){
                    const hasMark = (()=>{ const x = o.exchange_mark_price; if(x===null||x===undefined||x==="")return false; const n=Number(x); return !Number.isNaN(n); })();
                    let disp = "";
                    if(hasMark && o.exchange_mark_price_display) disp = o.exchange_mark_price_display;
                    else if(o.price_display) disp = o.price_display;
                    else { const px = hasMark ? Number(o.exchange_mark_price) : Number(o.price); disp = Number.isFinite(px) ? px.toFixed(6) : "-"; }
                    pEl.innerText = disp;
                    const pxNum = hasMark ? Number(o.exchange_mark_price) : Number(o.price);
                    paintPriceTrend(pEl, `o-${o.id}`, Number.isFinite(pxNum) ? pxNum : px);
                }
                const exM = document.getElementById(`order-ex-margin-${o.id}`);
                if(exM){
                    const mv = o.exchange_initial_margin;
                    const mn = (mv === null || mv === undefined || mv === "") ? NaN : Number(mv);
                    if(!Number.isNaN(mn)) exM.innerText = `${mn.toFixed(2)}U`;
                    else { const prc = (typeof data.positions_raw_count === "number") ? data.positions_raw_count : null; exM.innerText = (prc === 0) ? "无仓数据" : "-"; }
                }
                const pnlEl = document.getElementById(`order-pnl-${o.id}`);
                if(pnlEl){
                    pnlEl.innerText = `${formatSigned(o.float_pnl, 2)}U (${formatSigned(o.float_pct, 2)}%)`;
                    pnlEl.classList.remove("price-up","price-down","price-flat");
                    if(Number(o.float_pnl) > 0) pnlEl.classList.add("price-up");
                    else if(Number(o.float_pnl) < 0) pnlEl.classList.add("price-down");
                    else pnlEl.classList.add("price-flat");
                }
                const rrEl = document.getElementById(`order-rr-${o.id}`);
                if(rrEl) rrEl.innerText = formatRrRatio(o.rr_ratio);
            });
        }
    }).catch(()=>{});
}
setInterval(refreshPriceSnapshotConditional, {{ price_refresh_seconds * 1000 }});""",
        )
    return text


def main():
    for path in PATHS:
        if not path.exists():
            print("skip", path)
            continue
        text = path.read_text(encoding="utf-8")
        start = text.find(KEY_START)
        if start < 0:
            start = text.find(KEY_START_ALT)
        end = text.find(RECORDS_START)
        if start < 0 or end < 0:
            raise SystemExit(f"markers not found: {path}")
        old = text[start:end]
        m = re.search(r"(\{% for o in order %\}.*?\{% endfor %\})", old, re.S)
        if not m:
            raise SystemExit(f"order loop not found: {path}")
        order_loop = m.group(1)
        section = build_section(order_loop)
        section = section.replace("{{%", "{%").replace("%}}", "%}").replace("{{{{", "{{").replace("}}}}", "}}")
        out = text[:start] + section + "\n\n" + text[end:]
        out = patch_nav(out)
        out = patch_js(out)
        path.write_text(out, encoding="utf-8")
        print("patched", path)


if __name__ == "__main__":
    main()
