from django.core.cache import cache
from django.test import override_settings
from rest_framework.test import APIClient, APITestCase

from apps.access.models import MembershipRole, Role
from apps.access.services import resolve_access, seed_roles
from apps.modules import services as modules
from apps.modules.services import sync_registry
from apps.organizations import services as orgs
from apps.organizations.models import Organization, OrganizationAssignment, OrganizationMembership
from infrastructure.models import User

FAST_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
PASSWORD = "Str0ng-pass!"


@override_settings(PASSWORD_HASHERS=FAST_HASHERS, ROOT_URLCONF="tests.urls")
class CoreTestCase(APITestCase):
    """Fixture: platform org + two customer orgs (A, B) with attendance enabled in both.

    Users: root (super admin), manager_a / manager_b (org_manager), employee_a / employee_b
    (employee), and `multi` (manager in A, employee in B).
    """

    def setUp(self):
        cache.clear()
        sync_registry()
        self.platform = Organization.objects.create(name="NoTeam", slug="noteam", kind="platform")
        seed_roles(self.platform)
        self.root = self.make_user("root")
        self.join(self.root, self.platform, "super_admin")

        self.org_a = orgs.create_organization(actor=self.root, name="Org A", slug="org-a")
        self.org_b = orgs.create_organization(actor=self.root, name="Org B", slug="org-b")
        for org in (self.org_a, self.org_b):
            modules.enable_module(actor=self.root, organization=org, module_code="attendance")

        self.manager_a = self.make_user("manager-a")
        self.manager_a2 = self.make_user("manager-a2")
        self.employee_a = self.make_user("employee-a")
        self.manager_b = self.make_user("manager-b")
        self.employee_b = self.make_user("employee-b")
        self.multi = self.make_user("multi")
        self.stranger = self.make_user("stranger")

        self.join(self.manager_a, self.org_a, "org_manager")
        self.join(self.manager_a2, self.org_a, "org_manager")
        self.join(self.employee_a, self.org_a, "employee")
        self.join(self.manager_b, self.org_b, "org_manager")
        self.join(self.employee_b, self.org_b, "employee")
        self.join(self.multi, self.org_a, "org_manager")
        self.join(self.multi, self.org_b, "employee")

    # ---- helpers
    def make_user(self, username, **extra):
        return User.objects.create_user(personnel_code=username, password=PASSWORD, name=username, **extra)

    def join(self, user, organization, role_code=None):
        membership, _ = OrganizationMembership.objects.get_or_create(user=user, organization=organization)
        if role_code:
            role = Role.objects.get(organization=organization, code=role_code)
            MembershipRole.objects.get_or_create(membership=membership, role=role)
        return membership

    def membership(self, user, organization):
        return OrganizationMembership.objects.get(user=user, organization=organization)

    def role(self, organization, code):
        return Role.objects.get(organization=organization, code=code)

    def ctx(self, user, organization):
        return resolve_access(user, organization)

    def assign(self, staff_user, organization):
        OrganizationAssignment.objects.get_or_create(
            membership=self.membership(staff_user, self.platform), organization=organization
        )

    def api(self, user=None, organization=None):
        client = APIClient()
        if user is not None:
            client.force_authenticate(user)
        if organization is not None:
            client.credentials(HTTP_X_ORGANIZATION=str(organization.slug))
        return client
