import argparse
import os
import threading

from flownet.api.actor_ref import ContainerRef
from flownet.config import ContainerRuntimeConfig
from flownet.core.request import FlownetPacket
from flownet.runtime import loops
from flownet.runtime.runtime import get_runtime


def main():
    os.environ.setdefault("FLOWNET_RUNTIME_ROLE", "container")
    # Node-centric membership guardrail:
    # container runtimes are worker endpoints, not cluster members.
    # Scheduler/placement can still consume container effects via node-local
    # aggregated summaries exposed by the hosting node.
    os.environ.pop("FLOWNET_CLUSTER_NODES", None)
    os.environ.setdefault("FLOWNET_CLUSTER_GOSSIP_ENABLED", "0")
    parser = argparse.ArgumentParser(description="Start a Flownet container.")
    parser.add_argument("--host", type=str, default="127.0.0.1", help="Host to bind the container runtime.")
    parser.add_argument("--port", type=int, required=True, help="Port to bind the container runtime.")
    parser.add_argument("--node-id", type=str, default="default-node", help="Logical node id.")
    parser.add_argument("--threads", type=int, default=4, help="Max worker threads for the container runtime.")
    parser.add_argument("--transport-mode", type=str, default="auto", help="Transport mode: auto|tcp|uds_prefer|hetero_auto.")
    parser.add_argument("--local-ipc-dir", type=str, default="/tmp/flownet", help="Directory for local IPC sockets.")
    parser.add_argument(
        "--transport-shm-threshold-bytes",
        type=int,
        default=262144,
        help="Payload size threshold to prefer SHM in hetero_auto mode.",
    )
    parser.add_argument(
        "--transport-shm-max-payload-bytes",
        type=int,
        default=67108864,
        help="Max payload bytes allowed for SHM transport.",
    )
    parser.add_argument(
        "--transport-backend-cooldown-seconds",
        type=float,
        default=1.0,
        help="Cooldown after backend failure before retrying same backend/address.",
    )
    parser.add_argument(
        "--transport-backend-cooldown-max-entries",
        type=int,
        default=4096,
        help="Max entries tracked in backend cooldown map.",
    )
    parser.add_argument(
        "--transport-backend-cooldown-cleanup-interval",
        type=int,
        default=128,
        help="Cleanup interval (send operations) for cooldown pruning.",
    )
    parser.add_argument("--host-id", type=str, default="", help="Stable host identifier for locality matching.")
    parser.add_argument("--uds-path", type=str, default="", help="Explicit UDS socket path for this runtime.")
    parser.add_argument("--shm-path", type=str, default="", help="Explicit SHM control socket path for this runtime.")
    parser.add_argument(
        "--transport-caps",
        type=str,
        default="",
        help="Comma-separated transport capability list (e.g. tcp,uds,shm).",
    )
    parser.add_argument("--creator", type=str, help="address of the creator runtime (optional).")
    parser.add_argument("--uuid", type=str, help="callback uuid of the creator runtime.")
    args = parser.parse_args()
    print("args:", args)
    transport_caps_list = [
        cap.strip().lower()
        for cap in args.transport_caps.split(",")
        if isinstance(cap, str) and cap.strip()
    ]
    if transport_caps_list and "tcp" not in transport_caps_list:
        transport_caps_list.append("tcp")
    transport_caps = tuple(transport_caps_list) or None
    config = ContainerRuntimeConfig(
        host=args.host,
        port=args.port,
        node_id=args.node_id,
        threads=args.threads,
        transport_mode=args.transport_mode,
        local_ipc_dir=args.local_ipc_dir,
        transport_shm_threshold_bytes=args.transport_shm_threshold_bytes,
        transport_shm_max_payload_bytes=args.transport_shm_max_payload_bytes,
        transport_backend_cooldown_seconds=args.transport_backend_cooldown_seconds,
        transport_backend_cooldown_max_entries=args.transport_backend_cooldown_max_entries,
        transport_backend_cooldown_cleanup_interval=args.transport_backend_cooldown_cleanup_interval,
        host_id=args.host_id or None,
        uds_path=args.uds_path or None,
        shm_path=args.shm_path or None,
        transport_caps=transport_caps,
    )
    import flownet.api
    flownet.api.configure_runtime(config)
    runtime = get_runtime()
    if args.creator and not args.uuid or args.uuid and not args.creator:
        raise ValueError("Both --creator and --uuid must be provided together.")

    role_label = "Container"
    if args.creator and args.uuid:
        container_ref = ContainerRef(address=args.creator)
        try:
            container_ref.ping().result()
        except Exception as e:
            raise ConnectionError(
                f"[FlownetRuntime] Failed to connect to container at {args.creator}: {e}"
            ) from e
        print("connected to creator at", args.creator)
        coro = runtime.call_manager.send_packet(args.creator, FlownetPacket(
            type="response",
            uuid=args.uuid,
            reply=False,
            packet_content=None,
        ))
        loops.submit_runtime_coro(coro)
        # creator_ref.hello(f"{args.host}:{args.port}")
    print(f"[{role_label} Main] FlownetRuntime started at {args.host}:{args.port} with {args.threads} threads.")

    # 阻塞主线程以保持存活（例如使用 EventLoop）
    try:
        threading.Event().wait()
    except KeyboardInterrupt:
        print(f"[{role_label} Main] Shutdown requested. Exiting...")

if __name__ == "__main__":
    main()
