# -*- coding: utf-8 -*-

# Copyright (C) 2018 Avencall
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>


import unittest
from random import randint

from mock import Mock, patch

from xivo_agid import objects


class MeetMeBuilder(object):

    def __init__(self):
        self._user_pin = None
        self._admin_pin = None
        self._musiconhold = None
        self._user_waitingroom = 0
        self._noplaymsgfirstenter = 0
        self._announceusercount = 0
        self._quiet = 0
        self._record = 0
        self._user_announcejoinleave = 'no'
        self._confno = None
        self._context = None
        self._name = None
        self._preprocess_subroutine = None
        self._maxusers = 0

    def withUserPin(self, user_pin):
        self._user_pin = user_pin
        return self

    def withAdminPin(self, admin_pin):
        self._admin_pin = admin_pin
        return self

    def withMusicOnHold(self, musiconhold):
        self._musiconhold = musiconhold
        return self

    def withWaitingRoom(self):
        self._user_waitingroom = 1
        return self

    def withNoPlaysMsgFirstEnter(self):
        self._noplaymsgfirstenter = 1
        return self

    def withAnnounceUserCount(self):
        self._announceusercount = 1
        return self

    def withQuiet(self):
        self._quiet = 1
        return self

    def withRecord(self):
        self._record = 1
        return self

    def withAnnounceJoinLeave(self, user_announcejoinleave):
        self._user_announcejoinleave = user_announcejoinleave
        return self

    def withConfNo(self, confno):
        self._confno = confno
        return self

    def withContext(self, context):
        self._context = context
        return self

    def withName(self, name):
        self._name = name
        return self

    def withSubroutine(self, preprocess_subroutine):
        self._preprocess_subroutine = preprocess_subroutine
        return self

    def withMaxUsers(self, maxusers):
        self._maxusers = maxusers
        return self

    @patch('xivo_dao.meetme_dao.get')
    def build(self, mock_meetme_dao_get):
        mock = Mock(user_pin=self._user_pin,
                    admin_pin=self._admin_pin,
                    musiconhold=self._musiconhold,
                    user_waitingroom=self._user_waitingroom,
                    noplaymsgfirstenter=self._noplaymsgfirstenter,
                    announceusercount=self._announceusercount,
                    quiet=self._quiet,
                    record=self._record,
                    user_announcejoinleave=self._user_announcejoinleave,
                    confno=self._confno,
                    context=self._context,
                    preprocess_subroutine=self._preprocess_subroutine,
                    maxusers=self._maxusers)

        '''
        name is a property of Mock class
        therefore we can't define the name property of the above Mock declaration
        and have to do it separately as below
        '''
        mock.configure_mock(name=self._name)

        mock_meetme_dao_get.return_value = mock
        meetme = objects.MeetMe(1)
        return meetme


def a_meetme():
    return MeetMeBuilder()


class TestMeetMe(unittest.TestCase):

    def test_no_pin(self):
        meetme = a_meetme().build()

        self.assertFalse(meetme.has_pin())

    def test_user_pin(self):
        meetme = (a_meetme()
                  .withUserPin('1234')
                  .build())

        self.assertTrue(meetme.has_pin())

    def test_admin_pin(self):
        meetme = (a_meetme()
                  .withAdminPin('4321')
                  .build())

        self.assertTrue(meetme.has_pin())

    def test_user_and_admin_pin(self):
        meetme = (a_meetme()
                  .withUserPin('1234')
                  .withAdminPin('4321')
                  .build())

        self.assertTrue(meetme.has_pin())

    def test_max_len_pin_(self):
        userpin_rand = str(randint(1, 999999999999))
        adminpin_rand = str(randint(1, 999999999999))
        longest_pin = userpin_rand if len(userpin_rand) > len(adminpin_rand) else adminpin_rand

        meetme = (a_meetme()
                  .withUserPin(userpin_rand)
                  .withAdminPin(adminpin_rand)
                  .build())

        self.assertEqual(meetme.max_len_pin(), len(longest_pin))

    def test_has_admin(self):
        meetme_wpin = (a_meetme()
                       .withUserPin('1234')
                       .withAdminPin('4321')
                       .build())

        meetme_w2pins = (a_meetme()
                         .withUserPin('2000')
                         .withAdminPin('40000')
                         .build())

        self.assertTrue(meetme_wpin.has_admin())
        self.assertTrue(meetme_w2pins.has_admin())

    def test_has_no_admin(self):
        meetme = (a_meetme()
                  .build())

        meetme_wpin = (a_meetme()
                       .withUserPin('1234')
                       .build())

        self.assertFalse(meetme.has_admin())
        self.assertFalse(meetme_wpin.has_admin())


