import os

import pytest
from pytest_mock import MockerFixture
from pytest_subprocess import FakeProcess

from dangerzone.isolation_provider.container import (
    Container,
    ImageInstallationException,
    ImageNotPresentException,
    NotAvailableContainerTechException,
)
from dangerzone.isolation_provider.qubes import is_qubes_native_conversion

from .base import IsolationProviderTermination, IsolationProviderTest

# Run the tests in this module only if we can spawn containers.
if is_qubes_native_conversion():
    pytest.skip("Qubes native conversion is enabled", allow_module_level=True)
elif os.environ.get("DUMMY_CONVERSION", False):
    pytest.skip("Dummy conversion is enabled", allow_module_level=True)


@pytest.fixture
def provider() -> Container:
    return Container()


class TestContainer(IsolationProviderTest):
    def test_is_runtime_available_raises(
        self, provider: Container, fp: FakeProcess
    ) -> None:
        """
        NotAvailableContainerTechException should be raised when
        the "podman image ls" command fails.
        """
        fp.register_subprocess(
            [provider.get_runtime(), "image", "ls"],
            returncode=-1,
            stderr="podman image ls logs",
        )
        with pytest.raises(NotAvailableContainerTechException):
            provider.is_runtime_available()

    def test_is_runtime_available_works(
        self, provider: Container, fp: FakeProcess
    ) -> None:
        """
        No exception should be raised when the "podman image ls" can return properly.
        """
        fp.register_subprocess(
            [provider.get_runtime(), "image", "ls"],
        )
        provider.is_runtime_available()

    def test_install_raise_if_image_cant_be_installed(
        self, mocker: MockerFixture, provider: Container, fp: FakeProcess
    ) -> None:
        """When an image installation fails, an exception should be raised"""

        fp.register_subprocess(
            [provider.get_runtime(), "image", "ls"],
        )

        # First check should return nothing.
        fp.register_subprocess(
            [
                provider.get_runtime(),
                "image",
                "list",
                "--format",
                "{{.ID}}",
                "dangerzone.rocks/dangerzone",
            ],
            occurrences=2,
        )

        # Make podman load fail
        mocker.patch("gzip.open", mocker.mock_open(read_data=""))

        fp.register_subprocess(
            [provider.get_runtime(), "load"],
            returncode=-1,
        )

        with pytest.raises(ImageInstallationException):
            provider.install()

    def test_install_raises_if_still_not_installed(
        self, mocker: MockerFixture, provider: Container, fp: FakeProcess
    ) -> None:
        """When an image keep being not installed, it should return False"""

        fp.register_subprocess(
            [provider.get_runtime(), "image", "ls"],
        )

        # First check should return nothing.
        fp.register_subprocess(
            [
                provider.get_runtime(),
                "image",
                "list",
                "--format",
                "{{.ID}}",
                "dangerzone.rocks/dangerzone",
            ],
            occurrences=2,
        )

        # Patch gzip.open and podman load so that it works
        mocker.patch("gzip.open", mocker.mock_open(read_data=""))
        fp.register_subprocess(
            [provider.get_runtime(), "load"],
        )
        with pytest.raises(ImageNotPresentException):
            provider.install()


class TestContainerTermination(IsolationProviderTermination):
    pass
