# Generated by CodiumAI
import logging
import asyncio
import time
from unittest.mock import Mock

import pytest
from aiohttp import ClientSession
from bs4 import BeautifulSoup

from pyadtpulse import PyADTPulse
from pyadtpulse.const import ADT_SUMMARY_URI, DEFAULT_API_HOST


class TestPyADTPulse:
    # The class can be instantiated with a username, password, and fingerprint.
    def test_instantiation_with_username_password_fingerprint(self):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"

        # Act
        pulse = PyADTPulse(username, password, fingerprint, do_login=False)

        # Assert
        assert pulse._username == username
        assert pulse._password == password
        assert pulse._fingerprint == fingerprint

    # The login method successfully logs in the user.
    @pytest.mark.asyncio
    async def test_login_successfully_logs_in_user(self, mocker):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        pulse = PyADTPulse(username, password, fingerprint, do_login=False)

        async def mock_async_login():
            pulse._pulse_connection.authenticated_flag.set()

        mocker.patch.object(pulse, "async_login", side_effect=mock_async_login)

        # Act
        pulse.login()

        # Assert
        assert pulse._pulse_connection.authenticated_flag.is_set()

    # The logout method successfully logs out the user.
    @pytest.mark.asyncio
    async def test_logout_successfully_logs_out_user(self, mocker):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        pulse = PyADTPulse(username, password, fingerprint, do_login=False)
        pulse._pulse_connection.authenticated_flag.set()

        async def mock_async_logout():
            pulse._pulse_connection.authenticated_flag.clear()

        async def mock_async_login():
            pulse._pulse_connection.authenticated_flag.set()

        mocker.patch.object(
            pulse._pulse_connection,
            "async_do_logout_query",
            side_effect=mock_async_logout,
        )
        mocker.patch.object(pulse, "async_login", side_effect=mock_async_login)

        # Act
        await pulse.logout()

        # Assert
        assert not pulse._pulse_connection.authenticated_flag.is_set()

    # The service_host property can be set to a different host.
    def test_service_host_can_be_set_to_different_host(self):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        pulse = PyADTPulse(username, password, fingerprint, do_login=False)
        new_service_host = DEFAULT_API_HOST

        # Act
        pulse.service_host = new_service_host

        # Assert
        assert pulse._pulse_connection.service_host == new_service_host

    # The relogin_interval property can be set to a different interval.
    def test_relogin_interval_can_be_set_to_different_interval(self):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        pulse = PyADTPulse(username, password, fingerprint, do_login=False)
        new_relogin_interval = 120

        # Act
        pulse.relogin_interval = new_relogin_interval

        # Assert
        assert pulse._relogin_interval == new_relogin_interval

    # The updates_exist property returns True when updates are available.
    def test_updates_exist_returns_true_when_updates_available(self):
        # Arrange
        pulse = PyADTPulse(
            "test@example.com", "password123", "fingerprint123", do_login=False
        )
        pulse._updates_exist.set()

        # Act
        result = pulse.updates_exist

        # Assert
        assert result is True

    # The wait_for_update method waits for updates and returns True when updates are available.
    @pytest.mark.asyncio
    async def test_wait_for_update_returns_true_when_updates_available(self, mocker):
        # Arrange
        pulse = PyADTPulse(
            "test@example.com", "password123", "fingerprint123", do_login=False
        )
        pulse._updates_exist.set()

        # Act
        result = await pulse.wait_for_update()

        # Assert
        assert result is True

    # The is_connected property returns True when the user is connected to the ADT Pulse service.
    def test_is_connected_returns_true_when_user_connected(self, mocker):
        # Arrange
        pulse = PyADTPulse(
            "test@example.com", "password123", "fingerprint123", do_login=False
        )
        pulse._pulse_connection.authenticated_flag.set()
        pulse._pulse_connection.retry_after = time.time() - 1

        # Act
        result = pulse.is_connected

        # Assert
        assert result is True

    # The async_update method successfully queries the ADT Pulse service for updates.
    @pytest.mark.asyncio
    async def test_async_update_successfully_queries_pulse_service_for_updates(
        self, mocker
    ):
        # Arrange
        pulse = PyADTPulse(
            "email@example.com", "password", "fingerprint", do_login=False
        )
        mock_query_orb = mocker.patch.object(pulse._pulse_connection, "query_orb")
        mock_soup = mocker.Mock()
        mock_query_orb.return_value = mock_soup

        # Act
        result = await pulse.async_update()

        # Assert
        assert result is True
        mock_query_orb.assert_called_once_with(
            logging.INFO, "Error returned from ADT Pulse service check"
        )
        pulse._update_sites.assert_called_once_with(mock_soup)

    # The update method successfully queries the ADT Pulse service for updates.
    def test_update_successfully_queries_pulse_service_for_updates(self, mocker):
        # Arrange
        pulse = PyADTPulse(
            "email@example.com", "password", "fingerprint", do_login=False
        )
        mock_async_update = mocker.patch.object(pulse, "async_update")
        mock_async_update.return_value = True

        # Act
        result = pulse.update()

        # Assert
        assert result is True
        mock_async_update.assert_called_once()

    # The sites property returns a list of ADTPulseSite objects.
    def test_sites_property_returns_list_of_sites(self, mocker):
        # Arrange
        pulse = PyADTPulse("email@example.com", "password", "fingerprint")
        mock_site = mocker.Mock()
        pulse._site = mock_site

        # Act
        result = pulse.sites

        # Assert
        assert result == [mock_site]

    # The site property returns an ADTPulseSite object.
    def test_site_property_returns_ADTPulseSite_object(self):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        pulse = PyADTPulse(username, password, fingerprint, do_login=False)

        # Mock the site object
        class MockADTPulseSite:
            pass

        pulse._site = MockADTPulseSite()

        # Act
        site = pulse.site

        # Assert
        assert isinstance(site, MockADTPulseSite)

    # The class can be instantiated with optional parameters such as service_host, user_agent, websession, do_login, debug_locks, keepalive_interval, relogin_interval, and detailed_debug_logging.
    def test_class_instantiation_with_optional_parameters(self):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        service_host = DEFAULT_API_HOST
        user_agent = "Test User Agent"
        websession = ClientSession()
        do_login = False
        debug_locks = True
        keepalive_interval = 10
        relogin_interval = 5
        detailed_debug_logging = True

        # Act
        pulse = PyADTPulse(
            username,
            password,
            fingerprint,
            service_host=service_host,
            user_agent=user_agent,
            websession=websession,
            do_login=do_login,
            debug_locks=debug_locks,
            keepalive_interval=keepalive_interval,
            relogin_interval=relogin_interval,
            detailed_debug_logging=detailed_debug_logging,
        )

        # Assert
        assert pulse._username == username
        assert pulse._password == password
        assert pulse._fingerprint == fingerprint
        assert pulse._pulse_connection.service_host == service_host
        assert pulse._pulse_connection.user_agent == user_agent
        assert pulse._pulse_connection.session == websession
        assert pulse._pulse_connection.debug_locks == debug_locks
        assert pulse.keepalive_interval == keepalive_interval
        assert pulse.relogin_interval == relogin_interval
        assert pulse._detailed_debug_logging == detailed_debug_logging

    # The keepalive_interval property can be set to a different interval.
    def test_keepalive_interval_property_can_be_set(self):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        pulse = PyADTPulse(username, password, fingerprint, do_login=False)
        new_interval = 5

        # Act
        pulse.keepalive_interval = new_interval

        # Assert
        assert pulse.keepalive_interval == new_interval

    # The detailed_debug_logging property can be set to True or False.
    def test_detailed_debug_logging_property(self):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        pulse = PyADTPulse(username, password, fingerprint)

        # Act
        pulse.detailed_debug_logging = True

        # Assert
        assert pulse.detailed_debug_logging == True

        # Act
        pulse.detailed_debug_logging = False

        # Assert
        assert pulse.detailed_debug_logging == False

    # The async_login method returns False if authentication fails.
    @pytest.mark.asyncio
    async def test_async_login_authentication_fails(self, mocker):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        pulse = PyADTPulse(username, password, fingerprint)
        response = Mock()
        response.url = pulse._pulse_connection.make_url(ADT_SUMMARY_URI)
        soup = BeautifulSoup(
            "<div id='warnMsgContents'>Invalid username/password</div>", "html.parser"
        )
        mocker.patch.object(pulse._pulse_connection, "async_fetch_version")
        mocker.patch.object(
            pulse._pulse_connection,
            "async_do_login_query",
            return_value=asyncio.Future(),
        )
        mocker.patch.object(
            pulse._pulse_connection, "query_orb", return_value=asyncio.Future()
        )
        pulse._pulse_connection.async_do_login_query.return_value.set_result(response)
        pulse._pulse_connection.query_orb.return_value.set_result(soup)

        # Act
        result = await pulse.async_login()

        # Assert
        assert result == False

    # The async_logout method successfully logs out the user.
    @pytest.mark.asyncio
    async def test_async_logout_successfully_logs_out_user(self, mocker):
        # Arrange
        pulse = PyADTPulse("test@example.com", "password123", "fingerprint123")
        pulse._pulse_connection.authenticated_flag.set()

        async def mock_async_do_logout_query(site_id):
            return None

        mocker.patch.object(
            pulse._pulse_connection,
            "async_do_logout_query",
            side_effect=mock_async_do_logout_query,
        )

        # Act
        await pulse.async_logout()

        # Assert
        assert not pulse._pulse_connection.authenticated_flag.is_set()

    # The update method returns False if querying the ADT Pulse service fails.
    @pytest.mark.asyncio
    async def test_update_method_returns_false_if_querying_fails(self, mocker):
        # Arrange
        pulse = PyADTPulse("username", "password", "fingerprint")
        mocker.patch.object(pulse._pulse_connection, "query_orb", return_value=None)

        # Act
        result = await pulse.async_update()

        # Assert
        assert result == False

    # The async_update method returns False if querying the ADT Pulse service fails.
    @pytest.mark.asyncio
    async def test_async_update_returns_false_on_query_failure(self, mocker):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        pulse = PyADTPulse(username, password, fingerprint)
        mocker.patch.object(pulse._pulse_connection, "query_orb", return_value=None)

        # Act
        result = await pulse.async_update()

        # Assert
        assert result == False

    # The sites property raises a RuntimeError if no sites have been retrieved.
    def test_sites_property_raises_runtime_error_if_no_sites_retrieved(self, mocker):
        # Arrange
        username = "test@example.com"
        password = "password123"
        fingerprint = "fingerprint123"
        pulse = PyADTPulse(username, password, fingerprint)

        # Act and Assert
        with pytest.raises(RuntimeError):
            pulse.sites
