from __future__ import annotations

from django.conf import settings
from django.db import models

SCOPE_CHOICES = [
    ("self", "Self"),
    ("team", "Team"),
    ("unit", "Unit"),
    ("organization", "Organization"),
    ("assigned_organizations", "Assigned organizations"),
    ("all", "All"),
]


class Permission(models.Model):
    """Catalog entry, mirrored from the code registry. Never created by users."""

    code = models.CharField(max_length=100, unique=True)
    module = models.ForeignKey("modules.Module", on_delete=models.CASCADE, related_name="permissions")
    action = models.CharField(max_length=40)
    name_fa = models.CharField(max_length=160)
    is_platform_only = models.BooleanField(default=False)

    class Meta:
        db_table = "permissions"
        ordering = ["code"]

    def __str__(self):
        return self.code


class Role(models.Model):
    """A named bundle of permissions inside one organization (platform roles live in the
    platform organization). System roles are seeded from templates and cannot be deleted."""

    organization = models.ForeignKey(
        "organizations.Organization", on_delete=models.CASCADE, related_name="roles"
    )
    code = models.SlugField(max_length=50)
    name = models.CharField(max_length=120)
    is_system = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "roles"
        ordering = ["id"]
        constraints = [models.UniqueConstraint(fields=["organization", "code"], name="unique_role_code_per_org")]

    def __str__(self):
        return f"{self.organization_id}:{self.code}"


class RolePermission(models.Model):
    role = models.ForeignKey(Role, on_delete=models.CASCADE, related_name="grants")
    permission = models.ForeignKey(Permission, on_delete=models.CASCADE, related_name="role_grants")
    scope = models.CharField(max_length=30, choices=SCOPE_CHOICES, default="self")
    can_delegate = models.BooleanField(default=False)

    class Meta:
        db_table = "role_permissions"
        constraints = [models.UniqueConstraint(fields=["role", "permission"], name="unique_role_permission")]


class MembershipRole(models.Model):
    membership = models.ForeignKey(
        "organizations.OrganizationMembership", on_delete=models.CASCADE, related_name="membership_roles"
    )
    role = models.ForeignKey(Role, on_delete=models.CASCADE, related_name="membership_roles")

    class Meta:
        db_table = "membership_roles"
        constraints = [models.UniqueConstraint(fields=["membership", "role"], name="unique_membership_role")]


class UserPermissionOverride(models.Model):
    """Per-membership exception on top of roles. An explicit DENY always wins."""

    class Effect(models.TextChoices):
        ALLOW = "allow", "Allow"
        DENY = "deny", "Deny"

    membership = models.ForeignKey(
        "organizations.OrganizationMembership", on_delete=models.CASCADE, related_name="overrides"
    )
    permission = models.ForeignKey(Permission, on_delete=models.CASCADE, related_name="overrides")
    effect = models.CharField(max_length=5, choices=Effect.choices)
    scope = models.CharField(max_length=30, choices=SCOPE_CHOICES, default="self")
    can_delegate = models.BooleanField(default=False)
    reason = models.CharField(max_length=255, blank=True, default="")
    expires_at = models.DateTimeField(null=True, blank=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, related_name="+"
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "user_permission_overrides"
        constraints = [
            models.UniqueConstraint(fields=["membership", "permission"], name="unique_override_per_permission")
        ]
