from django.contrib import auth
from django.test import TestCase
from unittest import mock

from apps.lyric.models import LoginToken


@mock.patch("apps.lyric.views.send_login_email_task.delay")
class SendLoginEmailViewTest(TestCase):
    def test_redirects_to_home_page(self, mock_delay):
        response = self.client.post(
            "/dashboard/send_login_email", data={"email": "discoman@example.com"}
        )
        self.assertRedirects(response, "/")

    def test_sends_mail_to_address_from_post(self, mock_delay):
        self.client.post(
            "/dashboard/send_login_email", data={"email": "discoman@example.com"}
        )

        self.assertEqual(mock_delay.called, True)
        self.assertEqual(mock_delay.call_args.args[0], "discoman@example.com")

    def test_adds_success_message(self, mock_delay):
        response = self.client.post(
            "/dashboard/send_login_email",
            data={"email": "discoman@example.com"},
            follow=True
        )

        message = list(response.context["messages"])[0]
        self.assertEqual(
            message.message,
            "Check your email!—there you'll find a magic login link. But hurry… it's only temporary!",
        )
        self.assertEqual(message.tags, "success")

    def test_creates_login_token_associated_with_email(self, mock_delay):
        self.client.post(
            "/dashboard/send_login_email", data={"email": "discoman@example.com"}
        )
        login_token = LoginToken.objects.get()
        self.assertEqual(login_token.email, "discoman@example.com")
        
    def test_sends_link_to_login_using_login_token_uid(self, mock_delay):
        self.client.post(
            "/dashboard/send_login_email", data={"email": "discoman@example.com"}
        )

        login_token = LoginToken.objects.get()
        expected_url = f"http://testserver/dashboard/login?token={login_token.uid}"
        self.assertEqual(mock_delay.call_args.args[1], expected_url)

class LoginViewTest(TestCase):
    def test_redirects_to_home_page(self):
        response = self.client.get("/dashboard/login?token=abc123")
        self.assertRedirects(response, "/")

    def test_logs_in_if_given_valid_login_token(self):
        anon_user = auth.get_user(self.client)
        self.assertEqual(anon_user.is_authenticated, False)

        login_token = LoginToken.objects.create(email="discoman@example.com")
        self.client.get(f"/dashboard/login?token={login_token.uid}", follow=True)

        user = auth.get_user(self.client)
        self.assertEqual(user.is_authenticated, True)
        self.assertEqual(user.email, "discoman@example.com")

    def test_shows_login_error_if_login_token_invalid(self):
        response = self.client.get("/dashboard/login?token=invalid-token", follow=True)
        user = auth.get_user(self.client)
        self.assertEqual(user.is_authenticated, False)
        message = list(response.context["messages"])[0]
        self.assertEqual(
            message.message,
            "Invalid login link!—please request another",
        )
        self.assertEqual(message.tags, "error")

    @mock.patch("apps.lyric.views.auth")
    def test_calls_authenticate_with_uid_from_get_request(self, mock_auth):
        self.client.get("/dashboard/login?token=abc123")
        self.assertEqual(
            mock_auth.authenticate.call_args,
            mock.call(uid="abc123")
        )


class DevLoginViewTest(TestCase):
    def test_happy_path_sets_session_cookie_and_redirects(self):
        from django.test import override_settings
        with override_settings(DEBUG=True):
            response = self.client.get("/dashboard/dev-login/testsessionkey/")
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response["Location"], "/")
        self.assertIn("sessionid", response.cookies)

    def test_next_param_sets_redirect_target(self):
        from django.test import override_settings
        with override_settings(DEBUG=True):
            response = self.client.get("/dashboard/dev-login/key/?next=/gameboard/")
        self.assertEqual(response["Location"], "/gameboard/")

    def test_returns_404_when_debug_is_false(self):
        from django.test import override_settings
        with override_settings(DEBUG=False):
            response = self.client.get("/dashboard/dev-login/key/")
        self.assertEqual(response.status_code, 404)
