"""Projects domain models.

Model inventory
---------------
ProjectStatus     — enum: draft / active / on_hold / completed / cancelled
ProjectMemberRole — enum: lead / member / viewer
PhaseStatus       — enum: planned / active / done
ProjectTag        — per-tenant flat label
Project           — core entity: tenant-scoped project
ProjectMember     — many:many bridge: project ↔ user with a role
ProjectPhase      — ordered phases inside a project
Milestone         — checkable milestone inside a project

Design decisions
----------------
* All main business entities extend ``TenantScopedModel`` (tenant + org_node FKs).
* ``UUIDModel`` exposes ``public_id`` for external API identifiers.
* ``ProjectMember`` uses a UniqueConstraint so one user has one role per project.
* ``ProjectPhase.order`` keeps an explicit integer sort order; the queryset is
  ordered by ``order`` by default.
* ``contact`` FK on ``Project`` is a nullable cross-module reference to
  ``crm.Contact`` — stored as a raw FK so the CRM module can be absent without
  breaking the Projects module schema (on_delete=SET_NULL).
"""

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 (
    TenantScopedModel,
    TimeStampedModel,
    UUIDModel,
)


# ---------------------------------------------------------------------------
# Choices
# ---------------------------------------------------------------------------

class ProjectStatus(models.TextChoices):
    DRAFT = "draft", _("Draft")
    ACTIVE = "active", _("Active")
    ON_HOLD = "on_hold", _("On Hold")
    COMPLETED = "completed", _("Completed")
    CANCELLED = "cancelled", _("Cancelled")


class ProjectMemberRole(models.TextChoices):
    LEAD = "lead", _("Lead")
    MEMBER = "member", _("Member")
    VIEWER = "viewer", _("Viewer")


class PhaseStatus(models.TextChoices):
    PLANNED = "planned", _("Planned")
    ACTIVE = "active", _("Active")
    DONE = "done", _("Done")


# ---------------------------------------------------------------------------
# ProjectTag
# ---------------------------------------------------------------------------

class ProjectTag(UUIDModel, TimeStampedModel):
    """Flat, tenant-scoped label applied to projects."""

    tenant = models.ForeignKey(
        "tenants.Tenant",
        on_delete=models.CASCADE,
        related_name="project_tags",
    )
    name = models.CharField(_("name"), max_length=100)
    color = models.CharField(_("color"), max_length=20, blank=True, default="")

    class Meta:
        verbose_name = _("project tag")
        verbose_name_plural = _("project tags")
        constraints = (
            models.UniqueConstraint(
                fields=("tenant", "name"),
                name="projects_tag_unique_tenant_name",
            ),
        )

    def __str__(self) -> str:
        return self.name


# ---------------------------------------------------------------------------
# Project
# ---------------------------------------------------------------------------

class Project(UUIDModel, TenantScopedModel):
    """A project belonging to a tenant."""

    name = models.CharField(_("name"), max_length=255)
    code = models.CharField(_("code"), max_length=64, blank=True, default="")
    description = models.TextField(_("description"), blank=True, default="")
    status = models.CharField(
        _("status"),
        max_length=20,
        choices=ProjectStatus.choices,
        default=ProjectStatus.DRAFT,
        db_index=True,
    )
    start_date = models.DateField(_("start date"), null=True, blank=True)
    end_date = models.DateField(_("end date"), null=True, blank=True)
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
        related_name="owned_projects",
        verbose_name=_("owner"),
    )
    color = models.CharField(_("color"), max_length=20, blank=True, default="#4f46e5")
    tags = models.ManyToManyField(
        ProjectTag,
        blank=True,
        related_name="projects",
        verbose_name=_("tags"),
    )
    is_billable = models.BooleanField(_("is billable"), default=False)
    budget = models.DecimalField(
        _("budget"),
        max_digits=16,
        decimal_places=2,
        null=True,
        blank=True,
    )
    # Cross-module optional FK to CRM Contact (client / customer)
    contact_id = models.UUIDField(
        _("contact"),
        null=True,
        blank=True,
        db_index=True,
        help_text=_("Public UUID of the CRM Contact linked as client for this project."),
    )

    class Meta(TenantScopedModel.Meta):
        verbose_name = _("project")
        verbose_name_plural = _("projects")
        indexes: ClassVar[list[models.Index]] = [
            *TenantScopedModel.Meta.indexes,
            models.Index(fields=("tenant", "status")),
            models.Index(fields=("tenant", "owner")),
        ]
        constraints = (
            models.UniqueConstraint(
                fields=("tenant", "code"),
                condition=models.Q(code__gt=""),
                name="projects_project_unique_code_per_tenant",
            ),
        )

    def __str__(self) -> str:
        return self.name


# ---------------------------------------------------------------------------
# ProjectMember
# ---------------------------------------------------------------------------

class ProjectMember(UUIDModel, TimeStampedModel):
    """Membership bridge — one row per (project, user)."""

    project = models.ForeignKey(
        Project,
        on_delete=models.CASCADE,
        related_name="memberships",
        verbose_name=_("project"),
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="project_memberships",
        verbose_name=_("user"),
    )
    role = models.CharField(
        _("role"),
        max_length=20,
        choices=ProjectMemberRole.choices,
        default=ProjectMemberRole.MEMBER,
    )
    joined_at = models.DateTimeField(_("joined at"), auto_now_add=True)

    class Meta:
        verbose_name = _("project member")
        verbose_name_plural = _("project members")
        constraints = (
            models.UniqueConstraint(
                fields=("project", "user"),
                name="projects_member_unique_project_user",
            ),
        )

    def __str__(self) -> str:
        return f"{self.user} — {self.project} ({self.role})"


# ---------------------------------------------------------------------------
# ProjectPhase
# ---------------------------------------------------------------------------

class ProjectPhase(UUIDModel, TimeStampedModel):
    """An ordered phase within a project."""

    project = models.ForeignKey(
        Project,
        on_delete=models.CASCADE,
        related_name="phases",
        verbose_name=_("project"),
    )
    name = models.CharField(_("name"), max_length=255)
    order = models.PositiveIntegerField(_("order"), default=0, db_index=True)
    start_date = models.DateField(_("start date"), null=True, blank=True)
    end_date = models.DateField(_("end date"), null=True, blank=True)
    status = models.CharField(
        _("status"),
        max_length=20,
        choices=PhaseStatus.choices,
        default=PhaseStatus.PLANNED,
    )
    description = models.TextField(_("description"), blank=True, default="")

    class Meta:
        verbose_name = _("project phase")
        verbose_name_plural = _("project phases")
        ordering = ("order",)

    def __str__(self) -> str:
        return f"{self.project.name} — {self.name}"


# ---------------------------------------------------------------------------
# Milestone
# ---------------------------------------------------------------------------

class Milestone(UUIDModel, TimeStampedModel):
    """A checkable milestone inside a project."""

    project = models.ForeignKey(
        Project,
        on_delete=models.CASCADE,
        related_name="milestones",
        verbose_name=_("project"),
    )
    name = models.CharField(_("name"), max_length=255)
    due_date = models.DateField(_("due date"))
    is_completed = models.BooleanField(_("is completed"), default=False)
    completed_at = models.DateTimeField(_("completed at"), null=True, blank=True)
    description = models.TextField(_("description"), blank=True, default="")

    class Meta:
        verbose_name = _("milestone")
        verbose_name_plural = _("milestones")
        ordering = ("due_date",)

    def __str__(self) -> str:
        return f"{self.project.name} — {self.name}"
