from __future__ import annotations

import argparse
import json
import os
import time
from typing import Any


def _runtime_dir() -> str:
    d = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "runtime"))
    os.makedirs(d, exist_ok=True)
    return d


def _copy_params_path() -> str:
    return os.path.join(_runtime_dir(), "copy_params.json")


def _parse_opt_off_or_float(raw: str | None) -> float | None | str:
    """
    return:
      - "__OMIT__": not provided (raw is None)
      - None: explicit off
      - float: value
    """
    if raw is None:
        return "__OMIT__"
    s = str(raw).strip().lower()
    if s in ("off", "none", "null"):
        return None
    return float(raw)


def _parse_opt_off_or_coins(raw: str | None) -> list[str] | None | str:
    """
    coins:
      - "__OMIT__": not provided
      - None: explicit off / empty
      - list[str]: allowlist
    """
    if raw is None:
        return "__OMIT__"
    s = str(raw).strip()
    if not s or s.lower() in ("off", "none", "null", "all"):
        return None
    parts = [p.strip() for p in s.split(",") if p.strip()]
    return parts


def build_parser() -> argparse.ArgumentParser:
    p = argparse.ArgumentParser(description="1m-trade copy runtime params updater (incremental, via state file)")
    p.add_argument("--target", required=True, help="openclaw message target (must match running copy_main.py)")
    p.add_argument("--scale", type=float, default=None, help="update scale (float); omit to keep current")
    p.add_argument("--max-notional-usd", type=str, default=None, help="float or off (cancel maxNotionalUsd)")
    p.add_argument("--max-leverage", type=str, default=None, help="float or off (cancel maxLeverage)")
    p.add_argument("--take-profit-pct", type=str, default=None, help="float or off (cancel TP cooldown)")
    p.add_argument("--stop-loss-pct", type=str, default=None, help="float or off (cancel SL cooldown)")
    p.add_argument("--coins", type=str, default=None, help="comma-separated allowlist (e.g. BTC,HYPE) or off")
    return p


def run(args: argparse.Namespace) -> int:

    target = str(args.target).strip()
    if not target:
        raise SystemExit("--target is required")

    params_path = _copy_params_path()

    payload: dict[str, Any] = {}
    changed: list[str] = []

    if args.scale is not None:
        payload["scale"] = float(args.scale)
        changed.append("scale")

    v = _parse_opt_off_or_float(args.max_notional_usd)
    if v != "__OMIT__":
        payload["maxNotionalUsd"] = v
        changed.append("maxNotionalUsd")

    v = _parse_opt_off_or_float(args.max_leverage)
    if v != "__OMIT__":
        payload["maxLeverage"] = v
        changed.append("maxLeverage")

    v = _parse_opt_off_or_float(args.take_profit_pct)
    if v != "__OMIT__":
        payload["takeProfitPct"] = v
        changed.append("takeProfitPct")

    v = _parse_opt_off_or_float(args.stop_loss_pct)
    if v != "__OMIT__":
        payload["stopLossPct"] = v
        changed.append("stopLossPct")

    v = _parse_opt_off_or_coins(args.coins)
    if v != "__OMIT__":
        payload["coins"] = v
        changed.append("coins")

    if not changed:
        raise SystemExit("no params provided; pass at least one of --scale/--max-notional-usd/--max-leverage/--take-profit-pct/--stop-loss-pct/--coins")

    # seq: prefer increasing, to support watcher "seq > last_seq"
    seq = int(time.time() * 1000)
    if os.path.exists(params_path):
        try:
            with open(params_path, "r", encoding="utf-8") as f:
                prev = json.load(f) if f.readable() else {}
            prev_seq = prev.get("seq")
            if isinstance(prev_seq, (int, float, str)):
                prev_seq_i = int(prev_seq)
                if prev_seq_i >= seq:
                    seq = prev_seq_i + 1
        except Exception:
            pass

    payload["seq"] = seq

    tmp = f"{params_path}.tmp"
    with open(tmp, "w", encoding="utf-8") as f:
        json.dump(payload, f, ensure_ascii=False, indent=2)
    os.replace(tmp, params_path)

    print(f"[copy-update] target={target} seq={seq} changed={changed}")
    return 0


def main() -> int:
    args = build_parser().parse_args()
    return run(args)


if __name__ == "__main__":
    raise SystemExit(main())

