from __future__ import annotations

from typing import Any
from urllib.parse import quote

from .client import RabbitMQClient
from .mcp_errors import MCPToolError
from .registry import Operation


async def enforce_safety(
    operation: Operation,
    client: RabbitMQClient,
    path_params: dict[str, Any] | None,
    allow_destructive: bool,
) -> None:
    if not operation.safety_validation_required:
        return
    if not allow_destructive:
        raise MCPToolError(
            code="DESTRUCTIVE_OPERATION",
            message="Destructive operation requires allow_destructive=true",
        )

    params = path_params or {}
    vhost = params.get("vhost", "/")

    async def _ensure_queue(queue_name: str) -> None:
        try:
            await client.request(
                "GET",
                f"/api/queues/{quote(str(vhost), safe='')}/{quote(str(queue_name), safe='')}",
            )
        except Exception as exc:
            raise MCPToolError(
                code="QUEUE_NOT_FOUND",
                message="Queue not found",
                details={"queue": queue_name},
            ) from exc

    async def _ensure_exchange(exchange_name: str) -> None:
        try:
            await client.request(
                "GET",
                f"/api/exchanges/{quote(str(vhost), safe='')}/{quote(str(exchange_name), safe='')}",
            )
        except Exception as exc:
            raise MCPToolError(
                code="EXCHANGE_NOT_FOUND",
                message="Exchange not found",
                details={"exchange": exchange_name},
            ) from exc

    if operation.namespace == "queues" and operation.method.lower() == "delete":
        name = params.get("name")
        if name:
            queue = await client.request(
                "GET",
                f"/api/queues/{quote(str(vhost), safe='')}/{quote(str(name), safe='')}",
            )
            if isinstance(queue, dict):
                messages = queue.get("messages", 0)
                if isinstance(messages, int) and messages > 0:
                    raise MCPToolError(
                        code="QUEUE_NOT_EMPTY",
                        message="Queue has messages; purge before deleting",
                        details={"messages": messages},
                    )

    if operation.namespace == "queues_contents" and operation.method.lower() == "delete":
        name = params.get("name")
        if name:
            await _ensure_queue(str(name))

    if operation.namespace == "exchanges" and operation.method.lower() == "delete":
        name = params.get("name") or params.get("exchange")
        if name:
            await _ensure_exchange(str(name))
            source = await client.request(
                "GET",
                f"/api/exchanges/{quote(str(vhost), safe='')}/{quote(str(name), safe='')}/bindings/source",
            )
            destination = await client.request(
                "GET",
                f"/api/exchanges/{quote(str(vhost), safe='')}/{quote(str(name), safe='')}/bindings/destination",
            )
            if (isinstance(source, list) and source) or (
                isinstance(destination, list) and destination
            ):
                raise MCPToolError(
                    code="EXCHANGE_HAS_BINDINGS",
                    message="Exchange has bindings; remove bindings before deleting",
                )

    if operation.namespace == "bindings" and operation.method.lower() in {"post", "delete"}:
        if "queue" in params and "exchange" in params:
            await _ensure_queue(str(params["queue"]))
            await _ensure_exchange(str(params["exchange"]))
        if "source" in params and "destination" in params:
            await _ensure_exchange(str(params["source"]))
            await _ensure_exchange(str(params["destination"]))
