from __future__ import annotations

from typing import ClassVar

from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _

from simorgh.core.models import TimeStampedModel, UUIDModel


class MembershipStatus(models.TextChoices):
    ACTIVE = "active", _("Active")
    SUSPENDED = "suspended", _("Suspended")
    REVOKED = "revoked", _("Revoked")


class Membership(UUIDModel, TimeStampedModel):
    """A role assignment for multiple users on one organization node within one tenant.

    A single Membership record represents the combination of (tenant, org_node, role)
    and may include many users. Each user's effective access is the union of all
    Membership records they belong to within the active tenant.
    Permission checks combine all active memberships scoped to the request's tenant.
    """

    users = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name="memberships",
        blank=True,
        verbose_name=_("users"),
    )
    tenant = models.ForeignKey(
        "tenants.Tenant",
        on_delete=models.CASCADE,
        related_name="memberships",
        verbose_name=_("tenant"),
    )
    organization_node = models.ForeignKey(
        "organizations.OrganizationNode",
        on_delete=models.PROTECT,
        related_name="memberships",
        verbose_name=_("organization node"),
    )
    role = models.ForeignKey(
        "iam.Role",
        on_delete=models.PROTECT,
        related_name="memberships",
        verbose_name=_("role"),
    )
    status = models.CharField(
        _("status"),
        max_length=16,
        choices=MembershipStatus.choices,
        default=MembershipStatus.ACTIVE,
        db_index=True,
    )
    # Extra scope payload for ABAC (e.g. {"region": "EU", "max_amount": 1000}).
    scope_extra = models.JSONField(_("scope extra"), default=dict, blank=True)

    class Meta:
        verbose_name = _("membership")
        verbose_name_plural = _("memberships")
        ordering: ClassVar[list[str]] = ["tenant_id", "organization_node_id"]
        constraints: ClassVar[list[models.BaseConstraint]] = [
            models.UniqueConstraint(
                fields=("tenant", "organization_node", "role"),
                name="memberships_unique_tenant_node_role",
            ),
        ]

    def __str__(self) -> str:
        return f"{self.tenant_id}#{self.organization_node_id}/{self.role_id}"

    @property
    def is_active(self) -> bool:
        return self.status == MembershipStatus.ACTIVE
