from __future__ import annotations

from typing import ClassVar

from django.db import models
from django.utils.translation import gettext_lazy as _

from simorgh.core.models import TimeStampedModel, UUIDModel


class OrganizationNodeType(models.TextChoices):
    ORGANIZATION = "organization", _("Organization")
    HOLDING = "holding", _("Holding")
    COMPANY = "company", _("Company")
    BRANCH = "branch", _("Branch")
    DEPARTMENT = "department", _("Department")
    WAREHOUSE = "warehouse", _("Warehouse")


class OrganizationNode(UUIDModel, TimeStampedModel):
    """A node in the per-tenant org tree.

    `path_string` is the materialized path including this node's own id:
    e.g. ``/1/4/12/``. Root nodes are ``/{id}/``. The path is always kept in
    sync by `HierarchyService.attach_to_parent` / `move_node`; never edit it
    directly.
    """

    tenant = models.ForeignKey(
        "tenants.Tenant",
        on_delete=models.CASCADE,
        related_name="organization_nodes",
        verbose_name=_("tenant"),
    )
    parent = models.ForeignKey(
        "self",
        on_delete=models.PROTECT,
        related_name="children",
        null=True,
        blank=True,
        verbose_name=_("parent"),
    )
    type = models.CharField(
        _("type"),
        max_length=32,
        choices=OrganizationNodeType.choices,
        default=OrganizationNodeType.ORGANIZATION,
    )
    name = models.CharField(_("name"), max_length=255)
    code = models.CharField(_("code"), max_length=64, blank=True, default="")
    # Materialized path — populated by service, validated by db constraint length.
    path_string = models.CharField(
        _("path"), max_length=1024, blank=True, default="", db_index=True
    )
    depth = models.PositiveIntegerField(_("depth"), default=0, db_index=True)
    is_active = models.BooleanField(_("is active"), default=True)

    class Meta:
        verbose_name = _("organization node")
        verbose_name_plural = _("organization nodes")
        ordering: ClassVar[list[str]] = ["tenant_id", "path_string"]
        constraints: ClassVar[list[models.BaseConstraint]] = [
            models.UniqueConstraint(
                fields=("tenant", "parent", "name"),
                name="organizations_node_unique_sibling_name",
            ),
        ]
        indexes: ClassVar[list[models.Index]] = [
            models.Index(fields=("tenant", "path_string")),
        ]

    def __str__(self) -> str:
        return f"{self.tenant_id}:{self.path_string or self.pk} {self.name}"
