"""Test docker events monitor."""

import asyncio
from typing import Any, Optional
from unittest.mock import MagicMock, PropertyMock, patch

from awesomeversion import AwesomeVersion
from docker.models.containers import Container
import pytest

from supervisor.const import BusEvent
from supervisor.coresys import CoreSys
from supervisor.docker.const import ContainerState
from supervisor.docker.monitor import DockerContainerStateEvent


@pytest.mark.parametrize(
    "event,expected",
    [
        (
            {
                "Type": "container",
                "Action": "start",
                "Actor": {"Attributes": {"supervisor_managed": ""}},
            },
            ContainerState.RUNNING,
        ),
        (
            {
                "Type": "container",
                "Action": "die",
                "Actor": {"Attributes": {"supervisor_managed": "", "exitCode": "0"}},
            },
            ContainerState.STOPPED,
        ),
        (
            {
                "Type": "container",
                "Action": "die",
                "Actor": {"Attributes": {"supervisor_managed": "", "exitCode": "137"}},
            },
            ContainerState.FAILED,
        ),
        (
            {
                "Type": "container",
                "Action": "health_status: healthy",
                "Actor": {"Attributes": {"supervisor_managed": ""}},
            },
            ContainerState.HEALTHY,
        ),
        (
            {
                "Type": "container",
                "Action": "health_status: unhealthy",
                "Actor": {"Attributes": {"supervisor_managed": ""}},
            },
            ContainerState.UNHEALTHY,
        ),
        (
            {
                "Type": "container",
                "Action": "exec_die",
                "Actor": {"Attributes": {"supervisor_managed": ""}},
            },
            None,
        ),
        (
            {
                "Type": "container",
                "Action": "start",
                "Actor": {"Attributes": {}},
            },
            None,
        ),
        (
            {
                "Type": "network",
                "Action": "start",
                "Actor": {"Attributes": {}},
            },
            None,
        ),
    ],
)
async def test_events(
    coresys: CoreSys, event: dict[str, Any], expected: Optional[ContainerState]
):
    """Test events created from docker events."""
    event["Actor"]["Attributes"]["name"] = "some_container"
    event["id"] = "abc123"
    event["time"] = 123
    with patch(
        "supervisor.docker.manager.DockerAPI.events",
        new=PropertyMock(return_value=[event]),
    ), patch.object(type(coresys.bus), "fire_event") as fire_event:
        await coresys.docker.monitor.load()
        await asyncio.sleep(0.1)
        if expected:
            fire_event.assert_called_once_with(
                BusEvent.DOCKER_CONTAINER_STATE_CHANGE,
                DockerContainerStateEvent("some_container", expected, "abc123", 123),
            )
        else:
            fire_event.assert_not_called()


async def test_unlabeled_container(coresys: CoreSys):
    """Test attaching to unlabeled container is still watched."""
    container_collection = MagicMock()
    container_collection.get.return_value = Container(
        {
            "Name": "homeassistant",
            "Id": "abc123",
            "State": {"Status": "running"},
            "Config": {},
        }
    )
    with patch(
        "supervisor.docker.manager.DockerAPI.containers",
        new=PropertyMock(return_value=container_collection),
    ):
        await coresys.homeassistant.core.instance.attach(AwesomeVersion("2022.7.3"))

    with patch(
        "supervisor.docker.manager.DockerAPI.events",
        new=PropertyMock(
            return_value=[
                {
                    "id": "abc123",
                    "time": 123,
                    "Type": "container",
                    "Action": "die",
                    "Actor": {
                        "Attributes": {"name": "homeassistant", "exitCode": "137"}
                    },
                }
            ]
        ),
    ), patch.object(type(coresys.bus), "fire_event") as fire_event:
        await coresys.docker.monitor.load()
        await asyncio.sleep(0.1)
        fire_event.assert_called_once_with(
            BusEvent.DOCKER_CONTAINER_STATE_CHANGE,
            DockerContainerStateEvent(
                "homeassistant", ContainerState.FAILED, "abc123", 123
            ),
        )