"""Shared fixtures for installer E2E tests."""

from __future__ import annotations

import os
import stat
import subprocess
from dataclasses import dataclass
from pathlib import Path
from typing import Any

import pytest

INSTALLER_DIR = Path(__file__).resolve().parent.parent.parent / "installer"
INSTALL_SH = INSTALLER_DIR / "install.sh"
INSTALL_PS1 = INSTALLER_DIR / "install.ps1"


@dataclass(frozen=True)
class ScriptResult:
    """Result from running an installer script."""

    returncode: int
    stdout: str
    stderr: str

    @property
    def output(self) -> str:
        return self.stdout + self.stderr


def write_fake_cmd(directory: Path, name: str, script: str) -> Path:
    """Create an executable bash stub in the given directory."""
    p = directory / name
    p.write_text(f"#!/usr/bin/env bash\n{script}\n")
    p.chmod(p.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
    return p


@pytest.fixture()
def fake_bin(tmp_path: Path) -> Path:
    """Directory for fake command stubs, prepended to PATH."""
    d = tmp_path / "fake_bin"
    d.mkdir()
    return d


@pytest.fixture()
def sandbox(tmp_path: Path, fake_bin: Path) -> dict[str, str]:
    """Isolated environment dict for running install.sh.

    - HOME points to tmp
    - SHELL is /bin/bash
    - ILUM_VERSION is pinned (avoids GitHub API calls)
    - PATH has fake_bin first
    """
    home = tmp_path / "home"
    home.mkdir()

    install_dir = tmp_path / "install_bin"
    install_dir.mkdir()

    env = {
        "HOME": str(home),
        "SHELL": "/bin/bash",
        "ILUM_VERSION": "0.3.0",
        "PATH": f"{fake_bin}:{os.environ.get('PATH', '/usr/bin:/bin')}",
        "TERM": "dumb",
        "ILUM_INSTALL_DIR": str(install_dir),
    }
    return env


@pytest.fixture()
def run_installer(sandbox: dict[str, str]) -> Any:
    """Callable fixture that runs install.sh with the sandbox env.

    Usage:
        result = run_installer()                        # no args
        result = run_installer("--version", "1.2.3")    # with args
        result = run_installer(env_override={"SHELL": "/bin/zsh"})
    """

    def _run(
        *args: str,
        env_override: dict[str, str] | None = None,
        input_text: str | None = None,
    ) -> ScriptResult:
        env = dict(sandbox)
        if env_override:
            env.update(env_override)
        proc = subprocess.run(
            ["bash", str(INSTALL_SH), *args],
            capture_output=True,
            text=True,
            env=env,
            timeout=30,
            input=input_text,
        )
        return ScriptResult(
            returncode=proc.returncode,
            stdout=proc.stdout,
            stderr=proc.stderr,
        )

    return _run
