from __future__ import annotations

from typing import Any

from flownet.api.actor_ref import ContainerRef
import flownet.api.runtime as runtime_api
from flownet.config import RuntimeConfigInput, coerce_flownet_config


def spawn_container(
    config: RuntimeConfigInput,
    *,
    node_address: str | None = None,
    tenant_id: str | None = None,
    flow_id: str | None = None,
    request_id: str | None = None,
) -> ContainerRef:
    resolved = coerce_flownet_config(config, section="container")
    address = runtime_api.node_control_call(
        "spawn_container",
        resolved,
        tenant_id=tenant_id,
        flow_id=flow_id,
        request_id=request_id,
        node_address=node_address,
    )
    if isinstance(address, str):
        return ContainerRef(address=address)
    raise TypeError(f"Unexpected spawn response type: {type(address)}")


def spawn_container_on(
    node_address: str,
    config: RuntimeConfigInput,
    *,
    tenant_id: str | None = None,
    flow_id: str | None = None,
    request_id: str | None = None,
) -> ContainerRef:
    return spawn_container(
        config,
        node_address=node_address,
        tenant_id=tenant_id,
        flow_id=flow_id,
        request_id=request_id,
    )


def list_containers(*, node_address: str | None = None) -> list[dict[str, Any]]:
    items = runtime_api.node_control_call(
        "list_containers",
        node_address=node_address,
    )
    return list(items or [])


def list_containers_on(node_address: str) -> list[dict[str, Any]]:
    return list_containers(node_address=node_address)


def kill_container(
    address: str,
    *,
    node_address: str | None = None,
    timeout: float = 5.0,
) -> bool:
    result = runtime_api.node_control_call(
        "kill_container",
        address,
        timeout=timeout,
        node_address=node_address,
    )
    return bool(result)


def kill_container_on(
    node_address: str,
    address: str,
    *,
    timeout: float = 5.0,
) -> bool:
    return kill_container(
        address,
        node_address=node_address,
        timeout=timeout,
    )


def list_services(*, node_address: str | None = None) -> list[dict[str, Any]]:
    items = runtime_api.node_control_call(
        "list_services",
        node_address=node_address,
    )
    return list(items or [])


def list_services_on(node_address: str) -> list[dict[str, Any]]:
    return list_services(node_address=node_address)


def subscribe_service_flow(
    service_name: str,
    flow_task: Any,
    execution_address: str,
    *,
    tags: dict[str, str] | None = None,
    node_address: str | None = None,
) -> str:
    value = runtime_api.node_control_call(
        "subscribe_service_flow",
        service_name,
        flow_task,
        execution_address,
        tags=tags,
        node_address=node_address,
    )
    if not isinstance(value, str):
        raise TypeError(f"Unexpected subscribe response type: {type(value)}")
    return value


def subscribe_service_flow_on(
    node_address: str,
    service_name: str,
    flow_task: Any,
    execution_address: str,
    *,
    tags: dict[str, str] | None = None,
) -> str:
    return subscribe_service_flow(
        service_name,
        flow_task,
        execution_address,
        tags=tags,
        node_address=node_address,
    )


def unsubscribe_service_flow(
    subscription_id: str,
    *,
    node_address: str | None = None,
) -> bool:
    result = runtime_api.node_control_call(
        "unsubscribe_service_flow",
        subscription_id,
        node_address=node_address,
    )
    return bool(result)


def unsubscribe_service_flow_on(node_address: str, subscription_id: str) -> bool:
    return unsubscribe_service_flow(subscription_id, node_address=node_address)


def list_runtime_topics(*, node_address: str | None = None):
    return runtime_api.node_control_call(
        "list_runtime_topics",
        node_address=node_address,
    )


def list_runtime_actors(*, node_address: str | None = None):
    return runtime_api.node_control_call(
        "list_runtime_actors",
        node_address=node_address,
    )


def list_runtime_nodes(*, node_address: str | None = None):
    return runtime_api.node_control_call(
        "list_runtime_nodes",
        node_address=node_address,
    )


def cluster_view_snapshot(*, schema: str = "v1", node_address: str | None = None):
    return runtime_api.node_control_call(
        "cluster_view_snapshot",
        schema=schema,
        node_address=node_address,
    )


def cluster_gossip_stats(*, node_address: str | None = None):
    return runtime_api.node_control_call(
        "cluster_gossip_stats",
        node_address=node_address,
    )


__all__ = [
    "spawn_container",
    "spawn_container_on",
    "list_containers",
    "list_containers_on",
    "kill_container",
    "kill_container_on",
    "list_services",
    "list_services_on",
    "subscribe_service_flow",
    "subscribe_service_flow_on",
    "unsubscribe_service_flow",
    "unsubscribe_service_flow_on",
    "list_runtime_topics",
    "list_runtime_actors",
    "list_runtime_nodes",
    "cluster_view_snapshot",
    "cluster_gossip_stats",
]
