"""Shell command execution with safety guardrails."""

from __future__ import annotations

import asyncio
import re
from pathlib import Path
from typing import Optional

BLOCKED_PATTERNS = [
    re.compile(r"rm\s+(-[a-zA-Z]*r[a-zA-Z]*f|--recursive)\s+/\s*$"),
    re.compile(r"\brm\s+-rf\s+/\b"),
    re.compile(r"\bmkfs\b"),
    re.compile(r"\bdd\s+if="),
    re.compile(r":\(\)\s*\{.*\|.*&\s*\}\s*;"),
    re.compile(r"\b(shutdown|reboot|halt|poweroff)\b"),
    re.compile(r"\bchmod\s+(-R\s+)?777\s+/\s*$"),
    re.compile(r"curl.*\|\s*(ba)?sh"),
    re.compile(r"wget.*\|\s*(ba)?sh"),
    re.compile(r">\s*/dev/sd[a-z]"),
    re.compile(r">\s*/etc/passwd"),
]

COMMAND_TIMEOUT = 60


async def run_command(command: str, cwd: Optional[str] = None) -> str:
    """Execute a shell command with safety checks.

    Returns a string with exit_code, stdout, and stderr.
    """
    for pattern in BLOCKED_PATTERNS:
        if pattern.search(command):
            return f"BLOCKED: Command matches safety pattern. Refused to execute: {command}"

    effective_cwd = cwd or str(Path.home())

    try:
        proc = await asyncio.create_subprocess_shell(
            command,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
            cwd=effective_cwd,
        )
        stdout, stderr = await asyncio.wait_for(
            proc.communicate(), timeout=COMMAND_TIMEOUT
        )

        out = stdout.decode(errors="replace").strip()
        err = stderr.decode(errors="replace").strip()

        if len(out) > 50_000:
            out = out[:50_000] + f"\n... [truncated, {len(stdout)} bytes total]"
        if len(err) > 10_000:
            err = err[:10_000] + f"\n... [truncated, {len(stderr)} bytes total]"

        parts = [f"exit_code: {proc.returncode}"]
        if out:
            parts.append(f"stdout:\n{out}")
        if err:
            parts.append(f"stderr:\n{err}")

        return "\n".join(parts)

    except asyncio.TimeoutError:
        try:
            proc.kill()  # type: ignore[possibly-undefined]
        except Exception:
            pass
        return f"Error: Command timed out after {COMMAND_TIMEOUT}s: {command}"
    except Exception as e:
        return f"Error: {e}"
