"""
The Docker Container "database" needs to run to execute this tests properly
"""
import time
import unittest

from app import db
from Models.UserModel import UserModel
from Models.ChatModel import ChatModel
from Models.ChannelModel import ChannelModel
from Models.MatchModel import MatchModel
from datetime import datetime, timedelta
from Rest.UserREST import UserREST
from Rest.Answer import MessageCodes


def prepare_db():
    db.session.commit()
    db.drop_all()
    db.create_all()
    db.session.commit()


def setup_one():
    """
    Three users, user one is a moderator, user two not, user three is muted for 10 minutes.
    """
    # create users
    user_one = UserModel.create("user_one", "password", "randomemail@1")
    user_two = UserModel.create("user_two", "password", "randomemail@2")
    user_three = UserModel.create("user_three", "password", "randomemail@3")
    # give user_one moderator rights
    user_one.moderation_flags.is_moderator = True
    # mute user three for 10 min
    user_three.moderation_flags.muted_till = datetime.utcnow() + timedelta(minutes=10)
    return {'user_one': user_one, 'user_two': user_two, 'user_three': user_three}


def setup_two():
    """
    Three users, one chat between user one and two, user three and user two are matched but have no chat yet
    """
    # create users
    user_one = UserModel.create("user_one", "password", "randomemail@1")
    user_two = UserModel.create("user_two", "password", "randomemail@2")
    user_three = UserModel.create("user_three", "password", "randomemail@3")
    match = MatchModel()
    match.users.append(user_two)
    match.users.append(user_three)
    db.session.add(match)
    db.session.commit()
    channel = ChannelModel()
    db.session.add(channel)
    db.session.commit()
    chat = ChatModel(channel=channel)
    chat.users.append(user_one)
    chat.users.append(user_two)
    db.session.add(chat)
    db.session.commit()
    return {'user_one': user_one, 'user_two': user_two, 'user_three': user_three, 'chat': chat}


def setup_three():
    """
    three users, user one is admin and has ban power, user two is banned, user three is normal
    """
    prepare_db()
    # create admin user
    user_one = UserModel.create("user_one", "password", "randomemail1@1")
    user_one.moderation_flags.can_ban = True
    # create banned user
    user_two = UserModel.create("user_two", "password", "randomemail2@1")
    user_two.moderation_flags.banned_till = datetime.max
    # create normal user
    user_three = UserModel.create("user_three", "password", "randomemail3@1")

    return {'user_one': user_one, 'user_two': user_two, 'user_three': user_three}


