"""One-shot ops script: register the agenteval-patrol cron job on the OpenClaw
gateway via its WS RPC protocol, authenticating through the trusted-proxy
network (x-forwarded-user). Run inside the agenteval container."""

import base64
import json
import os
import socket
import struct
import sys

HOST, PORT = "openclaw-eval", 18789


def recv_exact(s, n):
    buf = b""
    while len(buf) < n:
        chunk = s.recv(n - len(buf))
        if not chunk:
            raise ConnectionError("closed")
        buf += chunk
    return buf


def read_frame(s):
    b1, b2 = recv_exact(s, 2)
    length = b2 & 0x7F
    if length == 126:
        length = struct.unpack(">H", recv_exact(s, 2))[0]
    elif length == 127:
        length = struct.unpack(">Q", recv_exact(s, 8))[0]
    return recv_exact(s, length).decode()


def send_text(s, payload):
    data = payload.encode()
    mask = os.urandom(4)
    header = b"\x81"
    n = len(data)
    if n < 126:
        header += bytes([0x80 | n])
    elif n < 65536:
        header += bytes([0x80 | 126]) + struct.pack(">H", n)
    else:
        header += bytes([0x80 | 127]) + struct.pack(">Q", n)
    masked = bytes(d ^ mask[i % 4] for i, d in enumerate(data))
    s.sendall(header + mask + masked)


def rpc(s, rid, method, params):
    send_text(s, json.dumps({"type": "req", "id": rid, "method": method, "params": params}))
    while True:
        msg = json.loads(read_frame(s))
        if msg.get("type") == "res" and msg.get("id") == rid:
            return msg
        print("note:", json.dumps(msg)[:200])


def main(action):
    s = socket.create_connection((HOST, PORT), timeout=15)
    key = base64.b64encode(os.urandom(16)).decode()
    req = (
        f"GET / HTTP/1.1\r\nHost: {HOST}:{PORT}\r\nUpgrade: websocket\r\n"
        f"Connection: Upgrade\r\nSec-WebSocket-Key: {key}\r\nSec-WebSocket-Version: 13\r\n"
        f"Origin: http://192.168.8.145:8001\r\n"
        f"x-forwarded-user: agenteval\r\n\r\n"
    )
    s.sendall(req.encode())
    resp = b""
    while b"\r\n\r\n" not in resp:
        resp += s.recv(4096)
    status = resp.split(b"\r\n")[0].decode()
    print("UPGRADE:", status)
    if "101" not in status:
        sys.exit(1)

    challenge = json.loads(read_frame(s))
    print("CHALLENGE:", json.dumps(challenge)[:300])

    connect_params = {
        "minProtocol": 4,
        "maxProtocol": 4,
        "client": {"id": "openclaw-control-ui", "version": "0.0.1", "platform": "linux", "mode": "ui"},
        "role": "operator",
        "scopes": ["operator.read", "operator.write", "operator.admin"],
        "caps": [],
        "commands": [],
        "permissions": {},
        "auth": {},
        "locale": "zh-CN",
        "userAgent": "agenteval-ops/0.0.1",
    }
    res = rpc(s, "c1", "connect", connect_params)
    print("CONNECT:", json.dumps(res)[:400])
    if not res.get("ok"):
        sys.exit(2)

    if action == "list":
        res = rpc(s, "c2", "cron.list", {"includeDisabled": True})
        print("CRON.LIST:", json.dumps(res, ensure_ascii=False)[:1200])
    elif action == "add":
        params = {
            "name": "agenteval-patrol",
            "description": "AgentEvalTool 常驻巡检：每小时按 agenteval-patrol skill 闭环巡检探索",
            "enabled": True,
            "agentId": "main",
            "schedule": {"kind": "cron", "expr": "0 * * * *", "tz": "Asia/Shanghai"},
            "sessionTarget": "isolated",
            "wakeMode": "now",
            "payload": {
                "kind": "agentTurn",
                "message": (
                    "使用 agenteval-patrol skill 执行一次完整巡检闭环：调用巡检 API，"
                    "研判新结果与预算余量，按规则派发/驱动探索会话并提交体验记录，"
                    "收到 409 立即收敛，最后汇报本轮巡检结果。"
                ),
            },
            "delivery": {"mode": "none"},
        }
        res = rpc(s, "c2", "cron.add", params)
        print("CRON.ADD:", json.dumps(res, ensure_ascii=False)[:1200])
    elif action == "run":
        job_id = sys.argv[2]
        res = rpc(s, "c2", "cron.run", {"id": job_id})
        print("CRON.RUN:", json.dumps(res, ensure_ascii=False)[:1200])
    elif action == "runs":
        job_id = sys.argv[2]
        res = rpc(s, "c2", "cron.runs", {"id": job_id})
        print("CRON.RUNS:", json.dumps(res, ensure_ascii=False)[:2000])
    s.close()


if __name__ == "__main__":
    main(sys.argv[1] if len(sys.argv) > 1 else "list")
