"""
JavaScript Runtime

Node.js stdio protocol runtime for JavaScript tools.
"""

import asyncio
import json
import shutil
from pathlib import Path
from typing import Any, Dict, Optional

from tools.runtime.base import BaseRuntime


class JavaScriptRuntime(BaseRuntime):
    """JavaScript runtime using Node.js stdio protocol"""

    def __init__(self, node_path: Optional[str] = None):
        self.node_path = node_path or self._detect_node()
        self._validated: bool = False

    def get_name(self) -> str:
        return "javascript"

    def _detect_node(self) -> str:
        """Detect Node.js executable path"""
        node = shutil.which("node")
        if node:
            return node
        # Fallback for Windows
        return "node"

    async def validate(self, entry: str) -> bool:
        """Validate Node.js runtime and entry file"""
        # Check node is available
        try:
            result = await asyncio.create_subprocess_exec(
                self.node_path,
                "--version",
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
            )
            await result.wait()
            if result.returncode != 0:
                return False
        except Exception:
            return False

        # Check entry file exists
        path = Path(entry)
        if not path.exists():
            return False

        self._validated = True
        return True

    async def execute(
        self,
        entry: str,
        command: str,
        parameters: Dict[str, Any],
        timeout: int,
    ) -> Dict[str, Any]:
        """Execute a JavaScript tool via stdio protocol"""
        if not self._validated:
            is_valid = await self.validate(entry)
            if not is_valid:
                return {
                    "status": "error",
                    "error": "JavaScript runtime not available or entry file invalid",
                }

        # Build input data per stdio protocol
        input_data = {
            "command": command,
            "parameters": parameters,
        }

        try:
            process = await asyncio.create_subprocess_exec(
                self.node_path,
                entry,
                stdin=asyncio.subprocess.PIPE,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
            )

            stdout, stderr = await asyncio.wait_for(
                process.communicate(input=json.dumps(input_data).encode()),
                timeout=timeout / 1000,
            )

            if process.returncode != 0:
                return {
                    "status": "error",
                    "error": stderr.decode() if stderr else "Unknown error",
                }

            result_text = stdout.decode()
            if not result_text:
                return {
                    "status": "error",
                    "error": "Empty response from Node.js runtime",
                }

            try:
                result = json.loads(result_text)
                return result
            except json.JSONDecodeError:
                return {
                    "status": "success",
                    "result": result_text,
                }

        except asyncio.TimeoutError:
            return {
                "status": "error",
                "error": f"Execution timed out after {timeout}ms",
            }
        except Exception as e:
            return {
                "status": "error",
                "error": str(e),
            }
