"""
MT5 Client - Bridge File Mode (works on macOS via Wine)
Writes command files and reads responses via MT5TradeServer EA.
No AppleScript, no GUI automation needed.

废弃通知: 本模块使用旧版单文件协议 (mt5_cmd.json / mt5_rsp.json)。
新代码请使用 src/mt5_execution.py 的 per-request 文件协议 (signal_id.request.json)。
此模块保留以兼容旧版 EA（GoldAutoTradeBridgeEA v1.x）。
"""

import json
import os
import time
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict, Optional

from src.data_layer import mt5_dir

MT5_FILES = mt5_dir()

CMD_FILE = MT5_FILES / "mt5_cmd.json"
RSP_FILE = MT5_FILES / "mt5_rsp.json"
FILLED_MAGIC = MT5_FILES / "FILLED_MAGIC.txt"  # marker file written by EA


def _now() -> str:
    return datetime.now(timezone.utc).isoformat()


def _log(msg: str) -> None:
    print(f"[{_now()[11:19]}] {msg}")


def _send_and_wait(
    cmd: Dict[str, Any],
    timeout: float = 15.0,
    poll_s: float = 0.2,
) -> Optional[Dict]:
    """
    Write command file, wait for response file.
    Returns response dict or None on timeout.
    """
    # Clear old response
    if RSP_FILE.exists():
        try:
            RSP_FILE.unlink()
        except Exception:
            pass

    # Write command
    with CMD_FILE.open("w", encoding="utf-8") as f:
        json.dump(cmd, f, ensure_ascii=False)

    start = time.time()
    while time.time() - start < timeout:
        if RSP_FILE.exists():
            try:
                resp = json.loads(RSP_FILE.read_text(encoding="utf-8"))
                return resp
            except Exception:
                pass
        time.sleep(poll_s)

    return None


class MT5Client:
    """MT5 trading client using bridge file protocol."""

    def __init__(self, timeout: float = 15.0):
        self.timeout = timeout

    def ping(self) -> Dict:
        r = _send_and_wait({"action": "ping", "ts": _now()}, timeout=5)
        if r:
            return {"success": True, "message": r.get("message", "pong")}
        return {"success": False, "message": "MT5 EA not responding"}

    def get_positions(self) -> Dict:
        r = _send_and_wait({"action": "positions"}, timeout=self.timeout)
        return r or {"success": False, "positions": []}

    def get_account(self) -> Dict:
        r = _send_and_wait({"action": "account"}, timeout=self.timeout)
        return r or {"success": False}

    def get_quote(self, symbol: str = "XAUUSD") -> Dict:
        r = _send_and_wait({"action": "quote", "symbol": symbol}, timeout=self.timeout)
        return r or {"success": False}

    def show_status(self) -> tuple:
        acct = self.get_account()
        positions = self.get_positions()
        quote = self.get_quote()
        return acct, positions, quote

    def buy(
        self,
        symbol: str = "XAUUSD",
        volume: float = 0.01,
        sl: float = 0,
        tp: float = 0,
    ) -> Dict:
        cmd = {
            "action": "buy",
            "symbol": symbol,
            "volume": volume,
            "sl": sl,
            "tp": tp,
            "ts": _now(),
        }
        r = _send_and_wait(cmd, timeout=self.timeout)
        if not r:
            return {"success": False, "message": "MT5 EA timeout"}
        return {"success": r.get("success", False), **r}

    def sell(
        self,
        symbol: str = "XAUUSD",
        volume: float = 0.01,
        sl: float = 0,
        tp: float = 0,
    ) -> Dict:
        cmd = {
            "action": "sell",
            "symbol": symbol,
            "volume": volume,
            "sl": sl,
            "tp": tp,
            "ts": _now(),
        }
        r = _send_and_wait(cmd, timeout=self.timeout)
        if not r:
            return {"success": False, "message": "MT5 EA timeout"}
        return {"success": r.get("success", False), **r}

    def close(self, ticket: int = 0) -> Dict:
        cmd = {"action": "close", "ticket": ticket, "ts": _now()}
        r = _send_and_wait(cmd, timeout=self.timeout)
        if not r:
            return {"success": False, "message": "MT5 EA timeout"}
        return {"success": r.get("success", False), **r}

    def close_all(self) -> Dict:
        return self.close(ticket=0)


# ─── CLI ───────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    import sys

    client = MT5Client()
    cmd = sys.argv[1].lower() if len(sys.argv) > 1 else ""

    if not cmd or cmd == "ping":
        r = client.ping()
        _log(f"{'[OK]' if r['success'] else '[FAIL]'} {r.get('message','')}")
    elif cmd == "status":
        acct, positions, quote = client.show_status()
        print("\n" + "=" * 40)
        print(f"  MT5 Status ({_now()[11:19]})")
        print("=" * 40)
        if acct.get("success"):
            print(f"  Balance: ${acct.get('balance', 0):.2f}")
            print(f"  Equity:  ${acct.get('equity', 0):.2f}")
            print(f"  Profit:  ${acct.get('profit', 0):.2f}")
        if quote.get("success"):
            print(f"  XAUUSD:  {quote.get('bid', 'N/A')} / {quote.get('ask', 'N/A')}")
        if positions.get("success"):
            for p in positions.get("positions", []):
                print(f"  #{p['ticket']} {p['symbol']} {p['type']} "
                      f"v={p['volume']} PnL=${p.get('pnl', 0):.2f}")
        else:
            print("  Positions: none")
        print("=" * 40 + "\n")
    elif cmd == "buy":
        vol = float(sys.argv[2]) if len(sys.argv) > 2 else 0.01
        r = client.buy("XAUUSD", vol)
        _log(f"[UP] BUY {'[OK]' if r['success'] else '[FAIL]'} {r.get('message','')}")
    elif cmd == "sell":
        vol = float(sys.argv[2]) if len(sys.argv) > 2 else 0.01
        r = client.sell("XAUUSD", vol)
        _log(f"[DOWN] SELL {'[OK]' if r['success'] else '[FAIL]'} {r.get('message','')}")
    elif cmd == "close":
        r = client.close_all()
        _log(f"[END] CLOSE {'[OK]' if r['success'] else '[FAIL]'} {r.get('message','')}")
    elif cmd == "quote":
        r = client.get_quote("XAUUSD")
        print(json.dumps(r, indent=2, ensure_ascii=False))
    else:
        print(f"Usage: python3 mt5_client.py [ping|status|buy|sell|close|quote]")
