"""Test the Blink services."""
from unittest.mock import AsyncMock, MagicMock, Mock

import pytest

from homeassistant.components.blink.const import (
    DOMAIN,
    SERVICE_REFRESH,
    SERVICE_SAVE_RECENT_CLIPS,
    SERVICE_SAVE_VIDEO,
    SERVICE_SEND_PIN,
)
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import (
    ATTR_DEVICE_ID,
    CONF_FILE_PATH,
    CONF_FILENAME,
    CONF_NAME,
    CONF_PIN,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import device_registry as dr

from tests.common import MockConfigEntry

CAMERA_NAME = "Camera 1"
FILENAME = "blah"
PIN = "1234"


async def test_refresh_service_calls(
    hass: HomeAssistant,
    device_registry: dr.DeviceRegistry,
    mock_blink_api: MagicMock,
    mock_blink_auth_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test refrest service calls."""

    mock_config_entry.add_to_hass(hass)
    assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
    await hass.async_block_till_done()

    device_entry = device_registry.async_get_device(identifiers={(DOMAIN, "12345")})

    assert device_entry

    assert mock_config_entry.state is ConfigEntryState.LOADED
    assert mock_blink_api.refresh.call_count == 1

    await hass.services.async_call(
        DOMAIN,
        SERVICE_REFRESH,
        {ATTR_DEVICE_ID: [device_entry.id]},
        blocking=True,
    )

    assert mock_blink_api.refresh.call_count == 2

    with pytest.raises(HomeAssistantError):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_REFRESH,
            {ATTR_DEVICE_ID: ["bad-device_id"]},
            blocking=True,
        )


async def test_video_service_calls(
    hass: HomeAssistant,
    device_registry: dr.DeviceRegistry,
    mock_blink_api: MagicMock,
    mock_blink_auth_api: MagicMock,
    mock_config_entry: MockConfigEntry,
    caplog: pytest.LogCaptureFixture,
) -> None:
    """Test video service calls."""

    mock_config_entry.add_to_hass(hass)
    assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
    await hass.async_block_till_done()

    device_entry = device_registry.async_get_device(identifiers={(DOMAIN, "12345")})

    assert device_entry

    assert mock_config_entry.state is ConfigEntryState.LOADED
    assert mock_blink_api.refresh.call_count == 1

    with pytest.raises(HomeAssistantError):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SAVE_VIDEO,
            {
                ATTR_DEVICE_ID: [device_entry.id],
                CONF_NAME: CAMERA_NAME,
                CONF_FILENAME: FILENAME,
            },
            blocking=True,
        )

    hass.config.is_allowed_path = Mock(return_value=True)
    caplog.clear()
    mock_blink_api.cameras = {CAMERA_NAME: AsyncMock()}
    await hass.services.async_call(
        DOMAIN,
        SERVICE_SAVE_VIDEO,
        {
            ATTR_DEVICE_ID: [device_entry.id],
            CONF_NAME: CAMERA_NAME,
            CONF_FILENAME: FILENAME,
        },
        blocking=True,
    )
    mock_blink_api.cameras[CAMERA_NAME].video_to_file.assert_awaited_once()

    with pytest.raises(HomeAssistantError):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SAVE_VIDEO,
            {
                ATTR_DEVICE_ID: ["bad-device_id"],
                CONF_NAME: CAMERA_NAME,
                CONF_FILENAME: FILENAME,
            },
            blocking=True,
        )

    mock_blink_api.cameras[CAMERA_NAME].video_to_file = AsyncMock(side_effect=OSError)

    with pytest.raises(ServiceValidationError):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SAVE_VIDEO,
            {
                ATTR_DEVICE_ID: [device_entry.id],
                CONF_NAME: CAMERA_NAME,
                CONF_FILENAME: FILENAME,
            },
            blocking=True,
        )

    hass.config.is_allowed_path = Mock(return_value=False)


async def test_picture_service_calls(
    hass: HomeAssistant,
    device_registry: dr.DeviceRegistry,
    mock_blink_api: MagicMock,
    mock_blink_auth_api: MagicMock,
    mock_config_entry: MockConfigEntry,
    caplog: pytest.LogCaptureFixture,
) -> None:
    """Test picture servcie calls."""

    mock_config_entry.add_to_hass(hass)
    assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
    await hass.async_block_till_done()

    device_entry = device_registry.async_get_device(identifiers={(DOMAIN, "12345")})

    assert device_entry

    assert mock_config_entry.state is ConfigEntryState.LOADED
    assert mock_blink_api.refresh.call_count == 1

    with pytest.raises(ServiceValidationError):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SAVE_RECENT_CLIPS,
            {
                ATTR_DEVICE_ID: [device_entry.id],
                CONF_NAME: CAMERA_NAME,
                CONF_FILE_PATH: FILENAME,
            },
            blocking=True,
        )

    hass.config.is_allowed_path = Mock(return_value=True)
    mock_blink_api.cameras = {CAMERA_NAME: AsyncMock()}

    await hass.services.async_call(
        DOMAIN,
        SERVICE_SAVE_RECENT_CLIPS,
        {
            ATTR_DEVICE_ID: [device_entry.id],
            CONF_NAME: CAMERA_NAME,
            CONF_FILE_PATH: FILENAME,
        },
        blocking=True,
    )
    mock_blink_api.cameras[CAMERA_NAME].save_recent_clips.assert_awaited_once()

    mock_blink_api.cameras[CAMERA_NAME].save_recent_clips = AsyncMock(
        side_effect=OSError
    )

    with pytest.raises(ServiceValidationError):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SAVE_RECENT_CLIPS,
            {
                ATTR_DEVICE_ID: [device_entry.id],
                CONF_NAME: CAMERA_NAME,
                CONF_FILE_PATH: FILENAME,
            },
            blocking=True,
        )

    with pytest.raises(HomeAssistantError):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SAVE_RECENT_CLIPS,
            {
                ATTR_DEVICE_ID: ["bad-device_id"],
                CONF_NAME: CAMERA_NAME,
                CONF_FILE_PATH: FILENAME,
            },
            blocking=True,
        )


async def test_pin_service_calls(
    hass: HomeAssistant,
    device_registry: dr.DeviceRegistry,
    mock_blink_api: MagicMock,
    mock_blink_auth_api: MagicMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test pin service calls."""

    mock_config_entry.add_to_hass(hass)
    assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
    await hass.async_block_till_done()

    device_entry = device_registry.async_get_device(identifiers={(DOMAIN, "12345")})

    assert device_entry

    assert mock_config_entry.state is ConfigEntryState.LOADED
    assert mock_blink_api.refresh.call_count == 1

    await hass.services.async_call(
        DOMAIN,
        SERVICE_SEND_PIN,
        {ATTR_DEVICE_ID: [device_entry.id], CONF_PIN: PIN},
        blocking=True,
    )
    assert mock_blink_api.auth.send_auth_key.assert_awaited_once

    with pytest.raises(HomeAssistantError):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SEND_PIN,
            {ATTR_DEVICE_ID: ["bad-device_id"], CONF_PIN: PIN},
            blocking=True,
        )


@pytest.mark.parametrize(
    ("service", "params"),
    [
        (SERVICE_SEND_PIN, {CONF_PIN: PIN}),
        (
            SERVICE_SAVE_RECENT_CLIPS,
            {
                CONF_NAME: CAMERA_NAME,
                CONF_FILE_PATH: FILENAME,
            },
        ),
        (
            SERVICE_SAVE_VIDEO,
            {
                CONF_NAME: CAMERA_NAME,
                CONF_FILENAME: FILENAME,
            },
        ),
    ],
)
async def test_service_called_with_non_blink_device(
    hass: HomeAssistant,
    device_registry: dr.DeviceRegistry,
    mock_blink_api: MagicMock,
    mock_blink_auth_api: MagicMock,
    mock_config_entry: MockConfigEntry,
    service,
    params,
) -> None:
    """Test service calls with non blink device."""

    mock_config_entry.add_to_hass(hass)
    assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
    await hass.async_block_till_done()

    other_domain = "NotBlink"
    other_config_id = "555"
    await hass.config_entries.async_add(
        MockConfigEntry(
            title="Not Blink", domain=other_domain, entry_id=other_config_id
        )
    )
    device_entry = device_registry.async_get_or_create(
        config_entry_id=other_config_id,
        identifiers={
            (other_domain, 1),
        },
    )

    hass.config.is_allowed_path = Mock(return_value=True)
    mock_blink_api.cameras = {CAMERA_NAME: AsyncMock()}

    parameters = {ATTR_DEVICE_ID: [device_entry.id]}
    parameters.update(params)

    with pytest.raises(ServiceValidationError):
        await hass.services.async_call(
            DOMAIN,
            service,
            parameters,
            blocking=True,
        )


@pytest.mark.parametrize(
    ("service", "params"),
    [
        (SERVICE_SEND_PIN, {CONF_PIN: PIN}),
        (
            SERVICE_SAVE_RECENT_CLIPS,
            {
                CONF_NAME: CAMERA_NAME,
                CONF_FILE_PATH: FILENAME,
            },
        ),
        (
            SERVICE_SAVE_VIDEO,
            {
                CONF_NAME: CAMERA_NAME,
                CONF_FILENAME: FILENAME,
            },
        ),
    ],
)
async def test_service_called_with_unloaded_entry(
    hass: HomeAssistant,
    device_registry: dr.DeviceRegistry,
    mock_blink_api: MagicMock,
    mock_blink_auth_api: MagicMock,
    mock_config_entry: MockConfigEntry,
    service,
    params,
) -> None:
    """Test service calls with unloaded config entry."""

    mock_config_entry.add_to_hass(hass)
    assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
    await hass.async_block_till_done()
    await mock_config_entry.async_unload(hass)

    device_entry = device_registry.async_get_device(identifiers={(DOMAIN, "12345")})

    assert device_entry

    hass.config.is_allowed_path = Mock(return_value=True)
    mock_blink_api.cameras = {CAMERA_NAME: AsyncMock()}

    parameters = {ATTR_DEVICE_ID: [device_entry.id]}
    parameters.update(params)

    with pytest.raises(HomeAssistantError):
        await hass.services.async_call(
            DOMAIN,
            service,
            parameters,
            blocking=True,
        )