"""
Job & Position - Domain Entities

معماری شغلی و مدیریت پست‌های سازمانی.
"""
from dataclasses import dataclass, field
from datetime import date
from typing import Optional, List
from uuid import UUID

from shared.base_classes.entity import TenantEntity


class JobLevel:
    """سطح شغلی."""
    INTERN = "INTERN"
    JUNIOR = "JUNIOR"
    MID = "MID"
    SENIOR = "SENIOR"
    LEAD = "LEAD"
    MANAGER = "MANAGER"
    DIRECTOR = "DIRECTOR"
    VP = "VP"
    C_LEVEL = "C_LEVEL"


class PositionStatus:
    """وضعیت پست سازمانی."""
    ACTIVE = "ACTIVE"
    FROZEN = "FROZEN"
    ABOLISHED = "ABOLISHED"


@dataclass
class JobFamily(TenantEntity):
    """
    خانواده شغلی - گروه‌بندی مشاغل مرتبط.

    Rules:
    - نام و کد یکتا در هر tenant
    """

    name: str = ""
    code: str = ""
    description: str = ""
    is_active: bool = True

    def validate(self) -> None:
        if not self.name:
            raise ValueError("نام خانواده شغلی الزامی است")
        if not self.code:
            raise ValueError("کد خانواده شغلی الزامی است")


@dataclass
class JobTitle(TenantEntity):
    """
    عنوان شغلی - تعریف شغل با شرح وظایف.

    Rules:
    - عنوان و کد یکتا
    - سطح شغلی باید مشخص باشد
    """

    title: str = ""
    title_en: str = ""
    code: str = ""
    job_family_id: Optional[UUID] = None
    level: str = JobLevel.MID
    grade: int = 0
    description: str = ""
    responsibilities: str = ""
    qualifications: str = ""
    min_experience_years: int = 0
    is_active: bool = True
    metadata: dict = field(default_factory=dict)

    def validate(self) -> None:
        if not self.title:
            raise ValueError("عنوان شغلی الزامی است")
        if not self.code:
            raise ValueError("کد شغلی الزامی است")


@dataclass
class Position(TenantEntity):
    """
    پست سازمانی - Aggregate Root.

    هر پست یک موقعیت خاص در ساختار سازمانی است.
    پست می‌تواند خالی یا پر باشد.

    Rules:
    - هر پست به یک واحد سازمانی تعلق دارد
    - حداکثر یک نفر incumbent در هر لحظه
    - بودجه باید مثبت باشد
    """

    title: str = ""
    code: str = ""
    job_title_id: Optional[UUID] = None
    org_unit_id: Optional[UUID] = None
    legal_entity_id: Optional[UUID] = None
    location_id: Optional[UUID] = None
    reports_to_position_id: Optional[UUID] = None
    functional_reports_to_id: Optional[UUID] = None
    incumbent_employee_id: Optional[UUID] = None
    status: str = PositionStatus.ACTIVE
    is_key_position: bool = False
    is_budgeted: bool = True
    budget_amount: float = 0.0
    headcount: int = 1
    fte: float = 1.0
    effective_date: Optional[date] = None
    end_date: Optional[date] = None
    successor_employee_ids: list = field(default_factory=list)
    metadata: dict = field(default_factory=dict)

    @property
    def is_vacant(self) -> bool:
        """بررسی خالی بودن پست."""
        return self.incumbent_employee_id is None

    def validate(self) -> None:
        if not self.title:
            raise ValueError("عنوان پست الزامی است")
        if not self.code:
            raise ValueError("کد پست الزامی است")
        if self.budget_amount < 0:
            raise ValueError("بودجه نمی‌تواند منفی باشد")
        if self.headcount < 0:
            raise ValueError("تعداد نیرو نمی‌تواند منفی باشد")

    def fill(self, employee_id: UUID) -> None:
        """تخصیص کارمند به پست."""
        if not self.is_vacant:
            raise ValueError("پست قبلاً پر شده است")
        if self.status != PositionStatus.ACTIVE:
            raise ValueError("فقط پست‌های فعال قابل تخصیص هستند")
        self.incumbent_employee_id = employee_id
        self.mark_updated()

    def vacate(self) -> None:
        """خالی کردن پست."""
        self.incumbent_employee_id = None
        self.mark_updated()

    def freeze(self) -> None:
        """انجماد پست."""
        if self.status != PositionStatus.ACTIVE:
            raise ValueError("فقط پست‌های فعال قابل انجماد هستند")
        self.status = PositionStatus.FROZEN
        self.mark_updated()

    def abolish(self) -> None:
        """حذف پست."""
        if not self.is_vacant:
            raise ValueError("پست باید ابتدا خالی شود")
        self.status = PositionStatus.ABOLISHED
        self.mark_updated()


@dataclass
class ReportingLine(TenantEntity):
    """
    خط گزارش‌دهی.

    Rules:
    - هر کارمند یک گزارش‌دهی مستقیم و چند نقطه‌چین
    """

    employee_id: UUID = field(default_factory=lambda: None)
    manager_id: UUID = field(default_factory=lambda: None)
    reporting_type: str = "DIRECT"  # DIRECT, FUNCTIONAL, MATRIX, DOTTED
    is_primary: bool = True
    effective_date: Optional[date] = None
    end_date: Optional[date] = None

    def validate(self) -> None:
        if not self.employee_id:
            raise ValueError("شناسه کارمند الزامی است")
        if not self.manager_id:
            raise ValueError("شناسه مدیر الزامی است")
        if self.employee_id == self.manager_id:
            raise ValueError("کارمند نمی‌تواند مدیر خودش باشد")
