"""Test the binary sensor platform of ping."""

from collections.abc import Generator
from datetime import timedelta
from unittest.mock import patch

from freezegun.api import FrozenDateTimeFactory
from icmplib import Host
import pytest

from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er

from tests.common import MockConfigEntry, async_fire_time_changed


@pytest.fixture
def entity_registry_enabled_by_default() -> Generator[None]:
    """Test fixture that ensures ping device_tracker entities are enabled in the registry."""
    with patch(
        "homeassistant.components.ping.device_tracker.PingDeviceTracker.entity_registry_enabled_default",
        return_value=True,
    ):
        yield


@pytest.mark.usefixtures("setup_integration")
async def test_setup_and_update(
    hass: HomeAssistant,
    entity_registry: er.EntityRegistry,
    config_entry: MockConfigEntry,
    freezer: FrozenDateTimeFactory,
) -> None:
    """Test sensor setup and update."""

    entry = entity_registry.async_get("device_tracker.10_10_10_10")
    assert entry
    assert entry.disabled
    assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION

    # check device tracker state is not there
    state = hass.states.get("device_tracker.10_10_10_10")
    assert state is None

    # enable the entity
    updated_entry = entity_registry.async_update_entity(
        entity_id="device_tracker.10_10_10_10", disabled_by=None
    )
    assert updated_entry != entry
    assert updated_entry.disabled is False

    # reload config entry to enable entity
    await hass.config_entries.async_reload(config_entry.entry_id)
    await hass.async_block_till_done()

    state = hass.states.get("device_tracker.10_10_10_10")
    assert state.state == "home"

    with patch(
        "homeassistant.components.ping.helpers.async_ping",
        return_value=Host(address="10.10.10.10", packets_sent=10, rtts=[]),
    ):
        # we need to travel two times into the future to run the update twice
        freezer.tick(timedelta(minutes=1, seconds=10))
        async_fire_time_changed(hass)
        await hass.async_block_till_done()

        freezer.tick(timedelta(minutes=4, seconds=10))
        async_fire_time_changed(hass)
        await hass.async_block_till_done()

    assert (state := hass.states.get("device_tracker.10_10_10_10"))
    assert state.state == "not_home"

    freezer.tick(timedelta(minutes=1, seconds=1))
    async_fire_time_changed(hass)
    await hass.async_block_till_done()

    assert (state := hass.states.get("device_tracker.10_10_10_10"))
    assert state.state == "home"


@pytest.mark.usefixtures("entity_registry_enabled_by_default", "setup_integration")
async def test_reload_not_triggering_home(
    hass: HomeAssistant,
    freezer: FrozenDateTimeFactory,
    config_entry: MockConfigEntry,
) -> None:
    """Test if reload/restart does not trigger home when device is unavailable."""
    assert hass.states.get("device_tracker.10_10_10_10").state == "home"

    with patch(
        "homeassistant.components.ping.helpers.async_ping",
        return_value=Host("10.10.10.10", 5, []),
    ):
        # device should be "not_home" after consider_home interval
        freezer.tick(timedelta(minutes=5, seconds=10))
        async_fire_time_changed(hass)
        await hass.async_block_till_done()

        assert hass.states.get("device_tracker.10_10_10_10").state == "not_home"

        # reload config entry
        await hass.config_entries.async_reload(config_entry.entry_id)
        await hass.async_block_till_done()

    # device should still be "not_home" after a reload
    assert hass.states.get("device_tracker.10_10_10_10").state == "not_home"

    # device should be "home" after the next refresh
    freezer.tick(timedelta(seconds=30))
    async_fire_time_changed(hass)
    await hass.async_block_till_done()

    assert hass.states.get("device_tracker.10_10_10_10").state == "home"