"""Subprocess runner for the management-code-setup step."""
from __future__ import annotations

import queue
import subprocess
import threading
from pathlib import Path
from typing import Optional

DPG_ROOT = Path(__file__).resolve().parent.parent


class SetupRunner:
    def __init__(self) -> None:
        self.events: queue.Queue = queue.Queue()
        self._proc: Optional[subprocess.Popen] = None
        self.is_running = False
        self.return_code: Optional[int] = None

    def start(self, project_slug: str | None = None, efs_env: str | None = None, project_dir: str | None = None) -> None:
        if self.is_running:
            return
        cmd = [
            "uv", "run", "python",
            "pipeline/management-code/run.py",
            "--execute-setup",
        ]
        if project_dir:
            cmd += ["--project-dir", project_dir]
        elif project_slug:
            cmd += ["--run-id", project_slug]
            if efs_env:
                cmd += ["--efs-env", efs_env]
        import os
        env = os.environ.copy()
        env.pop("VIRTUAL_ENV", None)
        env["PYTHONUNBUFFERED"] = "1"
        self._proc = subprocess.Popen(
            cmd, cwd=str(DPG_ROOT),
            stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
            text=True, bufsize=1, env=env,
        )
        self.is_running = True
        self.return_code = None
        threading.Thread(target=self._read, daemon=True).start()

    def drain(self) -> list[dict]:
        events: list[dict] = []
        try:
            while True:
                events.append(self.events.get_nowait())
        except queue.Empty:
            pass
        return events

    def terminate(self) -> None:
        if self._proc and self.is_running:
            self._proc.terminate()
        self.is_running = False

    def _read(self) -> None:
        try:
            assert self._proc and self._proc.stdout
            for raw in self._proc.stdout:
                line = raw.rstrip()
                if line:
                    self.events.put({"type": "log", "text": line})
                    if "[setup] Done →" in line:
                        self.events.put({"type": "setup_done"})
                    elif "[setup] FAILED" in line:
                        self.events.put({"type": "setup_error", "text": line})
            self._proc.wait()
            self.return_code = self._proc.returncode
            self.is_running = False
            self.events.put({"type": "finished", "return_code": self._proc.returncode})
        except Exception as exc:
            self.is_running = False
            self.events.put({"type": "error", "text": str(exc)})
