import pytest
from django.core import mail
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient

from openslides.core.config import config
from openslides.users.models import Group, PersonalNote, User
from openslides.users.serializers import UserFullSerializer
from openslides.utils.autoupdate import inform_changed_data
from openslides.utils.test import TestCase

from ..helpers import count_queries


@pytest.mark.django_db(transaction=False)
def test_user_db_queries():
    """
    Tests that only the following db queries are done:
    * 2 requests to get the list of all users and
    * 1 requests to get the list of all groups.
    """
    for index in range(10):
        User.objects.create(username=f"user{index}")

    assert count_queries(User.get_elements) == 3


@pytest.mark.django_db(transaction=False)
def test_group_db_queries():
    """
    Tests that only the following db queries are done:
    * 1 request to get the list of all groups.
    * 1 request to get the permissions
    """
    for index in range(10):
        Group.objects.create(name=f"group{index}")

    assert count_queries(Group.get_elements) == 2


class UserGetTest(TestCase):
    """
    Tests to receive a users via REST API.
    """

    def test_get_with_user_who_is_in_group_with_pk_1(self):
        """
        It is invalid, that a user is in the group with the pk 1. But if the
        database is invalid, the user should nevertheless be received.
        """
        admin = User.objects.get(username="admin")
        group1 = Group.objects.get(pk=1)
        admin.groups.add(group1)
        self.client.login(username="admin", password="admin")

        response = self.client.get("/rest/users/user/1/")

        self.assertEqual(response.status_code, 200)

    def test_get_with_user_without_permissions(self):
        group = Group.objects.get(pk=1)
        permission_string = "users.can_see_name"
        app_label, codename = permission_string.split(".")
        permission = group.permissions.get(
            content_type__app_label=app_label, codename=codename
        )
        group.permissions.remove(permission)
        inform_changed_data(group)
        config["general_system_enable_anonymous"] = True
        guest_client = APIClient()

        response = guest_client.get("/rest/users/user/1/")

        self.assertEqual(response.status_code, 404)


class UserCreate(TestCase):
    """
    Tests creation of users via REST API.
    """

    def test_simple_creation(self):
        self.client.login(username="admin", password="admin")

        response = self.client.post(
            reverse("user-list"), {"last_name": "Test name keimeiShieX4Aekoe3do"}
        )

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        new_user = User.objects.get(username="Test name keimeiShieX4Aekoe3do")
        self.assertEqual(response.data["id"], new_user.id)

    def test_creation_with_group(self):
        self.client.login(username="admin", password="admin")
        # These are the builtin groups 'Delegates' and 'Staff'. The pks are valid.
        group_pks = (2, 3)

        self.client.post(
            reverse("user-list"),
            {"last_name": "Test name aedah1iequoof0Ashed4", "groups_id": group_pks},
        )

        user = User.objects.get(username="Test name aedah1iequoof0Ashed4")
        self.assertTrue(user.groups.filter(pk=group_pks[0]).exists())
        self.assertTrue(user.groups.filter(pk=group_pks[1]).exists())

    def test_creation_with_default_group(self):
        self.client.login(username="admin", password="admin")
        # This is the builtin groups 'default'.
        # The pk is valid. But this group can not be added to users.
        group_pk = (1,)

        response = self.client.post(
            reverse("user-list"),
            {"last_name": "Test name aedah1iequoof0Ashed4", "groups_id": group_pk},
        )

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(
            response.data,
            {"groups_id": ['Invalid pk "%d" - object does not exist.' % group_pk]},
        )


class UserUpdate(TestCase):
    """
    Tests update of users via REST API.
    """

    def test_simple_update_via_patch(self):
        """
        Test to only update the last_name with a patch request.

        The field username *should not* be changed by the request.
        """
        admin_client = APIClient()
        admin_client.login(username="admin", password="admin")
        # This is the builtin user 'Administrator' with username 'admin'. The pk is valid.
        user_pk = User.objects.get(username="admin").pk

        response = admin_client.patch(
            reverse("user-detail", args=[user_pk]),
            {"last_name": "New name tu3ooh5Iez5Aec2laefo"},
        )

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        user = User.objects.get(pk=user_pk)
        self.assertEqual(user.last_name, "New name tu3ooh5Iez5Aec2laefo")
        self.assertEqual(user.username, "admin")

    def test_simple_update_via_put(self):
        """
        Test to only update the last_name with a put request.

        The field username *should* be changed by the request.
        """
        admin_client = APIClient()
        admin_client.login(username="admin", password="admin")
        # This is the builtin user 'Administrator'. The pk is valid.
        user_pk = User.objects.get(username="admin").pk

        response = admin_client.put(
            reverse("user-detail", args=[user_pk]), {"last_name": "New name Ohy4eeyei5"}
        )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(User.objects.get(pk=user_pk).username, "New name Ohy4eeyei5")

    def test_update_deactivate_yourselfself(self):
        """
        Tests that an user can not deactivate himself.
        """
        admin_client = APIClient()
        admin_client.login(username="admin", password="admin")
        # This is the builtin user 'Administrator'. The pk is valid.
        user_pk = User.objects.get(username="admin").pk

        response = admin_client.patch(
            reverse("user-detail", args=[user_pk]),
            {"username": "admin", "is_active": False},
            format="json",
        )

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_update_yourself_non_manager(self):
        """
        Tests that an user can update himself even if he is not a manager.
        """
        user = User.objects.create_user(
            username="non-admin zeiyeGhaoXoh4awe3xai",
            password="non-admin chah1hoshohN5Oh7zouj",
        )
        client = APIClient()
        client.login(
            username="non-admin zeiyeGhaoXoh4awe3xai",
            password="non-admin chah1hoshohN5Oh7zouj",
        )

        response = client.put(
            reverse("user-detail", args=[user.pk]),
            {
                "username": "New username IeWeipee5mahpi4quupo",
                "last_name": "New name fae1Bu1Eyeis9eRox4xu",
                "about_me": "New profile text Faemahphi3Hilokangei",
            },
        )

        self.assertEqual(response.status_code, 200)
        user = User.objects.get(pk=user.pk)
        self.assertEqual(user.username, "New username IeWeipee5mahpi4quupo")
        self.assertEqual(user.about_me, "New profile text Faemahphi3Hilokangei")
        # The user is not allowed to change some other fields (like last_name).
        self.assertNotEqual(user.last_name, "New name fae1Bu1Eyeis9eRox4xu")


class UserDelete(TestCase):
    """
    Tests delete of users via REST API.
    """

    def test_delete(self):
        admin_client = APIClient()
        admin_client.login(username="admin", password="admin")
        User.objects.create(username="Test name bo3zieT3iefahng0ahqu")

        response = admin_client.delete(reverse("user-detail", args=["2"]))

        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertFalse(
            User.objects.filter(username="Test name bo3zieT3iefahng0ahqu").exists()
        )

    def test_delete_yourself(self):
        admin_client = APIClient()
        admin_client.login(username="admin", password="admin")
        # This is the builtin user 'Administrator'. The pk is valid.
        admin_user_pk = 1

        response = admin_client.delete(reverse("user-detail", args=[admin_user_pk]))

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)


class UserResetPassword(TestCase):
    """
    Tests resetting users password via REST API by a manager.
    """

    def test_reset(self):