from unittest.mock import MagicMock

from deerflow.community.aio_sandbox.local_backend import LocalContainerBackend, _format_container_mount


def test_format_container_mount_uses_mount_syntax_for_docker_windows_paths():
    args = _format_container_mount("docker", "D:/deer-flow/backend/.deer-flow/threads", "/mnt/threads", False)

    assert args == [
        "--mount",
        "type=bind,src=D:/deer-flow/backend/.deer-flow/threads,dst=/mnt/threads",
    ]


def test_format_container_mount_marks_docker_readonly_mounts():
    args = _format_container_mount("docker", "/host/path", "/mnt/path", True)

    assert args == [
        "--mount",
        "type=bind,src=/host/path,dst=/mnt/path,readonly",
    ]


def test_format_container_mount_keeps_volume_syntax_for_apple_container():
    args = _format_container_mount("container", "/host/path", "/mnt/path", True)

    assert args == [
        "-v",
        "/host/path:/mnt/path:ro",
    ]


# ── extra_env injection ──────────────────────────────────────────────────────


def _make_backend(runtime: str = "docker") -> LocalContainerBackend:
    """Build a minimal LocalContainerBackend without real config."""
    backend = LocalContainerBackend.__new__(LocalContainerBackend)
    backend._runtime = runtime
    backend._container_prefix = "test"
    backend._environment = {}
    backend._config_mounts = []
    backend._base_port = 9000
    backend._image = "test-image:latest"
    return backend


def test_start_container_injects_extra_env(monkeypatch):
    """_start_container must append -e KEY=VALUE for each extra_env entry."""
    backend = _make_backend()

    captured: list[list[str]] = []

    def fake_run(cmd, **_kwargs):
        captured.append(list(cmd))
        result = MagicMock()
        result.returncode = 0
        result.stdout = "fake-container-id\n"
        return result

    monkeypatch.setattr("deerflow.community.aio_sandbox.local_backend.subprocess.run", fake_run)

    backend._start_container("c", 9000, extra_env={"THREAD_ID": "thread-abc", "FOO": "bar"})

    cmd = captured[0]
    assert "-e" in cmd
    env_pairs = {cmd[i + 1] for i in range(len(cmd)) if cmd[i] == "-e"}
    assert "THREAD_ID=thread-abc" in env_pairs
    assert "FOO=bar" in env_pairs


def test_start_container_no_extra_env_does_not_inject(monkeypatch):
    """_start_container with no extra_env must not add unexpected -e flags."""
    backend = _make_backend()

    captured: list[list[str]] = []

    def fake_run(cmd, **_kwargs):
        captured.append(list(cmd))
        result = MagicMock()
        result.returncode = 0
        result.stdout = "fake-container-id\n"
        return result

    monkeypatch.setattr("deerflow.community.aio_sandbox.local_backend.subprocess.run", fake_run)

    backend._start_container("c", 9000)

    cmd = captured[0]
    env_pairs = {cmd[i + 1] for i in range(len(cmd)) if cmd[i] == "-e"}
    assert all("THREAD_ID" not in pair for pair in env_pairs)


def test_start_container_extra_env_overrides_static_env(monkeypatch):
    """Runtime extra_env values must appear after static env, effectively overriding same-key entries."""
    backend = _make_backend()
    backend._environment = {"MY_VAR": "static"}

    captured: list[list[str]] = []

    def fake_run(cmd, **_kwargs):
        captured.append(list(cmd))
        result = MagicMock()
        result.returncode = 0
        result.stdout = "fake-container-id\n"
        return result

    monkeypatch.setattr("deerflow.community.aio_sandbox.local_backend.subprocess.run", fake_run)

    backend._start_container("c", 9000, extra_env={"MY_VAR": "runtime"})

    cmd = captured[0]
    env_pairs = [cmd[i + 1] for i in range(len(cmd)) if cmd[i] == "-e"]
    # Both entries should be present; the runtime one comes after, which Docker respects
    assert "MY_VAR=static" in env_pairs
    assert "MY_VAR=runtime" in env_pairs
    assert env_pairs.index("MY_VAR=runtime") > env_pairs.index("MY_VAR=static")
