"""Synthetic MCP walkthrough. Utilities only unless --execute is supplied."""
import argparse
import asyncio
import getpass
import json
import os
import re
import sys
from urllib.parse import urlsplit

import httpx2
from mcp import Client
from mcp.client.streamable_http import streamable_http_client


def ceiling(value: str) -> str:
    if not re.fullmatch(r"0|[1-9][0-9]{0,19}", value) or int(value) > 2**64 - 1:
        raise argparse.ArgumentTypeError("max-cu must be a canonical decimal u64")
    return value


async def run(base_url: str, key: str, batch: bool, max_cu: str | None) -> dict:
    endpoint = base_url.rstrip("/") + "/mcp"
    parsed = urlsplit(endpoint)
    local = parsed.scheme == "http" and parsed.hostname in ("127.0.0.1", "localhost", "::1")
    if (not (parsed.scheme == "https" or local) or not parsed.hostname
            or parsed.username or parsed.password or parsed.query or parsed.fragment
            or parsed.path != "/mcp"):
        raise ValueError("use an HTTPS service origin, or HTTP loopback for local testing")
    option = {
        "exercise_style": "european", "pricing_model": "auto", "option_type": "call",
        "spot": 100, "strike": 100, "time_to_expiry_years": 1,
        "risk_free_rate": 0.05, "dividend_yield": 0, "volatility": 0.2,
    }
    operation = "price_batch" if batch else "price"
    payload = {"requests": [option, {**option, "strike": 105}]} if batch else option
    # No proxy inheritance, redirects or retry policy. Credentials stay in headers.
    async with httpx2.AsyncClient(
        headers={"Authorization": f"Bearer {key}"}, trust_env=False,
        follow_redirects=False, timeout=15,
    ) as http:
        async with Client(
            streamable_http_client(endpoint, http_client=http),
            mode="2026-07-28", read_timeout_seconds=15, cache=None,
        ) as client:
            tools, cursor = [], None
            while True:
                page = await client.list_tools(cursor=cursor)
                tools.extend(tool.name for tool in page.tools)
                cursor = page.next_cursor
                if cursor is None:
                    break
            report = {"tools": tools}
            for label, name, arguments in [
                ("catalog", "pricing_models", {}),
                # Schedule filters use billing operations; batches share price rates.
                ("schedule", "cost_schedule", {"operation": "price"}),
                ("quote", "cost_quote", {"request": {"operation": operation, "request": payload}}),
            ]:
                reply = await client.call_tool(name, arguments)
                report[label] = reply.structured_content
                if reply.is_error:
                    return report  # A refused utility never triggers execution.
            # Explicit caller ceiling, never inferred or raised from the quote.
            if max_cu is not None:
                reply = await client.call_tool(operation, {"request": payload, "max_cu": max_cu})
                report["execution"] = reply.structured_content
            return report


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--batch", action="store_true", help="use two synthetic options")
    parser.add_argument("--execute", action="store_true", help="submit one billable call after the utilities")
    parser.add_argument("--max-cu", type=ceiling, help="explicit ceiling for the whole execution")
    args = parser.parse_args()
    if args.execute != (args.max_cu is not None):
        parser.error("--execute and --max-cu must be supplied together")
    base_url = os.environ.get("MORPHIQ_API_BASE_URL")
    if not base_url:
        parser.error("set MORPHIQ_API_BASE_URL to your enabled test service origin")
    key = os.environ.get("MORPHIQ_API_KEY") or getpass.getpass("MCP API key (hidden): ")
    if not key:
        parser.error("an MCP-authorized key is required")
    try:
        report = asyncio.run(run(base_url, key, args.batch, args.max_cu))
    except Exception:
        # Do not print credentials, request headers or exception payloads.
        print("No complete response. Check service/client configuration; any execution outcome may be uncertain. No retry was attempted.", file=sys.stderr)
        raise SystemExit(1) from None
    print(json.dumps(report, indent=2))
    if any(isinstance(value, dict) and value.get("status") == "error" for value in report.values()):
        raise SystemExit(2)  # Structured service refusal was printed with its receipt.


if __name__ == "__main__":
    main()
