from typing import Dict

from django.core import mail
from django.test import TestCase
from django.urls import reverse
from django.utils.translation import gettext as _

from newsreader.accounts.tests.factories import UserFactory


class PasswordResetTestCase(TestCase):
    def setUp(self):
        self.url = reverse("accounts:password-reset")
        self.success_url = reverse("accounts:password-reset-done")
        self.user = UserFactory(email="test@test.com")

    def test_simple(self):
        response = self.client.get(self.url)

        self.assertEquals(response.status_code, 200)

    def test_password_change(self):
        data = {"email": "test@test.com"}

        response = self.client.post(self.url, data)
        self.assertRedirects(response, self.success_url)

        self.assertEquals(len(mail.outbox), 1)

    def test_unkown_email(self):
        data = {"email": "unknown@test.com"}

        response = self.client.post(self.url, data)
        self.assertRedirects(response, self.success_url)

        self.assertEquals(len(mail.outbox), 0)

    def test_repeatedly(self):
        data = {"email": "test@test.com"}

        response = self.client.post(self.url, data)
        self.assertRedirects(response, self.success_url)

        response = self.client.post(self.url, data)
        self.assertRedirects(response, self.success_url)

        self.assertEquals(len(mail.outbox), 2)


class PasswordResetConfirmTestCase(TestCase):
    def setUp(self):
        self.success_url = reverse("accounts:password-reset-complete")
        self.user = UserFactory(email="test@test.com")

    def _get_reset_credentials(self) -> Dict:
        data = {"email": self.user.email}

        response = self.client.post(reverse("accounts:password-reset"), data)

        return {
            "uidb64": response.context[0]["uid"],
            "token": response.context[0]["token"],
        }

    def test_simple(self):
        kwargs = self._get_reset_credentials()

        response = self.client.get(
            reverse("accounts:password-reset-confirm", kwargs=kwargs)
        )

        self.assertRedirects(
            response, f"/accounts/password-reset/{kwargs['uidb64']}/set-password/"
        )

    def test_confirm_password(self):
        kwargs = self._get_reset_credentials()

        response = self.client.get(
            reverse("accounts:password-reset-confirm", kwargs=kwargs)
        )

        data = {"new_password1": "jabbadabadoe", "new_password2": "jabbadabadoe"}

        response = self.client.post(response.url, data)

        self.assertRedirects(response, self.success_url)

        self.user.refresh_from_db()

        self.assertTrue(self.user.check_password("jabbadabadoe"))

    def test_wrong_uuid(self):
        correct_kwargs = self._get_reset_credentials()
        wrong_kwargs = {"uidb64": "burp", "token": correct_kwargs["token"]}

        response = self.client.get(
            reverse("accounts:password-reset-confirm", kwargs=wrong_kwargs)
        )

        self.assertContains(response, _("Password reset unsuccessful"))

    def test_wrong_token(self):
        correct_kwargs = self._get_reset_credentials()
        wrong_kwargs = {"uidb64": correct_kwargs["uidb64"], "token": "token"}

        response = self.client.get(
            reverse("accounts:password-reset-confirm", kwargs=wrong_kwargs)
        )

        self.assertContains(response, _("Password reset unsuccessful"))

    def test_wrong_url_args(self):
        kwargs = {"uidb64": "burp", "token": "token"}

        response = self.client.get(
            reverse("accounts:password-reset-confirm", kwargs=kwargs)
        )

        self.assertContains(response, _("Password reset unsuccessful"))

    def test_token_repeatedly(self):
        kwargs = self._get_reset_credentials()

        response = self.client.get(
            reverse("accounts:password-reset-confirm", kwargs=kwargs)
        )

        data = {"new_password1": "jabbadabadoe", "new_password2": "jabbadabadoe"}

        self.client.post(response.url, data)

        response = self.client.get(
            reverse("accounts:password-reset-confirm", kwargs=kwargs)
        )

        self.assertContains(response, _("Password reset unsuccessful"))

    def test_change_form_repeatedly(self):
        kwargs = self._get_reset_credentials()

        response = self.client.get(
            reverse("accounts:password-reset-confirm", kwargs=kwargs)
        )

        data = {"new_password1": "new-password", "new_password2": "new-password"}

        self.client.post(response.url, data)

        data = {"new_password1": "jabbadabadoe", "new_password2": "jabbadabadoe"}

        response = self.client.post(
            reverse("accounts:password-reset-confirm", kwargs=kwargs)
        )

        self.assertContains(response, _("Password reset unsuccessful"))

        self.user.refresh_from_db()

        self.assertTrue(self.user.check_password("new-password"))
