"""
inventory/tests/test_permissions.py
Tests for RBAC permission classes.
"""

from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.test import RequestFactory, TestCase

from inventory.permissions import (
    IsFinanceManager,
    IsInventoryManager,
    IsInventoryManagerOrReadOnlyForStaff,
    IsInventoryOrFinanceManager,
    IsSuperAdmin,
)

User = get_user_model()


def make_group(name):
    group, _ = Group.objects.get_or_create(name=name)
    return group


def make_request(user, method="GET"):
    factory = RequestFactory()
    req = getattr(factory, method.lower())("/")
    req.user = user
    return req


class IsSuperAdminTest(TestCase):
    def test_superuser_allowed(self):
        user = User.objects.create_superuser("su", "su@test.com", "pass")
        self.assertTrue(IsSuperAdmin().has_permission(make_request(user), None))

    def test_staff_not_allowed(self):
        user = User.objects.create_user("staff", "s@test.com", "pass", is_staff=True)
        self.assertFalse(IsSuperAdmin().has_permission(make_request(user), None))

    def test_anonymous_not_allowed(self):
        from django.contrib.auth.models import AnonymousUser
        req = make_request(AnonymousUser())
        self.assertFalse(IsSuperAdmin().has_permission(req, None))


class IsInventoryManagerTest(TestCase):
    def setUp(self):
        self.group = make_group("inventory_managers")

    def test_group_member_allowed(self):
        user = User.objects.create_user("invmgr", password="pass", is_staff=True)
        user.groups.add(self.group)
        self.assertTrue(IsInventoryManager().has_permission(make_request(user), None))

    def test_non_member_not_allowed(self):
        user = User.objects.create_user("other", password="pass", is_staff=True)
        self.assertFalse(IsInventoryManager().has_permission(make_request(user), None))

    def test_superuser_allowed(self):
        user = User.objects.create_superuser("su2", "su2@test.com", "pass")
        self.assertTrue(IsInventoryManager().has_permission(make_request(user), None))

    def test_non_staff_not_allowed_even_in_group(self):
        user = User.objects.create_user("notstaff", password="pass", is_staff=False)
        user.groups.add(self.group)
        self.assertFalse(IsInventoryManager().has_permission(make_request(user), None))


class IsFinanceManagerTest(TestCase):
    def setUp(self):
        self.group = make_group("finance_managers")

    def test_group_member_allowed(self):
        user = User.objects.create_user("finmgr", password="pass", is_staff=True)
        user.groups.add(self.group)
        self.assertTrue(IsFinanceManager().has_permission(make_request(user), None))

    def test_inventory_manager_not_allowed(self):
        inv_group = make_group("inventory_managers")
        user = User.objects.create_user("invonly", password="pass", is_staff=True)
        user.groups.add(inv_group)
        self.assertFalse(IsFinanceManager().has_permission(make_request(user), None))


class IsInventoryOrFinanceManagerTest(TestCase):
    def test_inventory_manager_allowed(self):
        group = make_group("inventory_managers")
        user = User.objects.create_user("inv1", password="pass", is_staff=True)
        user.groups.add(group)
        self.assertTrue(IsInventoryOrFinanceManager().has_permission(make_request(user), None))

    def test_finance_manager_allowed(self):
        group = make_group("finance_managers")
        user = User.objects.create_user("fin1", password="pass", is_staff=True)
        user.groups.add(group)
        self.assertTrue(IsInventoryOrFinanceManager().has_permission(make_request(user), None))

    def test_neither_not_allowed(self):
        user = User.objects.create_user("nobody", password="pass", is_staff=True)
        self.assertFalse(IsInventoryOrFinanceManager().has_permission(make_request(user), None))


class IsInventoryManagerOrReadOnlyForStaffTest(TestCase):
    def setUp(self):
        self.inv_group = make_group("inventory_managers")
        self.staff_user = User.objects.create_user("staff_ro", password="pass", is_staff=True)
        self.inv_user = User.objects.create_user("inv_rw", password="pass", is_staff=True)
        self.inv_user.groups.add(self.inv_group)

    def test_staff_can_read(self):
        req = make_request(self.staff_user, "GET")
        self.assertTrue(IsInventoryManagerOrReadOnlyForStaff().has_permission(req, None))

    def test_staff_cannot_write(self):
        req = make_request(self.staff_user, "POST")
        self.assertFalse(IsInventoryManagerOrReadOnlyForStaff().has_permission(req, None))

    def test_inv_manager_can_write(self):
        req = make_request(self.inv_user, "POST")
        self.assertTrue(IsInventoryManagerOrReadOnlyForStaff().has_permission(req, None))

    def test_inv_manager_can_read(self):
        req = make_request(self.inv_user, "GET")
        self.assertTrue(IsInventoryManagerOrReadOnlyForStaff().has_permission(req, None))
