import subprocess

import pytest

from l4d2host.steam_install import SteamInstaller


def test_windows_then_linux(tmp_path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setenv("HOME", str(tmp_path / "home"))
    monkeypatch.setenv("LEFT4ME_ROOT", str(tmp_path))
    calls: list[list[str]] = []

    def fake_run_command(cmd, **kwargs):
        del kwargs
        calls.append(list(cmd))

    monkeypatch.setattr("l4d2host.steam_install.run_command", fake_run_command)
    SteamInstaller().install_or_update()
    assert "windows" in calls[0]
    assert "linux" in calls[1]


def test_fail_fast_on_first_failure(monkeypatch: pytest.MonkeyPatch) -> None:
    calls: list[list[str]] = []

    def fake_run_command(cmd, **kwargs):
        del kwargs
        calls.append(list(cmd))
        if len(calls) == 1:
            raise subprocess.CalledProcessError(returncode=1, cmd=cmd)

    monkeypatch.setattr("l4d2host.steam_install.run_command", fake_run_command)

    with pytest.raises(subprocess.CalledProcessError):
        SteamInstaller().install_or_update()

    assert len(calls) == 1


def test_default_install_dir_uses_left4me_root(tmp_path, monkeypatch):
    monkeypatch.setenv("HOME", str(tmp_path / "home"))
    monkeypatch.setenv("LEFT4ME_ROOT", str(tmp_path))
    calls = []
    monkeypatch.setattr("l4d2host.steam_install.run_command", lambda cmd, **kwargs: calls.append(cmd))

    SteamInstaller().install_or_update()

    assert str(tmp_path / "installation") in calls[0]


def test_steam_installer_emits_steps(tmp_path, monkeypatch) -> None:
    monkeypatch.setenv("LEFT4ME_ROOT", str(tmp_path))
    monkeypatch.setenv("HOME", str(tmp_path / "home"))
    monkeypatch.setattr("l4d2host.steam_install.run_command", lambda cmd, **kwargs: None)

    steps: list[str] = []

    from l4d2host.steam_install import SteamInstaller
    SteamInstaller().install_or_update(on_stdout=steps.append)

    assert steps == [
        "Step: downloading windows platform payload...",
        "Step: downloading linux platform payload...",
        "Step: ensuring steam sdk symlinks...",
        "Step: installation complete."
    ]


def test_install_creates_steam_sdk_symlinks_to_steamcmd_siblings(tmp_path, monkeypatch) -> None:
    home = tmp_path / "home"
    home.mkdir()
    monkeypatch.setenv("HOME", str(home))
    monkeypatch.setenv("LEFT4ME_ROOT", str(tmp_path))

    steamcmd_dir = tmp_path / "opt" / "steamcmd"
    (steamcmd_dir / "linux32").mkdir(parents=True)
    (steamcmd_dir / "linux64").mkdir(parents=True)
    fake_steamcmd = steamcmd_dir / "steamcmd.sh"
    fake_steamcmd.write_text("#!/bin/sh\nexit 0\n")
    fake_steamcmd.chmod(0o755)

    monkeypatch.setattr("l4d2host.steam_install.run_command", lambda cmd, **kwargs: None)

    from l4d2host.steam_install import SteamInstaller
    SteamInstaller(steamcmd=str(fake_steamcmd)).install_or_update()

    sdk32 = home / ".steam" / "sdk32"
    sdk64 = home / ".steam" / "sdk64"
    assert sdk32.is_symlink()
    assert sdk64.is_symlink()
    assert sdk32.resolve() == (steamcmd_dir / "linux32").resolve()
    assert sdk64.resolve() == (steamcmd_dir / "linux64").resolve()


def test_install_creates_steam_sdk_symlinks_falls_back_to_install_bin(tmp_path, monkeypatch) -> None:
    home = tmp_path / "home"
    home.mkdir()
    monkeypatch.setenv("HOME", str(home))
    monkeypatch.setenv("LEFT4ME_ROOT", str(tmp_path))

    install_bin = tmp_path / "installation" / "bin"
    install_bin.mkdir(parents=True)

    isolated_dir = tmp_path / "no-siblings"
    isolated_dir.mkdir()
    fake_steamcmd = isolated_dir / "steamcmd.sh"
    fake_steamcmd.write_text("#!/bin/sh\nexit 0\n")
    fake_steamcmd.chmod(0o755)

    monkeypatch.setattr("l4d2host.steam_install.run_command", lambda cmd, **kwargs: None)

    from l4d2host.steam_install import SteamInstaller
    SteamInstaller(steamcmd=str(fake_steamcmd)).install_or_update()

    sdk32 = home / ".steam" / "sdk32"
    sdk64 = home / ".steam" / "sdk64"
    assert sdk32.resolve() == install_bin.resolve()
    assert sdk64.resolve() == install_bin.resolve()


def test_install_steam_sdk_symlinks_is_idempotent(tmp_path, monkeypatch) -> None:
    home = tmp_path / "home"
    home.mkdir()
    monkeypatch.setenv("HOME", str(home))
    monkeypatch.setenv("LEFT4ME_ROOT", str(tmp_path))

    steamcmd_dir = tmp_path / "opt" / "steamcmd"
    (steamcmd_dir / "linux32").mkdir(parents=True)
    (steamcmd_dir / "linux64").mkdir(parents=True)
    fake_steamcmd = steamcmd_dir / "steamcmd.sh"
    fake_steamcmd.write_text("#!/bin/sh\nexit 0\n")
    fake_steamcmd.chmod(0o755)

    monkeypatch.setattr("l4d2host.steam_install.run_command", lambda cmd, **kwargs: None)

    from l4d2host.steam_install import SteamInstaller
    installer = SteamInstaller(steamcmd=str(fake_steamcmd))
    installer.install_or_update()
    installer.install_or_update()

    sdk32 = home / ".steam" / "sdk32"
    assert sdk32.resolve() == (steamcmd_dir / "linux32").resolve()
