#!/usr/bin/env python3
import argparse
import json
import shutil
import subprocess
from pathlib import Path

OPENCLAW_HOME = Path.home() / '.openclaw'
AGENTS_DIR = OPENCLAW_HOME / 'agents'
CONFIG_PATH = OPENCLAW_HOME / 'openclaw.json'


def load_json(path: Path):
    with path.open() as f:
        return json.load(f)


def save_json(path: Path, data):
    tmp = path.with_suffix(path.suffix + '.tmp')
    with tmp.open('w') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
        f.write('\n')
    tmp.replace(path)


def normalize(s):
    return (s or '').lower()


def ensure_agent(agent_id: str):
    if not (AGENTS_DIR / agent_id).exists():
        raise SystemExit(f'Agent not found: {agent_id}')


def restart_gateway(dry_run: bool):
    if dry_run:
        return {'requested': True, 'executed': False}
    cp = subprocess.run(['openclaw', 'gateway', 'restart'], capture_output=True, text=True)
    return {'requested': True, 'executed': cp.returncode == 0, 'stdout': cp.stdout.strip(), 'stderr': cp.stderr.strip()}


def main():
    ap = argparse.ArgumentParser(description='Bind one DM/channel account to exactly one agent.')
    ap.add_argument('--channel', default='openclaw-weixin')
    ap.add_argument('--account-id', required=True)
    ap.add_argument('--agent', required=True)
    ap.add_argument('--restart-gateway', action='store_true')
    ap.add_argument('--yes', action='store_true')
    ap.add_argument('--dry-run', action='store_true')
    args = ap.parse_args()

    ensure_agent(args.agent)
    dry_run = args.dry_run or not args.yes
    cfg = load_json(CONFIG_PATH)
    bindings = cfg.get('bindings', [])
    channel_n = normalize(args.channel)
    account_n = normalize(args.account_id)
    kept = []
    removed = []
    for b in bindings:
        match = b.get('match') or {}
        same = normalize(match.get('channel')) == channel_n and normalize(match.get('accountId')) == account_n
        if same:
            removed.append(b)
        else:
            kept.append(b)
    desired = {'type': 'route', 'agentId': args.agent, 'match': {'channel': args.channel, 'accountId': args.account_id}}
    final_bindings = kept + [desired]
    report = {
        'mode': 'bind',
        'channel': args.channel,
        'accountId': args.account_id,
        'agent': args.agent,
        'dryRun': dry_run,
        'removedBindings': removed,
        'finalBinding': desired,
    }
    print(json.dumps(report, ensure_ascii=False, indent=2))
    gateway = None
    if not dry_run:
        cfg['bindings'] = final_bindings
        backup = CONFIG_PATH.with_suffix('.json.bak')
        shutil.copy2(CONFIG_PATH, backup)
        save_json(CONFIG_PATH, cfg)
    if args.restart_gateway:
        gateway = restart_gateway(dry_run)
    result = {
        'createdBinding': True,
        'removedBindingsCount': len(removed),
        'gatewayRestart': gateway,
        'nextStep': f'Send one fresh inbound message from account {args.account_id} and verify a new session appears under agent {args.agent}.'
    }
    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == '__main__':
    main()
