"""Tests for the seventeentrack sensor."""

from __future__ import annotations

from unittest.mock import AsyncMock, patch

from freezegun.api import FrozenDateTimeFactory
from pyseventeentrack.errors import SeventeenTrackError

from homeassistant.core import HomeAssistant
from homeassistant.helpers import issue_registry as ir
from homeassistant.setup import async_setup_component

from . import goto_future, init_integration
from .conftest import (
    DEFAULT_SUMMARY,
    DEFAULT_SUMMARY_LENGTH,
    NEW_SUMMARY_DATA,
    VALID_PLATFORM_CONFIG_FULL,
    get_package,
)

from tests.common import MockConfigEntry


async def test_full_valid_config(
    hass: HomeAssistant,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Ensure everything starts correctly."""
    await init_integration(hass, mock_config_entry)
    assert len(hass.states.async_entity_ids()) == len(DEFAULT_SUMMARY.keys())


async def test_valid_config(
    hass: HomeAssistant,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Ensure everything starts correctly."""
    await init_integration(hass, mock_config_entry)
    assert len(hass.states.async_entity_ids()) == len(DEFAULT_SUMMARY.keys())


async def test_invalid_config(
    hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
    """Ensure nothing is created when config is wrong."""
    await init_integration(hass, mock_config_entry)
    assert not hass.states.async_entity_ids("sensor")


async def test_login_exception(
    hass: HomeAssistant,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Ensure everything starts correctly."""
    mock_seventeentrack.return_value.profile.login.side_effect = SeventeenTrackError(
        "Error"
    )
    await init_integration(hass, mock_config_entry)
    assert not hass.states.async_entity_ids("sensor")


async def test_add_package(
    hass: HomeAssistant,
    freezer: FrozenDateTimeFactory,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Ensure package is added correctly when user add a new package."""
    package = get_package()
    mock_seventeentrack.return_value.profile.packages.return_value = [package]

    await init_integration(hass, mock_config_entry)
    assert hass.states.get("sensor.17track_package_friendly_name_1")
    assert len(hass.states.async_entity_ids()) == DEFAULT_SUMMARY_LENGTH + 1

    package2 = get_package(
        tracking_number="789",
        friendly_name="friendly name 2",
        info_text="info text 2",
        location="location 2",
        timestamp="2020-08-10 14:25",
    )
    mock_seventeentrack.return_value.profile.packages.return_value = [package, package2]

    await goto_future(hass, freezer)

    assert hass.states.get("sensor.17track_package_friendly_name_1") is not None
    assert len(hass.states.async_entity_ids()) == DEFAULT_SUMMARY_LENGTH + 2


async def test_add_package_default_friendly_name(
    hass: HomeAssistant,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Ensure package is added correctly with default friendly name when user add a new package without his own friendly name."""
    package = get_package(friendly_name=None)
    mock_seventeentrack.return_value.profile.packages.return_value = [package]

    await init_integration(hass, mock_config_entry)
    state_456 = hass.states.get("sensor.17track_package_456")
    assert state_456 is not None
    assert state_456.attributes["friendly_name"] == "17Track Package 456"
    assert len(hass.states.async_entity_ids()) == DEFAULT_SUMMARY_LENGTH + 1


async def test_remove_package(
    hass: HomeAssistant,
    freezer: FrozenDateTimeFactory,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Ensure entity is not there anymore if package is not there."""
    package1 = get_package()
    package2 = get_package(
        tracking_number="789",
        friendly_name="friendly name 2",
        info_text="info text 2",
        location="location 2",
        timestamp="2020-08-10 14:25",
    )

    mock_seventeentrack.return_value.profile.packages.return_value = [
        package1,
        package2,
    ]

    await init_integration(hass, mock_config_entry)

    assert hass.states.get("sensor.17track_package_friendly_name_1") is not None
    assert hass.states.get("sensor.17track_package_friendly_name_2") is not None
    assert len(hass.states.async_entity_ids()) == DEFAULT_SUMMARY_LENGTH + 2

    mock_seventeentrack.return_value.profile.packages.return_value = [package2]

    await goto_future(hass, freezer)

    assert hass.states.get("sensor.17track_package_friendly_name_1") is None
    assert hass.states.get("sensor.17track_package_friendly_name_2") is not None
    assert len(hass.states.async_entity_ids()) == DEFAULT_SUMMARY_LENGTH + 1


async def test_package_error(
    hass: HomeAssistant,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Ensure package is added correctly when user add a new package."""
    mock_seventeentrack.return_value.profile.packages.side_effect = SeventeenTrackError(
        "Error"
    )
    mock_seventeentrack.return_value.profile.summary.return_value = {}

    await init_integration(hass, mock_config_entry)
    assert hass.states.get("sensor.17track_package_friendly_name_1") is None


async def test_delivered_not_shown(
    hass: HomeAssistant,
    freezer: FrozenDateTimeFactory,
    mock_seventeentrack: AsyncMock,
    mock_config_entry_with_default_options: MockConfigEntry,
) -> None:
    """Ensure delivered packages are not shown."""
    package = get_package(status=40)
    mock_seventeentrack.return_value.profile.packages.return_value = [package]

    with patch(
        "homeassistant.components.seventeentrack.sensor.persistent_notification"
    ) as persistent_notification_mock:
        await init_integration(hass, mock_config_entry_with_default_options)
        await goto_future(hass, freezer)

        assert hass.states.get("sensor.17track_package_friendly_name_1") is None
        persistent_notification_mock.create.assert_called()


async def test_delivered_shown(
    hass: HomeAssistant,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Ensure delivered packages are show when user choose to show them."""
    package = get_package(status=40)
    mock_seventeentrack.return_value.profile.packages.return_value = [package]

    with patch(
        "homeassistant.components.seventeentrack.sensor.persistent_notification"
    ) as persistent_notification_mock:
        await init_integration(hass, mock_config_entry)

        assert hass.states.get("sensor.17track_package_friendly_name_1") is not None
        assert len(hass.states.async_entity_ids()) == DEFAULT_SUMMARY_LENGTH + 1
        persistent_notification_mock.create.assert_not_called()


async def test_becomes_delivered_not_shown_notification(
    hass: HomeAssistant,
    freezer: FrozenDateTimeFactory,
    mock_seventeentrack: AsyncMock,
    mock_config_entry_with_default_options: MockConfigEntry,
) -> None:
    """Ensure notification is triggered when package becomes delivered."""
    package = get_package()
    mock_seventeentrack.return_value.profile.packages.return_value = [package]

    await init_integration(hass, mock_config_entry_with_default_options)

    assert hass.states.get("sensor.17track_package_friendly_name_1") is not None
    assert len(hass.states.async_entity_ids()) == DEFAULT_SUMMARY_LENGTH + 1

    package_delivered = get_package(status=40)
    mock_seventeentrack.return_value.profile.packages.return_value = [package_delivered]

    with patch(
        "homeassistant.components.seventeentrack.sensor.persistent_notification"
    ) as persistent_notification_mock:
        await goto_future(hass, freezer)

        persistent_notification_mock.create.assert_called()
        assert len(hass.states.async_entity_ids()) == DEFAULT_SUMMARY_LENGTH


async def test_summary_correctly_updated(
    hass: HomeAssistant,
    freezer: FrozenDateTimeFactory,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Ensure summary entities are not duplicated."""
    package = get_package(status=30)
    mock_seventeentrack.return_value.profile.packages.return_value = [package]

    await init_integration(hass, mock_config_entry)

    assert len(hass.states.async_entity_ids()) == DEFAULT_SUMMARY_LENGTH + 1

    state_ready_picked = hass.states.get("sensor.17track_ready_to_be_picked_up")
    assert state_ready_picked is not None
    assert len(state_ready_picked.attributes["packages"]) == 1

    mock_seventeentrack.return_value.profile.packages.return_value = []
    mock_seventeentrack.return_value.profile.summary.return_value = NEW_SUMMARY_DATA

    await goto_future(hass, freezer)

    assert len(hass.states.async_entity_ids()) == len(NEW_SUMMARY_DATA)
    for state in hass.states.async_all():
        assert state.state == "1"

    state_ready_picked = hass.states.get("sensor.17track_ready_to_be_picked_up")
    assert state_ready_picked is not None
    assert len(state_ready_picked.attributes["packages"]) == 0


async def test_summary_error(
    hass: HomeAssistant,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test summary empty if error."""
    package = get_package(status=30)
    mock_seventeentrack.return_value.profile.packages.return_value = [package]
    mock_seventeentrack.return_value.profile.summary.side_effect = SeventeenTrackError(
        "Error"
    )

    await init_integration(hass, mock_config_entry)

    assert len(hass.states.async_entity_ids()) == 0

    assert (
        hass.states.get("sensor.seventeentrack_packages_ready_to_be_picked_up") is None
    )


async def test_utc_timestamp(
    hass: HomeAssistant,
    mock_seventeentrack: AsyncMock,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Ensure package timestamp is converted correctly from HA-defined time zone to UTC."""

    package = get_package(tz="Asia/Jakarta")
    mock_seventeentrack.return_value.profile.packages.return_value = [package]

    await init_integration(hass, mock_config_entry)

    assert hass.states.get("sensor.17track_package_friendly_name_1") is not None
    assert len(hass.states.async_entity_ids()) == DEFAULT_SUMMARY_LENGTH + 1
    state_456 = hass.states.get("sensor.17track_package_friendly_name_1")
    assert state_456 is not None
    assert str(state_456.attributes.get("timestamp")) == "2020-08-10 03:32:00+00:00"


async def test_non_valid_platform_config(
    hass: HomeAssistant, mock_seventeentrack: AsyncMock
) -> None:
    """Test if login fails."""
    mock_seventeentrack.return_value.profile.login.return_value = False
    assert await async_setup_component(hass, "sensor", VALID_PLATFORM_CONFIG_FULL)
    await hass.async_block_till_done()
    assert len(hass.states.async_entity_ids()) == 0


async def test_full_valid_platform_config(
    hass: HomeAssistant,
    mock_seventeentrack: AsyncMock,
    issue_registry: ir.IssueRegistry,
) -> None:
    """Ensure everything starts correctly."""
    assert await async_setup_component(hass, "sensor", VALID_PLATFORM_CONFIG_FULL)
    await hass.async_block_till_done()
    assert len(hass.states.async_entity_ids()) == len(DEFAULT_SUMMARY.keys())
    assert len(issue_registry.issues) == 2
