"""
Process backend for Lazarus Pit.

Fastest spawn/teardown. Isolation comes from unique HERMES_HOME
and independent Python process. No containers required.
"""

import os
import signal
import subprocess
from pathlib import Path
from typing import Optional

from .base import Backend, BackendResult


class ProcessBackend(Backend):
    name = "process"

    def __init__(self, log_dir: Optional[str] = None):
        self.log_dir = Path(log_dir or "/tmp/lazarus-logs")
        self.log_dir.mkdir(parents=True, exist_ok=True)
        self._pids: dict = {}

    def _log_path(self, cell_id: str) -> Path:
        return self.log_dir / f"{cell_id}.log"

    def spawn(self, cell_id: str, hermes_home: str, command: list, env: Optional[dict] = None) -> BackendResult:
        log_path = self._log_path(cell_id)
        run_env = dict(os.environ)
        run_env["HERMES_HOME"] = hermes_home
        if env:
            run_env.update(env)

        try:
            with open(log_path, "a") as log_file:
                proc = subprocess.Popen(
                    command,
                    env=run_env,
                    stdout=log_file,
                    stderr=subprocess.STDOUT,
                    cwd=hermes_home,
                )
            self._pids[cell_id] = proc.pid
            return BackendResult(
                success=True,
                pid=proc.pid,
                message=f"Spawned {cell_id} with pid {proc.pid}",
            )
        except Exception as e:
            return BackendResult(success=False, stderr=str(e), message=f"Spawn failed: {e}")

    def probe(self, cell_id: str) -> BackendResult:
        pid = self._pids.get(cell_id)
        if not pid:
            return BackendResult(success=False, message="No known pid for cell")
        try:
            os.kill(pid, 0)
            return BackendResult(success=True, pid=pid, message="Process is alive")
        except OSError:
            return BackendResult(success=False, pid=pid, message="Process is dead")

    def logs(self, cell_id: str, tail: int = 50) -> BackendResult:
        log_path = self._log_path(cell_id)
        if not log_path.exists():
            return BackendResult(success=True, stdout="", message="No logs yet")
        try:
            lines = log_path.read_text().splitlines()
            return BackendResult(
                success=True,
                stdout="\n".join(lines[-tail:]),
                message=f"Returned last {tail} lines",
            )
        except Exception as e:
            return BackendResult(success=False, stderr=str(e), message=f"Log read failed: {e}")

    def close(self, cell_id: str) -> BackendResult:
        pid = self._pids.get(cell_id)
        if not pid:
            return BackendResult(success=False, message="No known pid for cell")
        try:
            os.kill(pid, signal.SIGTERM)
            return BackendResult(success=True, pid=pid, message="Sent SIGTERM")
        except OSError as e:
            return BackendResult(success=False, stderr=str(e), message=f"Close failed: {e}")

    def destroy(self, cell_id: str) -> BackendResult:
        res = self.close(cell_id)
        log_path = self._log_path(cell_id)
        if log_path.exists():
            log_path.unlink()
        self._pids.pop(cell_id, None)
        return BackendResult(
            success=res.success,
            pid=res.pid,
            message=f"Destroyed {cell_id}",
        )
