"""Shell executor implementation."""

from __future__ import annotations

import asyncio
import os
from typing import TYPE_CHECKING

from portal.shared.protocols.infrastructure_protocols import (
    ShellExecutorProtocol,
    ShellResult,
)

if TYPE_CHECKING:
    from pathlib import Path


class ShellExecutor(ShellExecutorProtocol):
    """Execute shell commands safely."""

    async def execute(
        self,
        command: str,
        cwd: Path | None = None,
        env: dict[str, str] | None = None,
        capture_output: bool = True,
        timeout: int | None = None,
    ) -> ShellResult:
        """Execute a shell command securely.

        Args:
            command: Command to execute
            cwd: Working directory for command
            env: Environment variables to merge
            capture_output: Whether to capture stdout/stderr
            timeout: Timeout in seconds

        Returns:
            ShellResult with execution details
        """
        # Merge environment securely
        full_env = os.environ.copy()
        if env:
            full_env.update(env)

        try:
            process = await asyncio.create_subprocess_shell(
                command,
                stdout=asyncio.subprocess.PIPE if capture_output else None,
                stderr=asyncio.subprocess.PIPE if capture_output else None,
                cwd=cwd,
                env=full_env,
            )

            stdout, stderr = await asyncio.wait_for(process.communicate(), timeout=timeout)

            return ShellResult(
                success=process.returncode == 0,
                stdout=stdout.decode() if stdout else "",
                stderr=stderr.decode() if stderr else "",
                exit_code=process.returncode or 0,
            )

        except TimeoutError:
            if process:
                process.kill()
                await process.wait()
            return ShellResult(
                success=False,
                stdout="",
                stderr=f"Command timed out after {timeout} seconds",
                exit_code=-1,
            )
        except Exception as e:
            return ShellResult(
                success=False,
                stdout="",
                stderr=str(e),
                exit_code=-1,
            )
