"""
PM Module — Issue Entity

مدیریت مسائل پروژه (Issue Log).
Issue مشکلی است که هم‌اکنون رخ داده و نیاز به اقدام دارد.
"""

from dataclasses import dataclass, field
from datetime import date
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 (
    IssueCategory,
    IssueSeverity,
    IssuePriority,
    IssueStatus,
)


@dataclass
class Issue(TenantEntity):
    """
    مسئله پروژه — Entity.

    Issue یک مشکل واقعی است (بر خلاف Risk که بالقوه است).
    """

    project_id: UUID = field(default_factory=uuid4)

    code: str = ""                    # ISS-001, ISS-002, ...
    title: str = ""
    description: str = ""

    # --- Classification ---
    category: IssueCategory = IssueCategory.OTHER
    severity: IssueSeverity = IssueSeverity.MODERATE
    priority: IssuePriority = IssuePriority.MEDIUM
    status: IssueStatus = IssueStatus.OPEN

    # --- People ---
    reporter_id: Optional[UUID] = None    # → User (گزارش‌دهنده)
    assignee_id: Optional[UUID] = None    # → User (مسئول رسیدگی)

    # --- Relations ---
    affected_tasks: Optional[list] = field(default_factory=list)  # [UUID]
    related_risk_id: Optional[UUID] = None  # → Risk (اگر از ریسک ناشی شده)

    # --- Resolution ---
    resolution: str = ""
    impact_description: str = ""

    # --- Impact ---
    cost_impact: Decimal = Decimal("0")
    schedule_impact_days: int = 0

    # --- Dates ---
    identified_date: Optional[date] = None
    due_date: Optional[date] = None
    resolved_date: Optional[date] = None
    closed_date: Optional[date] = None

    # --- Metadata ---
    notes: str = ""
    metadata: Optional[dict] = field(default_factory=dict)

    # ─── Business Rules ───

    def assign(self, assignee_id: UUID) -> None:
        """تخصیص Issue به کاربر."""
        self.assignee_id = assignee_id
        if self.status == IssueStatus.OPEN:
            self.status = IssueStatus.IN_PROGRESS

    def resolve(self, resolution: str) -> None:
        """حل Issue."""
        if not resolution.strip():
            raise ValueError("شرح راه‌حل اجباری است")
        if self.status == IssueStatus.CLOSED:
            raise ValueError("مسئله بسته‌شده قابل حل مجدد نیست")
        self.resolution = resolution
        self.status = IssueStatus.RESOLVED
        self.resolved_date = date.today()

    def close(self) -> None:
        """بستن Issue — فقط از وضعیت RESOLVED."""
        if self.status != IssueStatus.RESOLVED:
            raise ValueError("فقط مسائل حل‌شده قابل بستن هستند")
        self.status = IssueStatus.CLOSED
        self.closed_date = date.today()

    def reopen(self) -> None:
        """بازگشایی Issue — از RESOLVED یا CLOSED."""
        if self.status not in (IssueStatus.RESOLVED, IssueStatus.CLOSED):
            raise ValueError("فقط مسائل حل‌شده یا بسته‌شده قابل بازگشایی هستند")
        self.status = IssueStatus.OPEN
        self.resolved_date = None
        self.closed_date = None
        self.resolution = ""

    def put_on_hold(self) -> None:
        """متوقف کردن."""
        if self.status not in (IssueStatus.OPEN, IssueStatus.IN_PROGRESS):
            raise ValueError("فقط مسائل باز یا در حال انجام قابل توقف هستند")
        self.status = IssueStatus.ON_HOLD

    def resume(self) -> None:
        """از سرگیری."""
        if self.status != IssueStatus.ON_HOLD:
            raise ValueError("فقط مسائل متوقف قابل ازسرگیری هستند")
        self.status = IssueStatus.IN_PROGRESS if self.assignee_id else IssueStatus.OPEN

    @property
    def is_overdue(self) -> bool:
        """آیا از مهلت رسیدگی گذشته؟"""
        if self.due_date and self.status not in (IssueStatus.RESOLVED, IssueStatus.CLOSED):
            return date.today() > self.due_date
        return False

    @property
    def is_critical(self) -> bool:
        """آیا بحرانی است؟"""
        return (
            self.severity == IssueSeverity.CRITICAL
            or self.priority == IssuePriority.CRITICAL
        )
