"""The tests the cover command line platform."""
from __future__ import annotations

import os
import tempfile
from typing import Any
from unittest.mock import patch

from pytest import LogCaptureFixture

from homeassistant import config as hass_config, setup
from homeassistant.components.cover import DOMAIN, SCAN_INTERVAL
from homeassistant.const import (
    ATTR_ENTITY_ID,
    SERVICE_CLOSE_COVER,
    SERVICE_OPEN_COVER,
    SERVICE_RELOAD,
    SERVICE_STOP_COVER,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry
import homeassistant.util.dt as dt_util

from tests.common import async_fire_time_changed, get_fixture_path


async def setup_test_entity(hass: HomeAssistant, config_dict: dict[str, Any]) -> None:
    """Set up a test command line notify service."""
    assert await setup.async_setup_component(
        hass,
        DOMAIN,
        {
            DOMAIN: [
                {"platform": "command_line", "covers": config_dict},
            ]
        },
    )
    await hass.async_block_till_done()


async def test_no_covers(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
    """Test that the cover does not polls when there's no state command."""

    with patch(
        "homeassistant.components.command_line.subprocess.check_output",
        return_value=b"50\n",
    ):
        await setup_test_entity(hass, {})
        assert "No covers added" in caplog.text


async def test_no_poll_when_cover_has_no_command_state(hass: HomeAssistant) -> None:
    """Test that the cover does not polls when there's no state command."""

    with patch(
        "homeassistant.components.command_line.subprocess.check_output",
        return_value=b"50\n",
    ) as check_output:
        await setup_test_entity(hass, {"test": {}})
        async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
        await hass.async_block_till_done()
        assert not check_output.called


async def test_poll_when_cover_has_command_state(hass: HomeAssistant) -> None:
    """Test that the cover polls when there's a state  command."""

    with patch(
        "homeassistant.components.command_line.subprocess.check_output",
        return_value=b"50\n",
    ) as check_output:
        await setup_test_entity(hass, {"test": {"command_state": "echo state"}})
        async_fire_time_changed(hass, dt_util.utcnow() + SCAN_INTERVAL)
        await hass.async_block_till_done()
        check_output.assert_called_once_with(
            "echo state", shell=True, timeout=15  # nosec # shell by design
        )


async def test_state_value(hass: HomeAssistant) -> None:
    """Test with state value."""
    with tempfile.TemporaryDirectory() as tempdirname:
        path = os.path.join(tempdirname, "cover_status")
        await setup_test_entity(
            hass,
            {
                "test": {
                    "command_state": f"cat {path}",
                    "command_open": f"echo 1 > {path}",
                    "command_close": f"echo 1 > {path}",
                    "command_stop": f"echo 0 > {path}",
                    "value_template": "{{ value }}",
                }
            },
        )

        entity_state = hass.states.get("cover.test")
        assert entity_state
        assert entity_state.state == "unknown"

        await hass.services.async_call(
            DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: "cover.test"}, blocking=True
        )
        entity_state = hass.states.get("cover.test")
        assert entity_state
        assert entity_state.state == "open"

        await hass.services.async_call(
            DOMAIN, SERVICE_CLOSE_COVER, {ATTR_ENTITY_ID: "cover.test"}, blocking=True
        )
        entity_state = hass.states.get("cover.test")
        assert entity_state
        assert entity_state.state == "open"

        await hass.services.async_call(
            DOMAIN, SERVICE_STOP_COVER, {ATTR_ENTITY_ID: "cover.test"}, blocking=True
        )
        entity_state = hass.states.get("cover.test")
        assert entity_state
        assert entity_state.state == "closed"


async def test_reload(hass: HomeAssistant) -> None:
    """Verify we can reload command_line covers."""

    await setup_test_entity(
        hass,
        {
            "test": {
                "command_state": "echo open",
                "value_template": "{{ value }}",
            }
        },
    )
    entity_state = hass.states.get("cover.test")
    assert entity_state
    assert entity_state.state == "unknown"

    yaml_path = get_fixture_path("configuration.yaml", "command_line")
    with patch.object(hass_config, "YAML_CONFIG_FILE", yaml_path):
        await hass.services.async_call(
            "command_line",
            SERVICE_RELOAD,
            {},
            blocking=True,
        )
        await hass.async_block_till_done()

    assert len(hass.states.async_all()) == 1

    assert not hass.states.get("cover.test")
    assert hass.states.get("cover.from_yaml")


async def test_move_cover_failure(
    caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
    """Test with state value."""

    await setup_test_entity(
        hass,
        {"test": {"command_open": "exit 1"}},
    )
    await hass.services.async_call(
        DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: "cover.test"}, blocking=True
    )
    assert "Command failed" in caplog.text


async def test_unique_id(hass: HomeAssistant) -> None:
    """Test unique_id option and if it only creates one cover per id."""
    await setup_test_entity(
        hass,
        {
            "unique": {
                "command_open": "echo open",
                "command_close": "echo close",
                "command_stop": "echo stop",
                "unique_id": "unique",
            },
            "not_unique_1": {
                "command_open": "echo open",
                "command_close": "echo close",
                "command_stop": "echo stop",
                "unique_id": "not-so-unique-anymore",
            },
            "not_unique_2": {
                "command_open": "echo open",
                "command_close": "echo close",
                "command_stop": "echo stop",
                "unique_id": "not-so-unique-anymore",
            },
        },
    )

    assert len(hass.states.async_all()) == 2

    ent_reg = entity_registry.async_get(hass)

    assert len(ent_reg.entities) == 2
    assert ent_reg.async_get_entity_id("cover", "command_line", "unique") is not None
    assert (
        ent_reg.async_get_entity_id("cover", "command_line", "not-so-unique-anymore")
        is not None
    )