class TestLine(unittest.TestCase):

    @patch('xivo_dao.user_line_dao.get_main_exten_by_user_id')
    @patch('xivo_agid.objects.Line.get_line_for_user')
    def test_lineCUSTOM_webrtc_is_none(self, mock_get_line_for_user, mock_user_line_dao_get_main_exten_by_user_id):
        protocol = 'CUSTOM'
        mock = Mock(context='default',
                    protocol=protocol,
                    name='abcd',
                    number='1000')
        mock_get_line_for_user.return_value = mock
        mock_user_line_dao_get_main_exten_by_user_id.return_value = '1000'

        line = objects.Line(1)

        self.assertTrue(line.webrtc == None)

    @patch('xivo_dao.user_line_dao.get_main_exten_by_user_id')
    @patch('xivo_agid.objects.Line.get_line_for_user')
    def test_lineSCCP_webrtc_is_none(self, mock_get_line_for_user, mock_user_line_dao_get_main_exten_by_user_id):
        protocol = 'SCCP'
        mock = Mock(context='default',
                    protocol=protocol,
                    name='abcd',
                    number='1000')
        mock_get_line_for_user.return_value = mock
        mock_user_line_dao_get_main_exten_by_user_id.return_value = '1000'

        line = objects.Line(1)

        self.assertTrue(line.webrtc == None)

    @patch('xivo_dao.user_line_dao.get_main_exten_by_user_id')
    @patch('xivo_agid.objects.Line.get_line_for_user')
    @patch('xivo_agid.objects.Line.get_webrtc_option')
    def test_lineSIP_get_webrtc_is_called(self, mock_get_webrtc_option, mock_get_line_for_user,
                                          mock_user_line_dao_get_main_exten_by_user_id):
        protocol = 'SIP'
        mock = Mock(context='default',
                    protocol=protocol,
                    name='abcd',
                    number='1000')
        mock_get_line_for_user.return_value = mock
        mock_user_line_dao_get_main_exten_by_user_id.return_value = '1000'
        mock_get_webrtc_option.return_value = 'yes'

        line = objects.Line(1)

        mock_get_webrtc_option.assert_called_once()
        self.assertTrue(line.webrtc == 'yes')

    @patch('xivo_dao.user_line_dao.get_main_exten_by_user_id')
    @patch('xivo_agid.objects.Line.get_line_for_user')
    def test_lineSIP_nosipopt_webrtc_is_none(self, mock_get_line_for_user,
                                             mock_user_line_dao_get_main_exten_by_user_id):
        protocol = 'SIP'
        sip_opts = []
        mock = Mock(context='default',
                    protocol=protocol,
                    name='abcd',
                    number='1000',
                    sip_endpoint=Mock(_options=sip_opts))
        mock_get_line_for_user.return_value = mock
        mock_user_line_dao_get_main_exten_by_user_id.return_value = '1000'

        line = objects.Line(1)

        self.assertTrue(line.webrtc == None)

    @patch('xivo_dao.user_line_dao.get_main_exten_by_user_id')
    @patch('xivo_agid.objects.Line.get_line_for_user')
    def test_lineSIP_with_webrtc_opt_webrtc_is_defined(self, mock_get_line_for_user,
                                                       mock_user_line_dao_get_main_exten_by_user_id):
        protocol = 'SIP'
        sip_webrtc_value = 'whatever'
        sip_opts = [['webrtc', sip_webrtc_value]]
        mock = Mock(context='default',
                    protocol=protocol,
                    name='abcd',
                    number='1000',
                    sip_endpoint=Mock(_options=sip_opts))
        mock_get_line_for_user.return_value = mock
        mock_user_line_dao_get_main_exten_by_user_id.return_value = '1000'

        line = objects.Line(1)

        self.assertTrue(line.webrtc == sip_webrtc_value)


class AgiMock(object):

    def __init__(self):
        self.channel_variables = dict()
        self.execution_history = []

    def get_variable(self, name):
        if (name in self.channel_variables):
            return self.channel_variables[name]
        return None

    def set_variable(self, name, val):
        self.channel_variables[name] = val

    def appexec(self, app_name, param=None):
        self.execution_history.append({"app_name": app_name, "param": param})
