from io import StringIO

from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site
from django.core.management import CommandError, call_command
from django.test import TestCase

User = get_user_model()


class CreateAdminCommandTest(TestCase):
    def setUp(self):
        self.site = Site.objects.get_current()

    def test_create_admin_with_email(self):
        # creating a new admin user with an email should succeed
        out = StringIO()

        call_command(
            "createadmin",
            email="admin@example.com",
            password="strongpass",
            site_id=self.site.id,
            stdout=out,
        )

        user = User.objects.get(email="admin@example.com")
        self.assertTrue(user.is_staff)
        self.assertTrue(user.is_superuser)
        self.assertTrue(user.check_password("strongpass"))
        self.assertEqual(user.site_id, self.site.id)
        self.assertIn("successfully", out.getvalue())

    def test_create_admin_with_cpf_only(self):
        # at least one login provider (cpf here) is enough
        out = StringIO()

        call_command(
            "createadmin",
            cpf="52998224725",
            password="strongpass",
            stdout=out,
        )

        self.assertTrue(User.objects.filter(cpf="52998224725").exists())

    def test_create_admin_generates_username_when_missing(self):
        # without a username the command generates a uuid one
        out = StringIO()

        call_command(
            "createadmin",
            email="autouser@example.com",
            password="strongpass",
            stdout=out,
        )

        user = User.objects.get(email="autouser@example.com")
        self.assertTrue(user.username)

    def test_missing_login_provider_raises(self):
        # without email, cpf or mobile phone the command must fail
        with self.assertRaises(CommandError) as ctx:
            call_command("createadmin", password="strongpass")

        self.assertIn("At least one login method is required.", str(ctx.exception))

    def test_missing_password_raises(self):
        # password is mandatory
        with self.assertRaises(CommandError) as ctx:
            call_command("createadmin", email="nopass@example.com")

        self.assertIn("Password is required.", str(ctx.exception))

    def test_duplicate_user_raises_creation_failed(self):
        # creating a second admin with the same email triggers the failure branch
        call_command(
            "createadmin",
            email="dup@example.com",
            password="strongpass",
            site_id=self.site.id,
            stdout=StringIO(),
        )

        with self.assertRaises(CommandError) as ctx:
            call_command(
                "createadmin",
                email="dup@example.com",
                password="strongpass",
                site_id=self.site.id,
            )

        self.assertIn("Super user creation failed", str(ctx.exception))


class CreateAdminUsernameTest(TestCase):
    """
    `make create-su` passes --username, and it used to be dropped on the way
    through the manager: the account came out with a uuid for a login.
    """

    def test_the_username_that_was_passed_is_the_one_stored(self):
        call_command(
            "createadmin",
            username="admin",
            email="admin@admin.com",
            password="admin",
            interactive=False,
        )

        user = User.objects.get(email="admin@admin.com")

        self.assertEqual(user.username, "admin")
        self.assertTrue(user.check_password("admin"))
        self.assertTrue(user.is_superuser)

    def test_an_account_with_no_username_still_gets_a_unique_one(self):
        call_command(
            "createadmin",
            email="nameless@example.com",
            password="password123",
            interactive=False,
        )

        user = User.objects.get(email="nameless@example.com")

        self.assertTrue(user.username)
        self.assertNotEqual(user.username, "nameless@example.com")
