# Copyright 2016-2024 The Wazo Authors  (see the AUTHORS file)
# SPDX-License-Identifier: GPL-3.0-or-later

from unittest import TestCase
from unittest.mock import Mock
from unittest.mock import sentinel as s

from ari.exceptions import ARINotFound
from hamcrest import assert_that, calling, equal_to, is_, raises

from ..event import CallEvent, ConnectCallEvent, StartCallEvent
from ..exceptions import (
    InvalidCallEvent,
    InvalidConnectCallEvent,
    InvalidStartCallEvent,
)

ONE_HOUR = 3600


class TestCallEvent(TestCase):
    def test_duration(self):
        state_persistor = Mock()
        state_persistor.get.return_value = Mock(app='my-app', app_instance='red')
        event = CallEvent(
            channel=Mock(json={'creationtime': '2016-02-16T13:31:00Z'}),
            event={'timestamp': '2016-02-16T13:32:00Z'},
            state_persistor=state_persistor,
        )

        result = event.duration()

        assert_that(result, equal_to(60))

    def test_duration_different_timezones(self):
        state_persistor = Mock()
        state_persistor.get.return_value = Mock(app='my-app', app_instance='red')
        event = CallEvent(
            channel=Mock(json={'creationtime': '2016-02-16T13:31:00+0100'}),
            event={'timestamp': '2016-02-16T13:31:00-0500'},
            state_persistor=state_persistor,
        )

        result = event.duration()

        assert_that(result, equal_to(6 * ONE_HOUR))

    def test_app_app_instance(self):
        state_persistor = Mock()
        state_persistor.get.return_value = Mock(app='my-app', app_instance='red')
        event = CallEvent(channel=Mock(), event={}, state_persistor=state_persistor)

        assert_that(event.app, equal_to('my-app'))
        assert_that(event.app_instance, equal_to('red'))

    def test_app_app_instance_unknown_channel(self):
        state_persistor = Mock()
        state_persistor.get.side_effect = KeyError
        assert_that(
            calling(CallEvent).with_args(
                channel=Mock(), event={}, state_persistor=state_persistor
            ),
            raises(InvalidCallEvent),
        )


class TestStartCallEvent(TestCase):
    def test_get_stasis_start_app_invalid(self):
        assert_that(
            calling(StartCallEvent).with_args(
                channel=Mock(), event={}, state_persistor=Mock()
            ),
            raises(InvalidStartCallEvent),
        )

    def test_get_stasis_start_app_valid(self):
        event = {'application': 'myapp', 'args': ['red']}

        result = StartCallEvent(channel=Mock(), event=event, state_persistor=Mock())

        assert_that(result.app, equal_to('myapp'))
        assert_that(result.app_instance, equal_to('red'))

    def test_get_stasis_start_app_valid_no_argument(self):
        event = {
            'application': 'myapp',
            'args': [],
        }

        result = StartCallEvent(channel=Mock(), event=event, state_persistor=Mock())

        assert_that(result.app, equal_to('myapp'))
        assert_that(result.app_instance, equal_to(None))


class TestConnectCallEvent(TestCase):
    def test_is_connect_event_false(self):
        assert_that(ConnectCallEvent.is_connect_event({}), equal_to(False))
        assert_that(ConnectCallEvent.is_connect_event({'args': []}), equal_to(False))

    def test_is_connect_event_true(self):
        event = {'application': 'myapp', 'args': ['red', 'dialed_from']}

        result = ConnectCallEvent.is_connect_event(event)

        assert_that(result, is_(True))

    def test_connect_event_originator_missing_event_args(self):
        assert_that(
            calling(ConnectCallEvent).with_args(
                channel=Mock(),
                event={'application': 'myapp', 'args': ['red']},
                ari=Mock(),
                state_persistor=Mock(),
            ),
            raises(InvalidConnectCallEvent),
        )

    def test_connect_event_originator_wrong_originator(self):
        event = {'application': 'myapp', 'args': ['red', 'dialed_from', 'channel-id']}
        ari = Mock()
        ari.channels.get.side_effect = ARINotFound(Mock(), Mock())

        assert_that(
            calling(ConnectCallEvent).with_args(
                channel=Mock(), event=event, ari=ari, state_persistor=Mock()
            ),
            raises(InvalidConnectCallEvent),
        )

    def test_connect_event_originator_valid(self):
        event = {'application': 'myapp', 'args': ['red', 'dialed_from', 'channel-id']}
        ari = Mock()
        ari.channels.get.return_value = s.originator

        result = ConnectCallEvent(
            channel=Mock(), event=event, ari=ari, state_persistor=Mock()
        )

        assert_that(result.originator_channel, equal_to(s.originator))
