# adapters/blaxel.py

from __future__ import annotations
from typing import Any
from ..core.types import ExecResult, ExecOpts
from ..core.shell import shell_escape, fire_and_forget


def blaxel(sandbox: Any) -> _BlaxelAdapter:
    return _BlaxelAdapter(sandbox)


class _BlaxelAdapter:
    def __init__(self, sandbox: Any) -> None:
        self._sb = sandbox

    async def exec(
        self,
        cmd: str,
        args: list[str] | None = None,
        opts: ExecOpts | None = None,
    ) -> ExecResult:
        opts = opts or ExecOpts()
        command = shell_escape(cmd, args)
        full_cmd = f"sudo {command}" if opts.sudo else command

        exec_opts: dict[str, Any] = {
            "command": full_cmd,
            "wait_for_completion": True,
            "timeout": 60,
        }
        if opts.cwd:
            exec_opts["working_dir"] = opts.cwd

        try:
            if opts.detached:
                exec_opts["command"] = f"nohup {full_cmd} > /dev/null 2>&1 &"
                exec_opts["wait_for_completion"] = False
                fire_and_forget(self._sb.process.exec(exec_opts))
                return ExecResult(stdout="", stderr="", exit_code=0)

            result = await self._sb.process.exec(exec_opts)
            return ExecResult(
                stdout=getattr(result, "stdout", "") or "",
                stderr=getattr(result, "stderr", "") or "",
                exit_code=getattr(result, "exit_code", 0) or 0,
            )
        except Exception as e:
            return ExecResult(
                stdout=getattr(e, "stdout", "") or "",
                stderr=getattr(e, "stderr", "") or getattr(e, "message", str(e)),
                exit_code=getattr(e, "exit_code", 1),
            )

    async def write_file(self, path: str, content: str | bytes, *, sudo: bool = False) -> None:
        # Use base64 encoding to safely write content (matches TS adapter)
        import base64 as b64mod
        data = content if isinstance(content, bytes) else content.encode()
        encoded = b64mod.b64encode(data).decode()
        cmd = shell_escape("sh", ["-c", 'printf "%s" "$1" | base64 -d > "$2"', "_", encoded, path])
        result = await self._sb.process.exec({
            "command": cmd,
            "wait_for_completion": True,
            "timeout": 60,
        })
        exit_code = getattr(result, "exit_code", 0) or 0
        if exit_code != 0:
            stderr = getattr(result, "stderr", "") or ""
            raise RuntimeError(f"writeFile failed (exit {exit_code}): {stderr}")

    async def read_file(self, path: str) -> str:
        cmd = shell_escape("cat", [path])
        result = await self._sb.process.exec({
            "command": cmd,
            "wait_for_completion": True,
            "timeout": 60,
        })
        exit_code = getattr(result, "exit_code", 0) or 0
        if exit_code != 0:
            stderr = getattr(result, "stderr", "") or ""
            raise RuntimeError(f"readFile failed (exit {exit_code}): {stderr}")
        return getattr(result, "stdout", "") or ""

    async def stop(self) -> None:
        await self._sb.delete()

    async def file_exists(self, path: str) -> bool:
        result = await self.exec("test", ["-f", path])
        return result.exit_code == 0
