"""Unit tests for docker service utilities."""

from unittest.mock import MagicMock, patch

import logging

from src.services.docker.container import (
    get_container_id,
    get_container_name,
)
from src.services.docker.compose import sort_volumes_by_specificity


class TestGetContainerId:
    """Tests for get_container_id."""

    @patch("subprocess.run")
    def test_lowercases_name_for_filter(self, mock_run) -> None:
        """Docker inspect is case-sensitive; we must lowercase the name."""
        mock_run.return_value = MagicMock(returncode=0, stdout="abc123\n")

        result = get_container_id("MyContainer-ABC")

        assert result == "abc123"
        call_args = mock_run.call_args[0][0]
        # Exact inspect call uses lowercase
        assert call_args == ["docker", "inspect", "-f", "{{.Id}}", "mycontainer-abc"]

    @patch("subprocess.run")
    def test_returns_none_when_not_found(self, mock_run) -> None:
        mock_run.return_value = MagicMock(returncode=0, stdout="")

        result = get_container_id("missing")

        assert result is None


class TestGetContainerName:
    """Tests for get_container_name."""

    @patch("subprocess.run")
    def test_lowercases_name_for_filter(self, mock_run) -> None:
        """Docker inspect is case-sensitive; we must lowercase the name."""
        mock_run.return_value = MagicMock(returncode=0, stdout="mycontainer-abc\n")

        result = get_container_name("MyContainer-ABC")

        assert result == "mycontainer-abc"
        call_args = mock_run.call_args[0][0]
        assert call_args == ["docker", "inspect", "-f", "{{.Name}}", "mycontainer-abc"]

    @patch("subprocess.run")
    def test_returns_none_when_not_found(self, mock_run) -> None:
        mock_run.return_value = MagicMock(returncode=0, stdout="")

        result = get_container_name("missing")

        assert result is None


class TestSortVolumesBySpecificity:
    """Tests for sort_volumes_by_specificity."""

    def test_parent_before_child(self) -> None:
        """A repo mount to /workspace/x should come before a file mount to /workspace/x/y/config.json."""
        volumes = [
            "/repo/x/y/config.json:/workspace/x/y/config.json",
            "/repo/x:/workspace/x",
        ]
        result = sort_volumes_by_specificity(volumes)
        assert result[0] == "/repo/x:/workspace/x"
        assert result[1] == "/repo/x/y/config.json:/workspace/x/y/config.json"

    def test_stable_sort_for_equal_depth(self) -> None:
        """Mounts at the same depth preserve input order."""
        volumes = [
            "/a:/workspace/a",
            "/b:/workspace/b",
            "/c:/workspace/c",
        ]
        result = sort_volumes_by_specificity(volumes)
        assert result == volumes

    def test_with_type_suffix(self) -> None:
        """Volume strings with :bind or :ro suffixes are parsed correctly."""
        volumes = [
            "/repo/x/y/config.json:/workspace/x/y/config.json:bind",
            "/repo/x:/workspace/x:bind",
        ]
        result = sort_volumes_by_specificity(volumes)
        assert result[0] == "/repo/x:/workspace/x:bind"
        assert result[1] == "/repo/x/y/config.json:/workspace/x/y/config.json:bind"

    def test_empty_list(self) -> None:
        """Empty list returns empty list."""
        assert sort_volumes_by_specificity([]) == []

    def test_single_volume(self) -> None:
        """Single volume returns unchanged."""
        volumes = ["/repo:/workspace"]
        assert sort_volumes_by_specificity(volumes) == volumes

    def test_duplicate_target_warning(self, caplog) -> None:
        """Duplicate targets trigger a warning."""
        with caplog.at_level(logging.WARNING, logger="src.services.docker"):
            volumes = [
                "/a:/workspace/x",
                "/b:/workspace/x",
            ]
            sort_volumes_by_specificity(volumes)
        assert "Duplicate mount targets detected" in caplog.text
        assert "/workspace/x" in caplog.text
