import pytest
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.urls import reverse

from apps.core.permissions.access import user_effective_perm_codes
from apps.core.permissions.roles import UserRole


def _make_custom_group(name, codenames):
    ct = ContentType.objects.get_for_model(Group)
    perms = []
    for codename in codenames:
        perm, _ = Permission.objects.get_or_create(
            codename=codename, content_type=ct, defaults={"name": codename}
        )
        perms.append(perm)
    group = Group.objects.create(name=name)
    group.permissions.set(perms)
    return group


@pytest.mark.django_db
def test_user_create_with_additional_roles_grants_custom_group_permissions(client, django_user_model):
    admin = django_user_model.objects.create_user(
        email="admin-role@x.com",
        password="x",
        is_superuser=True,
        is_staff=True,
    )
    client.force_login(admin)
    group = _make_custom_group("facilitator", ["facilitator_perm_a", "facilitator_perm_b"])

    r = client.post(
        reverse("core:user_manage_create"),
        data={
            "email": "facilitated@x.com",
            "first_name": "Fa",
            "last_name": "Cil",
            "phone": "",
            "institution": "",
            "role": UserRole.LEARNER,
            "is_active": "on",
            "additional_roles": [group.pk],
            "password1": "some-pass-word-123",
            "password2": "some-pass-word-123",
        },
    )
    assert r.status_code == 302

    user = django_user_model.objects.get(email="facilitated@x.com")
    assert user.groups.filter(pk=group.pk).exists()
    # The enum-mapped role group is untouched by additional_roles.
    assert user.groups.filter(name=UserRole.LEARNER).exists()

    codes = user_effective_perm_codes(user)
    app_label = ContentType.objects.get_for_model(Group).app_label
    assert f"{app_label}.facilitator_perm_a" in codes
    assert f"{app_label}.facilitator_perm_b" in codes


@pytest.mark.django_db
def test_user_edit_can_toggle_additional_roles_without_disturbing_role_group(client, django_user_model):
    admin = django_user_model.objects.create_user(
        email="admin-role2@x.com",
        password="x",
        is_superuser=True,
        is_staff=True,
    )
    client.force_login(admin)
    group_a = _make_custom_group("reviewer_extra_a", ["extra_perm_a"])
    group_b = _make_custom_group("reviewer_extra_b", ["extra_perm_b"])

    target = django_user_model.objects.create_user(
        email="toggle@x.com", password="x", role=UserRole.REVIEWER
    )
    target.groups.add(group_a)

    r = client.post(
        reverse("core:user_manage_edit", kwargs={"pk": target.pk}),
        data={
            "first_name": "T",
            "last_name": "U",
            "phone": "",
            "institution": "",
            "role": UserRole.REVIEWER,
            "is_active": "on",
            "user_permissions": [],
            "additional_roles": [group_b.pk],
        },
    )
    assert r.status_code == 302

    target.refresh_from_db()
    assert not target.groups.filter(pk=group_a.pk).exists()
    assert target.groups.filter(pk=group_b.pk).exists()
    # Enum-synced role group membership is a separate lane and stays intact.
    assert target.groups.filter(name=UserRole.REVIEWER).exists()

    codes = user_effective_perm_codes(target)
    app_label = ContentType.objects.get_for_model(Group).app_label
    assert f"{app_label}.extra_perm_a" not in codes
    assert f"{app_label}.extra_perm_b" in codes
