"""Tests for `mgf.common.testing._paths` — parallel-safe socket paths."""

from __future__ import annotations

import tempfile
from pathlib import Path

import pytest

from mgf.common.testing import default_sock_path


class TestDefaultSockPathBasic:
    def test_returns_path_object(self) -> None:
        result = default_sock_path("myapp")
        assert isinstance(result, Path)

    def test_main_worker_when_no_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.delenv("PYTEST_XDIST_WORKER", raising=False)
        result = default_sock_path("myapp")
        assert result.name == "myapp-main.sock"

    def test_xdist_worker_picked_up_from_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.setenv("PYTEST_XDIST_WORKER", "gw3")
        result = default_sock_path("myapp")
        assert result.name == "myapp-gw3.sock"

    def test_explicit_worker_overrides_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.setenv("PYTEST_XDIST_WORKER", "gw3")
        result = default_sock_path("myapp", worker="explicit")
        assert result.name == "myapp-explicit.sock"

    def test_default_tmpdir_is_system_temp(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.delenv("PYTEST_XDIST_WORKER", raising=False)
        result = default_sock_path("myapp")
        assert result.parent == Path(tempfile.gettempdir())

    def test_explicit_tmpdir(self, tmp_path: Path) -> None:
        result = default_sock_path("myapp", tmpdir=tmp_path, worker="test")
        assert result == tmp_path / "myapp-test.sock"


class TestPrefixSafety:
    @pytest.mark.parametrize(
        "good_prefix",
        ["myapp", "mgf-hrb-server", "MyApp", "app_123", "v2", "a-b_c-d"],
    )
    def test_safe_prefixes_accepted(self, good_prefix: str) -> None:
        result = default_sock_path(good_prefix)
        assert good_prefix in result.name

    @pytest.mark.parametrize(
        "bad_prefix",
        [
            "",  # empty
            "myapp/server",  # path separator
            "../escape",  # path traversal
            "myapp\x00",  # NUL injection
            "myapp space",  # whitespace
            "myapp;rm -rf /",  # shell metachar
            "myapp.sock",  # dot — could be confused with extension
        ],
    )
    def test_unsafe_prefixes_rejected(self, bad_prefix: str) -> None:
        with pytest.raises(ValueError, match="filesystem-safe"):
            default_sock_path(bad_prefix)


class TestWorkerSafety:
    @pytest.mark.parametrize(
        "bad_worker",
        ["gw0/escape", "../etc", "main spaces", "gw\x00"],
    )
    def test_unsafe_worker_rejected(self, bad_worker: str) -> None:
        with pytest.raises(ValueError, match="filesystem-safe"):
            default_sock_path("myapp", worker=bad_worker)

    def test_unsafe_env_worker_also_rejected(self, monkeypatch: pytest.MonkeyPatch) -> None:
        # If a malicious PYTEST_XDIST_WORKER env var is set, the
        # helper rejects it rather than silently writing to an
        # unexpected path.
        monkeypatch.setenv("PYTEST_XDIST_WORKER", "../etc/shadow")
        with pytest.raises(ValueError, match="filesystem-safe"):
            default_sock_path("myapp")


class TestParallelDisambiguation:
    def test_different_workers_get_different_paths(self) -> None:
        a = default_sock_path("myapp", worker="gw0")
        b = default_sock_path("myapp", worker="gw1")
        assert a != b

    def test_same_worker_gets_same_path(self) -> None:
        # Determinism — caller can call this twice and get the same
        # answer, so spawn/cleanup pair up.
        a = default_sock_path("myapp", worker="gw0")
        b = default_sock_path("myapp", worker="gw0")
        assert a == b

    def test_different_prefixes_get_different_paths(self) -> None:
        a = default_sock_path("app-one", worker="gw0")
        b = default_sock_path("app-two", worker="gw0")
        assert a != b
