"""Run Node.js packages in background with npx.

DEPRECATED: This module uses blocking subprocess.Popen operations.
For new code, use the async implementations in:
- hanzo_mcp.tools.shell.npx_tool.NpxTool (based on BaseBinaryTool)

This provides non-blocking process execution using asyncio.create_subprocess_exec
with automatic backgrounding for long-running processes.
This module is maintained for backwards compatibility only.
"""

import warnings

# Emit deprecation warning on import
warnings.warn(
    "npx_background.py uses blocking subprocess.Popen. "
    "Consider using npx_tool.NpxTool for async execution.",
    DeprecationWarning,
    stacklevel=2
)

import uuid
import shutil
import subprocess
from typing import Unpack, Optional, Annotated, TypedDict, final, override

from pydantic import Field
from mcp.server.fastmcp import Context as MCPContext

from hanzo_mcp.tools.common.base import BaseTool
from hanzo_mcp.tools.common.context import create_tool_context
from hanzo_mcp.tools.common.permissions import PermissionManager
from hanzo_mcp.tools.common.auto_timeout import auto_timeout
from hanzo_mcp.tools.shell.run_background import BackgroundProcess, RunBackgroundTool

Package = Annotated[
    str,
    Field(
        description="Package name to run (e.g., 'http-server', 'json-server', 'serve')",
        min_length=1,
    ),
]

Args = Annotated[
    Optional[str],
    Field(
        description="Arguments to pass to the package",
        default=None,
    ),
]

Name = Annotated[
    Optional[str],
    Field(
        description="Process name for identification",
        default=None,
    ),
]

Yes = Annotated[
    bool,
    Field(
        description="Auto-confirm package installation",
        default=True,
    ),
]

LogOutput = Annotated[
    bool,
    Field(
        description="Log output to file in ~/.hanzo/logs",
        default=True,
    ),
]

WorkingDir = Annotated[
    Optional[str],
    Field(
        description="Working directory for the process",
        default=None,
    ),
]


class NpxBackgroundParams(TypedDict, total=False):
    """Parameters for npx background tool."""

    package: str
    args: Optional[str]
    name: Optional[str]
    yes: bool
    log_output: bool
    working_dir: Optional[str]


@final
class NpxBackgroundTool(BaseTool):
    """Tool for running Node.js packages in background with npx."""

    def __init__(self, permission_manager: PermissionManager):
        """Initialize the npx background tool.

        Args:
            permission_manager: Permission manager for access control
        """
        self.permission_manager = permission_manager

    @property
    @override
    def name(self) -> str:
        """Get the tool name."""
        return "npx_background"

    @property
    @override
    def description(self) -> str:
        """Get the tool description."""
        return """Run Node.js packages in the background using npx.

Perfect for running servers and long-running Node.js applications.
The process continues running even after the command returns.

Common server packages:
- http-server: Simple HTTP server
- json-server: REST API mock server
- serve: Static file server
- live-server: Dev server with reload
- webpack-dev-server: Webpack dev server
- nodemon: Auto-restart on changes
- localtunnel: Expose local server
- ngrok: Secure tunnels

Examples:
- npx_background --package http-server --args "-p 8080" --name web-server
- npx_background --package json-server --args "db.json --port 3001" --name api
- npx_background --package serve --args "-s build -p 5000" --name static
- npx_background --package live-server --args "--port=8081" --name dev-server

Use 'processes' to list running processes and 'pkill' to stop them.
"""

    @override
    @auto_timeout("npx")
    async def call(
        self,
        ctx: MCPContext,
        **params: Unpack[NpxBackgroundParams],
    ) -> str:
        """Execute npx command in background.

        Args:
            ctx: MCP context
            **params: Tool parameters

        Returns:
            Process information
        """
        tool_ctx = create_tool_context(ctx)
        await tool_ctx.set_tool_info(self.name)

        # Extract parameters
        package = params.get("package")
        if not package:
            return "Error: package is required"

        args = params.get("args", "")
        name = params.get("name", f"npx-{package}")
        yes = params.get("yes", True)
        log_output = params.get("log_output", True)
        working_dir = params.get("working_dir")

        # Check if npx is available
        if not shutil.which("npx"):
            return """Error: npx is not installed. Install Node.js and npm:

On macOS:
brew install node

On Ubuntu/Debian:
sudo apt update && sudo apt install nodejs npm

Or download from: https://nodejs.org/"""

        # Build command
        cmd = ["npx"]

        if yes:
            cmd.append("--yes")

        cmd.append(package)

        # Add package arguments
        if args:
            # Split args properly (basic parsing)
            import shlex

            cmd.extend(shlex.split(args))

        # Generate process ID
        process_id = str(uuid.uuid4())[:8]

        # Prepare log file if needed
        log_file = None
        if log_output:
            from pathlib import Path

            log_dir = Path.home() / ".hanzo" / "logs"
            log_dir.mkdir(parents=True, exist_ok=True)
            log_file = log_dir / f"{name}_{process_id}.log"

        await tool_ctx.info(f"Starting background process: {' '.join(cmd)}")

        try:
            # Start process
            if log_output and log_file:
                with open(log_file, "w") as f:
                    process = subprocess.Popen(
                        cmd,
                        stdout=f,
                        stderr=subprocess.STDOUT,
                        cwd=working_dir,
                        start_new_session=True,
                    )
            else:
                process = subprocess.Popen(
                    cmd,
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL,
                    cwd=working_dir,
                    start_new_session=True,
                )

            # Create background process object
            bg_process = BackgroundProcess(
                process_id=process_id,
                command=" ".join(cmd),
                name=name,
                process=process,
                log_file=str(log_file) if log_file else None,
                working_dir=working_dir,
            )

            # Register with RunBackgroundTool
            RunBackgroundTool._add_process(bg_process)

            output = [
                f"Started npx background process:",
                f"  ID: {process_id}",
                f"  Name: {name}",
                f"  Package: {package}",
                f"  PID: {process.pid}",
                f"  Command: {' '.join(cmd)}",
            ]

            if working_dir:
                output.append(f"  Working Dir: {working_dir}")

            if log_file:
                output.append(f"  Log: {log_file}")

            output.extend(
                [
                    "",
                    "Use 'processes' to list running processes.",
                    f"Use 'logs --process-id {process_id}' to view output.",
                    f"Use 'pkill --process-id {process_id}' to stop.",
                ]
            )

            return "\n".join(output)

        except Exception as e:
            await tool_ctx.error(f"Failed to start process: {str(e)}")
            return f"Error starting npx background process: {str(e)}"

    def register(self, mcp_server) -> None:
        """Register this tool with the MCP server."""
        pass
