"""VM lifecycle tools: start and stop VirtualBox VMs via VBoxManage."""

from __future__ import annotations

import logging
from typing import Annotated, Literal

from fastmcp.tools import tool
from pydantic import Field

from mcp_vm_blackbox._helpers import _resolve, _vbox
from mcp_vm_blackbox.models import VmStartResult, VmStopResult
from mcp_vm_blackbox.vm_recording import _start_recording, _stop_recording

_log = logging.getLogger(__name__)

# Valid start modes for VBoxManage startvm --type
_START_MODES: tuple[str, ...] = ("headless", "gui", "separate")

# Valid stop modes for VBoxManage controlvm
_STOP_MODES: tuple[str, ...] = ("acpi", "poweroff", "savestate")


@tool
async def vm_start(
    vm_name: Annotated[str, Field(description="VirtualBox VM name.")],
    mode: Annotated[
        Literal["headless", "gui"], Field(description="Start mode: 'headless' (default) or 'gui'.")
    ] = "headless",
    target: Annotated[
        str, Field(description='Named target ("local", "ci") or raw SSH string ("user@host").')
    ] = "local",
) -> VmStartResult:
    """Start a VirtualBox VM.

    Uses ``VBoxManage startvm <vm> --type <mode>`` to start the VM.
    For headless mode (default), the VM runs in the background without a GUI.
    For GUI mode, the VirtualBox GUI opens with the VM console.

    Args:
        vm_name: VirtualBox VM name as shown in ``VBoxManage list vms``.
        mode: Start mode: ``"headless"`` (default) or ``"gui"``.
        target: Named target or raw SSH string.

    Returns:
        VmStartResult with status, vm_name, mode on success, or error on failure.
    """
    cfg = _resolve(target)
    try:
        # VBoxDispatch.start_vm handles the VBoxManage command
        dispatch = _vbox(cfg, vm_name)
        await dispatch.start_vm(mode=mode)
    except RuntimeError as exc:
        return VmStartResult(status="error", vm_name=vm_name, mode=mode, error=f"Failed to start VM '{vm_name}': {exc}")

    # Auto-start always-on recording (non-fatal)
    recording_started = False
    recording_path: str | None = None
    recording_warning: str | None = None
    try:
        rec_result = await _start_recording(vm_name, target=target)
        if rec_result.status == "ok":
            recording_started = True
            recording_path = rec_result.recording_path
        else:
            recording_warning = rec_result.error or "Recording failed to start"
    except Exception as exc:  # noqa: BLE001
        _log.warning("Auto-recording start failed for '%s': %s", vm_name, exc)
        recording_warning = f"Recording failed to start: {exc}"

    return VmStartResult(
        status="ok",
        vm_name=vm_name,
        mode=mode,
        recording_started=recording_started,
        recording_path=recording_path,
        recording_warning=recording_warning,
    )


@tool
async def vm_stop(
    vm_name: Annotated[str, Field(description="VirtualBox VM name.")],
    mode: Annotated[
        Literal["acpi", "poweroff", "savestate"],
        Field(
            description="Stop mode: 'acpi' (graceful, default), 'poweroff' (hard), or 'savestate' (suspend to disk)."
        ),
    ] = "acpi",
    target: Annotated[
        str, Field(description='Named target ("local", "ci") or raw SSH string ("user@host").')
    ] = "local",
) -> VmStopResult:
    """Stop a VirtualBox VM.

    Uses ``VBoxManage controlvm <vm> <mode>`` to stop the VM:

    - ``acpi`` (default): Sends ACPI power-button event for graceful shutdown.
    - ``poweroff``: Hard power-off, equivalent to pulling the plug.
    - ``savestate``: Saves VM state to disk and suspends (fast resume).

    Args:
        vm_name: VirtualBox VM name as shown in ``VBoxManage list vms``.
        mode: Stop mode: ``"acpi"`` (default), ``"poweroff"``, or ``"savestate"``.
        target: Named target or raw SSH string.

    Returns:
        VmStopResult with status, vm_name, mode on success, or error on failure.
    """
    cfg = _resolve(target)

    # Auto-stop always-on recording before shutdown (non-fatal)
    recording_stopped = False
    recording_path: str | None = None
    try:
        rec_result = await _stop_recording(vm_name, target=target)
        if rec_result.status == "ok":
            recording_stopped = True
            recording_path = rec_result.recording_path
    except Exception as exc:  # noqa: BLE001
        _log.warning("Auto-recording stop failed for '%s': %s", vm_name, exc)

    try:
        dispatch = _vbox(cfg, vm_name)
        await dispatch.stop_vm(mode=mode)
    except RuntimeError as exc:
        return VmStopResult(status="error", vm_name=vm_name, mode=mode, error=f"Failed to stop VM '{vm_name}': {exc}")

    return VmStopResult(
        status="ok", vm_name=vm_name, mode=mode, recording_stopped=recording_stopped, recording_path=recording_path
    )
