"""
PM Module — Project Entity

پروژه — Aggregate Root اصلی ماژول مدیریت پروژه.
"""

from dataclasses import dataclass, field
from datetime import date, datetime
from decimal import Decimal
from typing import Optional, List
from uuid import UUID, uuid4

from shared.base_classes.entity import TenantEntity

from ..value_objects.common import (
    ProjectStatus,
    ProjectPriority,
    ProjectType,
    DateRange,
    Percentage,
)


@dataclass
class Project(TenantEntity):
    """
    پروژه — Aggregate Root.

    یکپارچه‌سازی:
    - company_id → FK به Company (پلتفرم)
    - org_unit_id → FK به OrganizationalUnit (پلتفرم) — unit_type=PROJECT
    - currency_id → FK به Currency (پلتفرم)
    - parent_id → Self FK (پورتفولیو > برنامه > پروژه > زیرپروژه)
    - manager_id → FK به User (پلتفرم)
    """

    # --- Identity & Metadata ---
    code: str = ""
    title: str = ""
    description: str = ""

    # --- Type & Hierarchy ---
    project_type: ProjectType = ProjectType.PROJECT
    parent_id: Optional[UUID] = None  # سلسله مراتب

    # --- Status ---
    status: ProjectStatus = ProjectStatus.DRAFT
    priority: ProjectPriority = ProjectPriority.MEDIUM

    # --- Dates ---
    planned_start: Optional[date] = None
    planned_end: Optional[date] = None
    actual_start: Optional[date] = None
    actual_end: Optional[date] = None

    # --- Progress ---
    progress: int = 0  # 0-100

    # --- Budget & Cost ---
    total_budget: Decimal = Decimal("0")
    actual_cost: Decimal = Decimal("0")
    estimated_cost: Decimal = Decimal("0")

    # --- Integration: Platform FK's ---
    company_id: Optional[UUID] = None       # → Company
    org_unit_id: Optional[UUID] = None      # → OrganizationalUnit
    currency_id: Optional[UUID] = None      # → Currency
    manager_id: Optional[UUID] = None       # → User

    # --- Calendar & Settings ---
    calendar_id: Optional[UUID] = None
    color: str = "#3B82F6"
    tags: Optional[list] = field(default_factory=list)
    metadata: Optional[dict] = field(default_factory=dict)

    # ─── Business Rules ───

    def can_start(self) -> bool:
        return self.status == ProjectStatus.PLANNING and self.planned_start is not None

    def start(self) -> None:
        if not self.can_start():
            raise ValueError("پروژه قابل شروع نیست")
        self.status = ProjectStatus.ACTIVE
        self.actual_start = date.today()

    def complete(self) -> None:
        if self.status != ProjectStatus.ACTIVE:
            raise ValueError("فقط پروژه‌های فعال قابل تکمیل هستند")
        self.status = ProjectStatus.COMPLETED
        self.actual_end = date.today()
        self.progress = 100

    def cancel(self) -> None:
        if self.status in (ProjectStatus.COMPLETED, ProjectStatus.ARCHIVED):
            raise ValueError("پروژه تکمیل‌شده یا آرشیوشده قابل لغو نیست")
        self.status = ProjectStatus.CANCELLED

    def put_on_hold(self) -> None:
        if self.status != ProjectStatus.ACTIVE:
            raise ValueError("فقط پروژه‌های فعال می‌توانند متوقف شوند")
        self.status = ProjectStatus.ON_HOLD

    def resume(self) -> None:
        if self.status != ProjectStatus.ON_HOLD:
            raise ValueError("فقط پروژه‌های متوقف‌شده قابل ازسرگیری هستند")
        self.status = ProjectStatus.ACTIVE

    def update_progress(self, progress: int) -> None:
        if not (0 <= progress <= 100):
            raise ValueError("پیشرفت باید بین ۰ تا ۱۰۰ باشد")
        self.progress = progress

    @property
    def is_overdue(self) -> bool:
        if self.planned_end and self.status == ProjectStatus.ACTIVE:
            return date.today() > self.planned_end
        return False

    @property
    def budget_variance(self) -> Decimal:
        return self.total_budget - self.actual_cost

    @property
    def planned_duration(self) -> Optional[int]:
        if self.planned_start and self.planned_end:
            return (self.planned_end - self.planned_start).days + 1
        return None

    @property
    def actual_duration(self) -> Optional[int]:
        end = self.actual_end or date.today()
        if self.actual_start:
            return (end - self.actual_start).days + 1
        return None
