"""
Contract — Domain 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 modules.clm.backend.domain.exceptions.contract_exceptions import (
    InvalidContractStateTransition,
)


# ═══════════════════════════════════════════════════
# Enums
# ═══════════════════════════════════════════════════

class ContractCategory:
    """دسته‌بندی اصلی قرارداد."""
    COMMERCIAL = "COMMERCIAL"
    PROJECT = "PROJECT"
    EMPLOYMENT = "EMPLOYMENT"
    LEASE = "LEASE"


class ContractType:
    """نوع قرارداد."""
    # Commercial
    PURCHASE = "PURCHASE"
    SALE = "SALE"
    SERVICE = "SERVICE"
    PARTNERSHIP = "PARTNERSHIP"
    DISTRIBUTION = "DISTRIBUTION"
    AGENCY = "AGENCY"
    # Project
    EPC = "EPC"
    CONTRACTOR = "CONTRACTOR"
    SUBCONTRACTOR = "SUBCONTRACTOR"
    CONSULTING = "CONSULTING"
    # Employment
    PERMANENT = "PERMANENT"
    TEMPORARY = "TEMPORARY"
    CONSULTANCY = "CONSULTANCY"
    INTERNSHIP = "INTERNSHIP"
    # Lease
    PROPERTY_LEASE = "PROPERTY_LEASE"
    EQUIPMENT_LEASE = "EQUIPMENT_LEASE"
    VEHICLE_LEASE = "VEHICLE_LEASE"


class ContractStatus:
    """وضعیت قرارداد."""
    DRAFT = "DRAFT"
    PENDING_APPROVAL = "PENDING_APPROVAL"
    APPROVED = "APPROVED"
    ACTIVE = "ACTIVE"
    SUSPENDED = "SUSPENDED"
    COMPLETED = "COMPLETED"
    TERMINATED = "TERMINATED"
    EXPIRED = "EXPIRED"
    CANCELLED = "CANCELLED"


class ContractPriority:
    """اولویت قرارداد."""
    LOW = "LOW"
    NORMAL = "NORMAL"
    HIGH = "HIGH"
    CRITICAL = "CRITICAL"


# ═══════════════════════════════════════════════════
# Aggregate Root
# ═══════════════════════════════════════════════════

@dataclass
class Contract(TenantEntity):
    """
    قرارداد — Aggregate Root.

    Rules:
    - شماره قرارداد باید یکتا در هر tenant باشد
    - تاریخ پایان نمی‌تواند قبل از تاریخ شروع باشد
    - مبلغ کل باید صفر یا بیشتر باشد
    - تغییر وضعیت فقط از طریق state machine مجاز
    - خاتمه فقط برای قراردادهای فعال یا تعلیق‌شده
    """

    # Basic Info
    contract_number: str = ""
    title: str = ""
    description: str = ""
    category: str = ContractCategory.COMMERCIAL
    contract_type: str = ContractType.SERVICE
    status: str = ContractStatus.DRAFT
    priority: str = ContractPriority.NORMAL

    # Dates
    start_date: Optional[date] = None
    end_date: Optional[date] = None
    signing_date: Optional[date] = None
    effective_date: Optional[date] = None
    expiry_date: Optional[date] = None

    # Financial
    total_value: Decimal = Decimal("0")
    currency_id: Optional[UUID] = None
    payment_terms_days: int = 30
    payment_terms_description: str = ""
    advance_payment_percent: Decimal = Decimal("0")
    retention_percent: Decimal = Decimal("0")
    penalty_rate_per_day: Decimal = Decimal("0")

    # Guarantee
    guarantee_amount: Decimal = Decimal("0")
    guarantee_type: str = ""  # BANK_GUARANTEE, PROMISSORY_NOTE, CHECK, CASH
    guarantee_expiry_date: Optional[date] = None
    performance_bond_amount: Decimal = Decimal("0")
    performance_bond_expiry_date: Optional[date] = None

    # Renewal
    auto_renew: bool = False
    renewal_period_days: int = 365
    renewal_notice_days: int = 30
    max_renewals: int = 0
    renewals_count: int = 0

    # Relations (UUID only — no cross-module FK)
    parent_contract_id: Optional[UUID] = None
    project_id: Optional[UUID] = None
    org_unit_id: Optional[UUID] = None
    legal_entity_id: Optional[UUID] = None
    responsible_person_id: Optional[UUID] = None
    employee_id: Optional[UUID] = None  # For employment contracts

    # Metadata
    reference_number: str = ""
    tags: str = ""
    notes: str = ""
    metadata: dict = field(default_factory=dict)
    is_active: bool = True
    is_confidential: bool = False

    # ── Business Rules ──────────────────────────

    def validate(self) -> List[str]:
        """اعتبارسنجی قوانین کسب‌وکار."""
        errors = []
        if not self.contract_number:
            errors.append("شماره قرارداد الزامی است")
        if not self.title:
            errors.append("عنوان قرارداد الزامی است")
        if self.start_date and self.end_date and self.end_date < self.start_date:
            errors.append("تاریخ پایان نمی‌تواند قبل از تاریخ شروع باشد")
        if self.total_value < 0:
            errors.append("مبلغ قرارداد نمی‌تواند منفی باشد")
        if self.advance_payment_percent < 0 or self.advance_payment_percent > 100:
            errors.append("درصد پیش‌پرداخت باید بین ۰ و ۱۰۰ باشد")
        if self.retention_percent < 0 or self.retention_percent > 100:
            errors.append("درصد حسن انجام کار باید بین ۰ و ۱۰۰ باشد")
        return errors

    def can_approve(self) -> bool:
        """آیا قرارداد قابل تأیید است؟"""
        return self.status == ContractStatus.DRAFT or self.status == ContractStatus.PENDING_APPROVAL

    def approve(self) -> None:
        """تأیید قرارداد."""
        if not self.can_approve():
            raise InvalidContractStateTransition(self.status, ContractStatus.APPROVED)
        self.status = ContractStatus.APPROVED

    def reject(self) -> None:
        """رد قرارداد."""
        if self.status != ContractStatus.PENDING_APPROVAL:
            raise InvalidContractStateTransition(self.status, ContractStatus.DRAFT)
        self.status = ContractStatus.DRAFT

    def activate(self) -> None:
        """فعال‌سازی قرارداد."""
        if self.status != ContractStatus.APPROVED:
            raise InvalidContractStateTransition(self.status, ContractStatus.ACTIVE)
        self.status = ContractStatus.ACTIVE

    def suspend(self) -> None:
        """تعلیق قرارداد."""
        if self.status != ContractStatus.ACTIVE:
            raise InvalidContractStateTransition(self.status, ContractStatus.SUSPENDED)
        self.status = ContractStatus.SUSPENDED

    def resume(self) -> None:
        """ازسرگیری قرارداد."""
        if self.status != ContractStatus.SUSPENDED:
            raise InvalidContractStateTransition(self.status, ContractStatus.ACTIVE)
        self.status = ContractStatus.ACTIVE

    def complete(self) -> None:
        """اتمام قرارداد."""
        if self.status != ContractStatus.ACTIVE:
            raise InvalidContractStateTransition(self.status, ContractStatus.COMPLETED)
        self.status = ContractStatus.COMPLETED

    def terminate(self, reason: str = "") -> None:
        """خاتمه قرارداد."""
        if self.status not in (ContractStatus.ACTIVE, ContractStatus.SUSPENDED):
            raise InvalidContractStateTransition(self.status, ContractStatus.TERMINATED)
        self.status = ContractStatus.TERMINATED

    def cancel(self) -> None:
        """لغو قرارداد."""
        if self.status in (ContractStatus.COMPLETED, ContractStatus.TERMINATED, ContractStatus.CANCELLED):
            raise InvalidContractStateTransition(self.status, ContractStatus.CANCELLED)
        self.status = ContractStatus.CANCELLED

    def mark_expired(self) -> None:
        """منقضی شدن قرارداد."""
        if self.status != ContractStatus.ACTIVE:
            raise InvalidContractStateTransition(self.status, ContractStatus.EXPIRED)
        self.status = ContractStatus.EXPIRED

    def submit_for_approval(self) -> None:
        """ارسال برای تأیید."""
        if self.status != ContractStatus.DRAFT:
            raise InvalidContractStateTransition(self.status, ContractStatus.PENDING_APPROVAL)
        errors = self.validate()
        if errors:
            raise ValueError(f"خطاهای اعتبارسنجی: {'; '.join(errors)}")
        self.status = ContractStatus.PENDING_APPROVAL

    @property
    def is_expired(self) -> bool:
        """آیا قرارداد منقضی شده؟"""
        if self.expiry_date and self.status == ContractStatus.ACTIVE:
            return date.today() > self.expiry_date
        return self.status == ContractStatus.EXPIRED

    @property
    def days_to_expiry(self) -> Optional[int]:
        """تعداد روز تا انقضا."""
        if self.expiry_date and self.status == ContractStatus.ACTIVE:
            return (self.expiry_date - date.today()).days
        return None

    @property
    def can_renew(self) -> bool:
        """آیا قرارداد قابل تمدید است؟"""
        if self.max_renewals > 0 and self.renewals_count >= self.max_renewals:
            return False
        return self.status in (ContractStatus.ACTIVE, ContractStatus.EXPIRED)

    @property
    def net_value(self) -> Decimal:
        """مبلغ خالص (بعد از کسر حسن انجام کار)."""
        return self.total_value * (1 - self.retention_percent / 100)
