"""VS Code extension notification client.

Sends WebSocket messages to the VS Code extension after tool execution,
triggering visual updates like opening GDS viewer, simulation panel,
or DRC results. Notifications are fire-and-forget — failures are logged
at debug level and never affect tool results.
"""

from __future__ import annotations

import asyncio
import json
import logging
from typing import TYPE_CHECKING

import websockets

if TYPE_CHECKING:
    from .registry import ServerRegistry

__all__ = ["notify_extension"]

logger = logging.getLogger(__name__)


async def notify_extension(
    project: str | None,
    message: dict,
    registry: ServerRegistry | None = None,
) -> bool:
    """Send a WebSocket message to the VS Code extension.

    Args:
        project: Project name/path to target, or None for single-server mode.
        message: The message dict to send (must include "what" key).
        registry: Optional registry instance (creates one if not provided).

    Returns:
        True if the message was sent successfully, False otherwise.
    """
    if registry is None:
        from .registry import ServerRegistry

        registry = ServerRegistry()

    ws_port = _resolve_ws_port(project, registry)

    if ws_port is None:
        logger.debug("No ws_port found in registry, skipping notification")
        return False

    try:
        uri = f"ws://localhost:{ws_port}"
        async with websockets.connect(uri, open_timeout=2, close_timeout=2) as ws:
            await ws.send(json.dumps(message))
        return True
    except Exception:
        logger.debug("Failed to send notification to extension", exc_info=True)
        return False


async def notify_show_gds(
    project: str | None,
    cell_names: list[str],
    project_path: str,
    registry: ServerRegistry | None = None,
) -> None:
    """Send showGds notifications for built cells.

    Args:
        project: Project name/path.
        cell_names: List of cell names that are ready.
        project_path: Absolute path to the project directory.
        registry: Optional registry instance.
    """
    for i, cell_name in enumerate(cell_names):
        gds_path = f"{project_path}/build/gds/{cell_name}.gds"
        await notify_extension(project, {"what": "showGds", "gds": gds_path}, registry)
        if i < len(cell_names) - 1:
            await asyncio.sleep(0.2)


async def notify_open_simulation(
    project: str | None,
    name: str,
    simulation_id: str | None,
    registry: ServerRegistry | None = None,
) -> None:
    """Send openSimulation notification after simulation.

    Args:
        project: Project name/path.
        name: Component/cell name.
        simulation_id: Simulation ID from the response.
        registry: Optional registry instance.
    """
    await notify_extension(
        project,
        {
            "what": "openSimulation",
            "name": name,
            "simulationId": simulation_id,
        },
        registry,
    )


async def notify_show_check_results(
    project: str | None,
    check_type: str,
    cell_name: str,
    registry: ServerRegistry | None = None,
) -> None:
    """Send showCheckResults notification after verification checks.

    Args:
        project: Project name/path.
        check_type: One of "DRC", "Connectivity", "LVS".
        cell_name: Name of the cell that was checked.
        registry: Optional registry instance.
    """
    await notify_extension(
        project,
        {
            "what": "showCheckResults",
            "checkType": check_type,
            "cellName": cell_name,
        },
        registry,
    )


def _resolve_ws_port(
    project: str | None,
    registry: ServerRegistry,
) -> int | None:
    """Resolve the WebSocket port for a project."""
    if project:
        server = registry.get_server_by_project(project)
    else:
        servers = registry.list_servers()
        server = servers[0] if len(servers) == 1 else None

    if server is None:
        return None

    return server.ws_port
