import pytest
from django_scopes import scope

from servala.core.models.organization import OrganizationRole
from servala.core.rules import (
    has_organization_role,
    is_organization_admin,
    is_organization_member,
    is_organization_owner,
)

pytestmark = pytest.mark.django_db


def test_has_organization_role_returns_false_for_non_organization_object(user):
    assert has_organization_role(user, "not an organization", None) is False


def test_has_organization_role_returns_false_for_non_member(user, organization):
    with scope(organization=organization):
        assert has_organization_role(user, organization, None) is False


@pytest.mark.parametrize("user_fixture", ["org_owner", "org_admin", "org_member"])
def test_has_organization_role_returns_true_for_any_member(
    user_fixture, organization, request
):
    user = request.getfixturevalue(user_fixture)
    with scope(organization=organization):
        assert has_organization_role(user, organization, None) is True


@pytest.mark.parametrize(
    "user_fixture,roles,expected",
    [
        ("org_owner", [OrganizationRole.OWNER], True),
        ("org_owner", [OrganizationRole.ADMIN], False),
        ("org_owner", [OrganizationRole.MEMBER], False),
        ("org_owner", [OrganizationRole.OWNER, OrganizationRole.ADMIN], True),
        ("org_admin", [OrganizationRole.ADMIN], True),
        ("org_admin", [OrganizationRole.OWNER], False),
        ("org_admin", [OrganizationRole.OWNER, OrganizationRole.ADMIN], True),
        ("org_member", [OrganizationRole.MEMBER], True),
        ("org_member", [OrganizationRole.OWNER], False),
        ("org_member", [OrganizationRole.ADMIN], False),
    ],
)
def test_has_organization_role_filters_by_roles(
    user_fixture, roles, expected, organization, request
):
    user = request.getfixturevalue(user_fixture)
    with scope(organization=organization):
        assert has_organization_role(user, organization, roles) is expected


@pytest.mark.parametrize(
    "user_fixture,expected",
    [
        ("org_owner", True),
        ("org_admin", False),
        ("org_member", False),
    ],
)
def test_is_organization_owner(user_fixture, expected, organization, request):
    user = request.getfixturevalue(user_fixture)
    with scope(organization=organization):
        assert is_organization_owner(user, organization) is expected


@pytest.mark.parametrize(
    "user_fixture,expected",
    [
        ("org_owner", True),
        ("org_admin", False),
        ("org_member", False),
    ],
)
def test_is_organization_owner_with_related_object(
    user_fixture, expected, organization, mocker, request
):
    user = request.getfixturevalue(user_fixture)
    obj = mocker.MagicMock()
    obj.organization = organization
    with scope(organization=organization):
        assert is_organization_owner(user, obj) is expected


@pytest.mark.parametrize(
    "user_fixture,expected",
    [
        ("org_owner", True),
        ("org_admin", True),
        ("org_member", False),
    ],
)
def test_is_organization_admin(user_fixture, expected, organization, request):
    user = request.getfixturevalue(user_fixture)
    with scope(organization=organization):
        assert is_organization_admin(user, organization) is expected


@pytest.mark.parametrize(
    "user_fixture,expected",
    [
        ("org_owner", True),
        ("org_admin", True),
        ("org_member", False),
    ],
)
def test_is_organization_admin_with_related_object(
    user_fixture, expected, organization, mocker, request
):
    user = request.getfixturevalue(user_fixture)
    obj = mocker.MagicMock()
    obj.organization = organization
    with scope(organization=organization):
        assert is_organization_admin(user, obj) is expected


@pytest.mark.parametrize("user_fixture", ["org_owner", "org_admin", "org_member"])
def test_is_organization_member_returns_true_for_members(
    user_fixture, organization, request
):
    user = request.getfixturevalue(user_fixture)
    with scope(organization=organization):
        assert is_organization_member(user, organization) is True


def test_is_organization_member_returns_false_for_non_member(user, organization):
    with scope(organization=organization):
        assert is_organization_member(user, organization) is False


@pytest.mark.parametrize("user_fixture", ["org_owner", "org_admin", "org_member"])
def test_is_organization_member_with_related_object(
    user_fixture, organization, mocker, request
):
    user = request.getfixturevalue(user_fixture)
    obj = mocker.MagicMock()
    obj.organization = organization
    with scope(organization=organization):
        assert is_organization_member(user, obj) is True


def test_is_organization_member_with_related_object_returns_false_for_non_member(
    user, organization, mocker
):
    obj = mocker.MagicMock()
    obj.organization = organization
    with scope(organization=organization):
        assert is_organization_member(user, obj) is False
