#!/usr/bin/env python3
"""TCP JSONL client for the GDR/XDVD host bridge.

This is a small client for gdr_host_tcp_bridge.py --serve.  It sends one JSON
object per line and records one response per line.  It is intentionally simple
so later front-ends can reuse the same request/response shape before an iSCSI
or virtual-device adapter is added.
"""
from __future__ import annotations

import argparse, json, socket, sys
from pathlib import Path
from typing import Any

from gdr_host_jsonl_bridge import Catalog, load_requests, write_outputs, write_verify


def json_line(obj: dict[str, Any]) -> bytes:
    return (json.dumps(obj, separators=(',', ':')) + '\n').encode('utf-8')


def read_ready_file(path: str | None) -> tuple[str | None, int | None]:
    if not path:
        return None, None
    doc = json.loads(Path(path).read_text(encoding='utf-8'))
    return str(doc.get('host') or '127.0.0.1'), int(doc.get('port'))


def run_client(args: argparse.Namespace) -> int:
    ready_host, ready_port = read_ready_file(args.ready_file)
    host = ready_host or str(args.host)
    port = ready_port if ready_port is not None else int(args.port)
    reqs = load_requests(args.script)
    rows: list[dict[str, Any]] = []
    with socket.create_connection((host, port), timeout=float(args.timeout)) as sock:
        sock.settimeout(float(args.timeout))
        for req in reqs:
            sock.sendall(json_line(req))
        sock.shutdown(socket.SHUT_WR)
        buf = b''
        while True:
            chunk = sock.recv(65536)
            if not chunk:
                break
            buf += chunk
    for line in buf.decode('utf-8', errors='replace').splitlines():
        line = line.strip()
        if line:
            rows.append(json.loads(line))
    if len(rows) != len(reqs):
        raise SystemExit(f'TCP client response count mismatch: got={len(rows)} expected={len(reqs)}')
    write_outputs(rows, args.out, args.write_response_dir)
    if args.verify_md:
        write_verify(Path(args.verify_md), rows, Catalog(args.catalog))
    print(f'[TCP-CLIENT] requests={len(reqs)} responses={len(rows)} ok={sum(1 for r in rows if r.get("ok"))}', flush=True)
    return 0 if all(r.get('ok') for r in rows) else (0 if args.allow_check_condition else 2)


def main() -> int:
    ap = argparse.ArgumentParser(description='TCP JSONL client for GDR/XDVD host bridge')
    ap.add_argument('--host', default='127.0.0.1')
    ap.add_argument('--port', type=int, default=32610)
    ap.add_argument('--ready-file', help='optional {host,port} JSON written by gdr_host_tcp_bridge.py --serve')
    ap.add_argument('--timeout', default='10')
    ap.add_argument('--script', '-i', help='JSON/JSONL requests; stdin when omitted or -')
    ap.add_argument('--out', '-o', help='write JSONL responses here; stdout when omitted or -')
    ap.add_argument('--write-response-dir', help='optional directory for binary DATA IN/OUT payloads')
    ap.add_argument('--catalog', help='optional generated command catalog for verification annotation')
    ap.add_argument('--verify-md', help='optional compact verification markdown')
    ap.add_argument('--allow-check-condition', action='store_true', help='return 0 even when some responses are CHECK CONDITION')
    args = ap.parse_args()
    return run_client(args)


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