"""Tests for tacoshop.runner."""

from __future__ import annotations

import os

import pytest

from tacoshop.cli import ParseResult
from tacoshop.config import Config, FlagVar, StaticVar
from tacoshop.runner import _apply_var, build_env, run_command


class TestApplyVar:
    def test_overwrite(self):
        env = {"X": "old"}
        _apply_var(env, "X", "new", append=False, prepend=False, separator="")
        assert env["X"] == "new"

    def test_set_new(self):
        env = {}
        _apply_var(env, "X", "val", append=False, prepend=False, separator="")
        assert env["X"] == "val"

    def test_append_to_empty(self):
        env = {}
        _apply_var(env, "X", "val", append=True, prepend=False, separator=",")
        assert env["X"] == "val"

    def test_append_with_separator(self):
        env = {"X": "a"}
        _apply_var(env, "X", "b", append=True, prepend=False, separator=",")
        assert env["X"] == "a,b"

    def test_append_existing_ends_with_separator(self):
        env = {"X": "a,"}
        _apply_var(env, "X", "b", append=True, prepend=False, separator=",")
        assert env["X"] == "a,b"

    def test_append_no_separator(self):
        env = {"X": "hello"}
        _apply_var(env, "X", "world", append=True, prepend=False, separator="")
        assert env["X"] == "helloworld"

    def test_append_colon_separator(self):
        env = {"PATH": "/usr/bin"}
        _apply_var(env, "PATH", "/extra/bin", append=True, prepend=False, separator=":")
        assert env["PATH"] == "/usr/bin:/extra/bin"

    def test_append_torch_logs_example(self):
        """Example from the plan: existing has trailing comma."""
        env = {"TORCH_LOGS": "+inductor,"}
        _apply_var(env, "TORCH_LOGS", "+dynamo,", append=True, prepend=False, separator=",")
        assert env["TORCH_LOGS"] == "+inductor,+dynamo,"

    def test_prepend_to_empty(self):
        env = {}
        _apply_var(env, "X", "val", append=False, prepend=True, separator=":")
        assert env["X"] == "val"

    def test_prepend_with_separator(self):
        env = {"PATH": "/usr/bin"}
        _apply_var(env, "PATH", "/my/bin", append=False, prepend=True, separator=":")
        assert env["PATH"] == "/my/bin:/usr/bin"

    def test_prepend_existing_starts_with_separator(self):
        env = {"X": ":rest"}
        _apply_var(env, "X", "first", append=False, prepend=True, separator=":")
        assert env["X"] == "first:rest"

    def test_prepend_no_separator(self):
        env = {"X": "world"}
        _apply_var(env, "X", "hello", append=False, prepend=True, separator="")
        assert env["X"] == "helloworld"


class TestBuildEnv:
    def test_static_vars_applied(self, monkeypatch):
        monkeypatch.delenv("MY_STATIC", raising=False)
        config = Config(
            static_vars={
                "MY_STATIC": StaticVar(name="MY_STATIC", value="42")
            }
        )
        result = ParseResult()
        env = build_env(config, result)
        assert env["MY_STATIC"] == "42"

    def test_activated_flags_applied(self, monkeypatch):
        monkeypatch.delenv("TRITON", raising=False)
        fv = FlagVar(name="TRITON", flag="--triton", value="1")
        config = Config(
            flag_vars={"TRITON": fv},
            flag_lookup={"--triton": fv},
        )
        result = ParseResult(activated_flags={"TRITON": "1"})
        env = build_env(config, result)
        assert env["TRITON"] == "1"

    def test_unactivated_flags_not_set(self, monkeypatch):
        monkeypatch.delenv("TRITON", raising=False)
        fv = FlagVar(name="TRITON", flag="--triton", value="1")
        config = Config(
            flag_vars={"TRITON": fv},
            flag_lookup={"--triton": fv},
        )
        result = ParseResult()  # no activated flags
        env = build_env(config, result)
        assert "TRITON" not in env

    def test_append_flag_var(self, monkeypatch):
        monkeypatch.setenv("LOGS", "+inductor,")
        fv = FlagVar(
            name="LOGS", flag="--logs", append=True, separator=","
        )
        config = Config(
            flag_vars={"LOGS": fv},
            flag_lookup={"--logs": fv},
        )
        result = ParseResult(activated_flags={"LOGS": "+dynamo,"})
        env = build_env(config, result)
        assert env["LOGS"] == "+inductor,+dynamo,"

    def test_prepend_flag_var(self, monkeypatch):
        monkeypatch.setenv("PATH_EXT", "/usr/bin")
        fv = FlagVar(
            name="PATH_EXT", flag="--path", prepend=True, separator=":"
        )
        config = Config(
            flag_vars={"PATH_EXT": fv},
            flag_lookup={"--path": fv},
        )
        result = ParseResult(activated_flags={"PATH_EXT": "/my/bin"})
        env = build_env(config, result)
        assert env["PATH_EXT"] == "/my/bin:/usr/bin"

    def test_inherits_existing_env(self):
        config = Config()
        result = ParseResult()
        env = build_env(config, result)
        # Should have at least PATH
        assert "PATH" in env


class TestRunCommand:
    def test_exit_code_passthrough(self):
        config = Config()
        result = ParseResult()
        with pytest.raises(SystemExit) as exc_info:
            run_command(["python", "-c", "exit(42)"], config, result)
        assert exc_info.value.code == 42

    def test_command_not_found(self, capsys):
        config = Config()
        result = ParseResult()
        with pytest.raises(SystemExit) as exc_info:
            run_command(["nonexistent_command_xyzzy"], config, result)
        assert exc_info.value.code == 127
        captured = capsys.readouterr()
        assert "command not found" in captured.err

    def test_dry_run(self, capsys):
        config = Config(
            static_vars={"X": StaticVar(name="X", value="1")}
        )
        result = ParseResult(dry_run=True)
        with pytest.raises(SystemExit) as exc_info:
            run_command(["python", "test.py"], config, result)
        assert exc_info.value.code == 0
        captured = capsys.readouterr()
        assert "X=1" in captured.err
        assert "python" in captured.err

    def test_verbose(self, capsys):
        config = Config(
            static_vars={"X": StaticVar(name="X", value="1")}
        )
        result = ParseResult(verbose=True)
        with pytest.raises(SystemExit) as exc_info:
            run_command(["python", "-c", "pass"], config, result)
        assert exc_info.value.code == 0
        captured = capsys.readouterr()
        assert "X=1" in captured.err

    def test_env_vars_visible_to_subprocess(self, monkeypatch):
        monkeypatch.delenv("TACOSHOP_TEST_VAR", raising=False)
        config = Config(
            static_vars={
                "TACOSHOP_TEST_VAR": StaticVar(
                    name="TACOSHOP_TEST_VAR", value="hello"
                )
            }
        )
        result = ParseResult()
        with pytest.raises(SystemExit) as exc_info:
            run_command(
                [
                    "python",
                    "-c",
                    "import os, sys; "
                    "v = os.environ.get('TACOSHOP_TEST_VAR', ''); "
                    "sys.exit(0 if v == 'hello' else 1)",
                ],
                config,
                result,
            )
        assert exc_info.value.code == 0