class TestUserRest(unittest.TestCase):

    def test_setup_one(self):
        prepare_db()
        setup = setup_one()
        user_one = setup['user_one']
        user_two = setup['user_two']
        user_three = setup['user_three']
        # check mute status
        self.assertFalse(user_one.moderation_flags.is_muted())
        self.assertFalse(user_two.moderation_flags.is_muted())
        self.assertTrue(user_three.moderation_flags.is_muted())
        # check moderator status
        self.assertFalse(user_two.moderation_flags.is_moderator)
        self.assertFalse(user_three.moderation_flags.is_moderator)
        self.assertTrue(user_one.moderation_flags.is_moderator)

    def test_post_mute_user_success(self):
        # SETUP
        prepare_db()
        setup = setup_one()
        user_one = setup['user_one']
        user_two = setup['user_two']

        # ACTION
        mute_user_two_result = UserREST.post_mute_user(user_one.id, user_two.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.USER_MUTED_SUCCESS.value, mute_user_two_result.message)
        # user is muted for 10 min (default value)
        self.assertTrue(user_two.moderation_flags.is_muted())
        self.assertTrue(datetime.utcnow() < user_two.moderation_flags.muted_till < datetime.utcnow() + timedelta(minutes=15))

    def test_post_mute_user_not_moderator(self):
        # SETUP
        prepare_db()
        setup = setup_one()
        user_one = setup['user_one']
        user_two = setup['user_two']

        # ACTION
        mute_user_one_not_mod_result = UserREST.post_mute_user(user_two.id, user_one.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.USER_NOT_A_MODERATOR.value, mute_user_one_not_mod_result.message)
        # user is not muted
        self.assertFalse(user_one.moderation_flags.is_muted())

    def test_post_unmute_user_success(self):
        # SETUP
        prepare_db()
        setup = setup_one()
        user_one = setup['user_one']
        user_three = setup['user_three']

        # ACTION
        unmute_user_three_result = UserREST.post_unmute_user(user_one.id, user_three.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.USER_UNMUTED_SUCCESS.value, unmute_user_three_result.message)
        # user is not muted anymore
        self.assertFalse(user_three.moderation_flags.is_muted())

    def test_post_unmute_user_not_moderator(self):
        # SETUP
        prepare_db()
        setup = setup_one()
        user_three = setup['user_three']
        user_two = setup['user_two']

        # ACTION
        unmute_user_three_not_mod_result = UserREST.post_unmute_user(user_two.id, user_three.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.USER_NOT_A_MODERATOR.value, unmute_user_three_not_mod_result.message)
        # user is still muted
        self.assertTrue(user_three.moderation_flags.is_muted())

    def test_unmute_not_muted_user(self):
        # SETUP
        prepare_db()
        setup = setup_one()
        user_one = setup['user_one']
        user_two = setup['user_two']

        # ACTION
        unmute_unmuted_user_result = UserREST.post_unmute_user(user_one.id, user_two.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.USER_IS_NOT_MUTED.value, unmute_unmuted_user_result.message)
        # user is still not muted
        self.assertFalse(user_two.moderation_flags.is_muted())

    def test_get_user_success(self):
        # Setup
        prepare_db()
        setup = setup_one()
        user_one = setup['user_one']
        user_one_name = user_one.display_name[:]

        # ACTION
        get_user_infos_result = UserREST.get_user(user_one.id, user_one.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.WORKED.value, get_user_infos_result.message)
        # right info returned
        self.assertEqual(user_one_name, get_user_infos_result.result.display_name)

    def test_get_user_self_success(self):
        # SETUP
        prepare_db()
        setup = setup_one()
        user_one = setup['user_one']
        user_one_name = user_one.display_name[:]

        # ACTION
        get_self_infos_result = UserREST.get_self(user_one.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.WORKED.value, get_self_infos_result.message)
        # right info returned
        self.assertEqual(user_one_name, get_self_infos_result.result.display_name)

    def test_put_chat_success(self):
        # SETUP
        prepare_db()
        setup = setup_two()
        user_two = setup['user_two']
        user_three = setup['user_three']

        # ACTION
        put_chat_result = UserREST.put_own_chat(user_two.id, user_three.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.WORKED.value, put_chat_result.message)
        # chat is created for both users
        chat = [chat for chat in user_two.chats if user_three in chat.users and user_two in chat.users]
        self.assertTrue(chat)
        chat = [chat for chat in user_three.chats if user_three in chat.users and user_two in chat.users]
        self.assertTrue(chat)
        # chat is returned as result
        print(put_chat_result.result)
        self.assertTrue(put_chat_result.result == chat[0])

    def test_put_chat_fail_no_accept(self):
        # SETUP
        setup = setup_three()
        user_one = setup["user_one"]
        user_two = setup["user_two"]

        # ACTION
        put_chat_result = UserREST.put_own_chat(user_one.id, user_two.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.USER_NO_RANDOM_CHATS.value, put_chat_result.message)
        # no chat is created
        self.assertFalse(ChatModel.query.all())

    def test_put_chat_success_no_accept(self):
        # SETUP
        setup = setup_three()
        user_one = setup["user_one"]
        user_two = setup["user_two"]
        # make user one able to message anyone
        user_one.moderation_flags.message_anyone = True
        db.session.add(user_one)
        db.session.commit()

        # ACTION
        put_chat_result = UserREST.put_own_chat(user_one.id, user_two.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.WORKED.value, put_chat_result.message)
        # chat with user two and one is created
        self.assertEqual(1, len(ChatModel.query.all()))
        self.assertTrue(user_one in ChatModel.query.all()[0].users)
        self.assertTrue(user_two in ChatModel.query.all()[0].users)

    def test_get_chat_success(self):
        # SETUP
        prepare_db()
        setup = setup_two()
        user_one = setup['user_one']
        user_two = setup['user_two']

        # ACTION
        get_chat_result = UserREST.get_own_chat(user_one.id, user_two.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.WORKED.value, get_chat_result.message)

    def test_get_chats_success(self):
        # SETUP
        prepare_db()
        setup = setup_two()
        user_one = setup['user_one']

        # ACTION
        get_chats_result = UserREST.get_own_chats(user_one.id)

        # RESULT
        # right message code
        self.assertEqual(MessageCodes.WORKED.value, get_chats_result.message)
        # list of chats is returned
        self.assertTrue(get_chats_result.result[0])

    def test_ban_user_success(self):
        # SETUP
        setup = setup_three()
        user_one = setup['user_one']
        user_three = setup['user_three']
        old_login_id = user_three.login_id

        # ACTION
        post_ban_user_result = UserREST.post_ban_user(str(user_one.id), (str(user_three.id)))

        # RESULT
        # right message codes
        self.assertEqual(MessageCodes.WORKED.value, post_ban_user_result.message)
        # user three is banned
        self.assertTrue(user_three.moderation_flags.is_banned())
        # login id is different
        self.assertNotEqual(old_login_id, user_three.login_id)

    def test_unban_user_success(self):
        # SETUP
        setup = setup_three()
        user_one = setup['user_one']
        user_two = setup['user_two']

        # ACTION
        post_ban_user_result = UserREST.post_unban_user(str(user_one.id), (str(user_two.id)))

        # RESULT
        # right message codes
        self.assertEqual(MessageCodes.WORKED.value, post_ban_user_result.message)
        # user two is not banned
        time.sleep(1)
        self.assertFalse(user_two.moderation_flags.is_banned())

    def test_ban_rights_user_fail(self):
        # SETUP
        setup = setup_three()
        user_one = setup['user_one']
        user_two = setup['user_two']
        user_three = setup['user_three']

        # ACTION
        post_ban_user_result = UserREST.post_ban_user(str(user_two.id), (str(user_one.id)))
        post_unban_user_result = UserREST.post_unban_user(str(user_three.id), str(user_two.id))

        # RESULT
        # right message codes
        self.assertEqual(MessageCodes.USER_NO_BAN_RIGHTS.value, post_ban_user_result.message)
        self.assertEqual(MessageCodes.USER_NO_BAN_RIGHTS.value, post_unban_user_result.message)
        # user one is not banned
        self.assertFalse(user_one.moderation_flags.is_banned())
        # user two is still banned
        self.assertTrue(user_two.moderation_flags.is_banned())
