# -*- coding: utf-8 -*-
import datetime
from unittest import mock

import aiojobs

from homehub_backend.services import uptime


class Test_UptimeService:
    def test_init(self, homehub_app):
        service = uptime.UptimeService(homehub_app, 'testing', {})
        assert service.uptime == 0
        assert service.job is None

    def test_update_uptime(self, homehub_app):
        homehub_app['STARTUP_TS'] = datetime.datetime(1987, 10, 3, 8, 0, 0)
        fake_now = homehub_app['STARTUP_TS'] + datetime.timedelta(minutes=15)

        service = uptime.UptimeService(homehub_app, 'testing', {})

        with mock.patch('datetime.datetime') as mock_datetime:
            mock_datetime.now.return_value = fake_now

            service.update_uptime()
            assert service.uptime == 900

    async def test_current_data(self, homehub_app):
        service = uptime.UptimeService(homehub_app, 'testing', {})
        service.uptime = 42

        result = await service.current_data()
        assert result.data == 42

    async def test_worker(self, homehub_app):
        service = uptime.UptimeService(homehub_app, 'testing', {})
        service.job = mock.Mock(spec=aiojobs._job.Job)
        service.job.closed = True
        service.update_uptime = mock.Mock()
        service.notify = mock.AsyncMock()

        with mock.patch('asyncio.sleep') as mock_asyncio_sleep:
            await service.worker()

            mock_asyncio_sleep.assert_called_with(60)
            assert service.update_uptime.called is True
            assert service.notify.called is True

    async def test_start(self, homehub_app):
        service = uptime.UptimeService(homehub_app, 'testing', {})
        service.update_uptime = mock.Mock()

        fake_worker = mock.AsyncMock()
        service.worker = mock.Mock()
        service.worker.return_value = fake_worker

        with mock.patch('aiojobs.aiohttp.get_scheduler_from_app') as mock_get_scheduler:
            fake_scheduler = mock.Mock(spec=aiojobs._scheduler.Scheduler)
            fake_scheduler.spawn.return_value = mock.Mock(
                spec=aiojobs._job.Job,
            )
            mock_get_scheduler.return_value = fake_scheduler

            await service.start()
            assert service.update_uptime.called is True
            mock_get_scheduler.assert_called_with(homehub_app)
            fake_scheduler.spawn.assert_called_with(fake_worker)

    async def test_start_already_started(self, homehub_app):
        service = uptime.UptimeService(homehub_app, 'testing', {})
        service.job = mock.Mock(spec=aiojobs._job.Job)
        service.update_uptime = mock.Mock()

        fake_worker = mock.AsyncMock()
        service.worker = mock.Mock()
        service.worker.return_value = fake_worker

        with mock.patch('aiojobs.aiohttp.get_scheduler_from_app') as mock_get_scheduler:
            fake_scheduler = mock.Mock(spec=aiojobs._scheduler.Scheduler)
            fake_scheduler.spawn.return_value = mock.Mock(
                spec=aiojobs._job.Job,
            )

            mock_get_scheduler.return_value = fake_scheduler

            await service.start()
            assert not service.update_uptime.called
            assert not mock_get_scheduler.called
            assert not fake_scheduler.spawn.called

    async def test_shutdown(self, homehub_app):
        service = uptime.UptimeService(homehub_app, 'testing', {})
        service.job = mock.Mock(spec=aiojobs._job.Job)
        service.job.closed = False

        await service.shutdown()
        assert service.job.close.called is True

    async def test_shutdown_job_already_closed(self, homehub_app):
        service = uptime.UptimeService(homehub_app, 'testing', {})
        service.job = mock.Mock(spec=aiojobs._job.Job)
        service.job.closed = True

        await service.shutdown()
        assert not service.job.close.called
