"""
Payroll Foundation - Domain Entities

ساختار حقوق و دستمزد، اطلاعات بانکی و تخصیص هزینه.
"""
from dataclasses import dataclass, field
from datetime import date
from decimal import Decimal
from typing import Optional
from uuid import UUID

from shared.base_classes.entity import TenantEntity


class PayGradeType:
    """انواع رتبه حقوقی."""
    HOURLY = "HOURLY"
    MONTHLY = "MONTHLY"
    ANNUAL = "ANNUAL"


class PaymentMethod:
    """روش پرداخت."""
    BANK_TRANSFER = "BANK_TRANSFER"
    CHECK = "CHECK"
    CASH = "CASH"


class CostAllocationType:
    """انواع تخصیص هزینه."""
    POSITION = "POSITION"
    DEPARTMENT = "DEPARTMENT"
    PROJECT = "PROJECT"
    COST_CENTER = "COST_CENTER"


@dataclass
class PayGrade(TenantEntity):
    """
    رتبه حقوقی - گروه‌بندی سطوح پرداخت.

    Rules:
    - حداقل حقوق باید کمتر یا مساوی حداکثر باشد
    - ارز پیش‌فرض ریال
    """

    name: str = ""
    code: str = ""
    grade_type: str = PayGradeType.MONTHLY
    min_amount: Decimal = Decimal("0")
    mid_amount: Decimal = Decimal("0")
    max_amount: Decimal = Decimal("0")
    currency: str = "IRR"
    step_count: int = 1
    step_increment: Decimal = Decimal("0")
    is_active: bool = True
    metadata: dict = field(default_factory=dict)

    def validate(self) -> None:
        if not self.name:
            raise ValueError("نام رتبه حقوقی الزامی است")
        if self.min_amount < 0:
            raise ValueError("حداقل حقوق نمی‌تواند منفی باشد")
        if self.max_amount < self.min_amount:
            raise ValueError("حداکثر حقوق نمی‌تواند کمتر از حداقل باشد")

    def get_step_amount(self, step: int) -> Decimal:
        """محاسبه مبلغ بر اساس پله."""
        if step < 1 or step > self.step_count:
            raise ValueError(f"پله باید بین ۱ تا {self.step_count} باشد")
        return self.min_amount + (self.step_increment * (step - 1))


@dataclass
class CompensationRecord(TenantEntity):
    """
    سابقه حقوق و مزایا - Aggregate Root.

    Rules:
    - هر کارمند یک رکورد فعال
    - تاریخ مؤثر الزامی
    """

    employee_id: UUID = field(default_factory=lambda: None)
    pay_grade_id: Optional[UUID] = None
    base_salary: Decimal = Decimal("0")
    housing_allowance: Decimal = Decimal("0")
    transportation_allowance: Decimal = Decimal("0")
    food_allowance: Decimal = Decimal("0")
    family_allowance: Decimal = Decimal("0")
    overtime_rate: Decimal = Decimal("1.4")
    holiday_rate: Decimal = Decimal("1.4")
    night_shift_rate: Decimal = Decimal("1.35")
    currency: str = "IRR"
    pay_grade_step: int = 1
    effective_date: Optional[date] = None
    end_date: Optional[date] = None
    is_current: bool = True
    change_reason: str = ""
    metadata: dict = field(default_factory=dict)

    @property
    def total_monthly(self) -> Decimal:
        """محاسبه مجموع حقوق ماهانه."""
        return (
            self.base_salary
            + self.housing_allowance
            + self.transportation_allowance
            + self.food_allowance
            + self.family_allowance
        )

    def validate(self) -> None:
        if not self.employee_id:
            raise ValueError("شناسه کارمند الزامی است")
        if self.base_salary < 0:
            raise ValueError("حقوق پایه نمی‌تواند منفی باشد")
        if not self.effective_date:
            raise ValueError("تاریخ مؤثر الزامی است")

    def end(self, end_date: date, reason: str = "") -> None:
        """پایان دادن به رکورد فعلی."""
        self.end_date = end_date
        self.is_current = False
        self.change_reason = reason
        self.mark_updated()


@dataclass
class BankAccount(TenantEntity):
    """
    اطلاعات حساب بانکی کارمند.

    Rules:
    - شماره شبا باید ۲۶ کاراکتر باشد
    - حداکثر یک حساب اصلی
    """

    employee_id: UUID = field(default_factory=lambda: None)
    bank_name: str = ""
    branch_name: str = ""
    branch_code: str = ""
    account_number: str = ""
    sheba_number: str = ""
    card_number: str = ""
    account_holder_name: str = ""
    is_primary: bool = False
    is_active: bool = True
    metadata: dict = field(default_factory=dict)

    def validate(self) -> None:
        if not self.employee_id:
            raise ValueError("شناسه کارمند الزامی است")
        if not self.bank_name:
            raise ValueError("نام بانک الزامی است")
        if not self.account_number:
            raise ValueError("شماره حساب الزامی است")
        if self.sheba_number and len(self.sheba_number) != 26:
            raise ValueError("شماره شبا باید ۲۶ کاراکتر باشد")


@dataclass
class CostAllocation(TenantEntity):
    """
    تخصیص هزینه نیروی انسانی.

    Rules:
    - مجموع درصد تخصیص‌ها نباید از ۱۰۰ تجاوز کند
    """

    employee_id: UUID = field(default_factory=lambda: None)
    allocation_type: str = CostAllocationType.DEPARTMENT
    target_id: UUID = field(default_factory=lambda: None)
    target_code: str = ""
    percentage: Decimal = Decimal("100")
    gl_account_code: str = ""
    effective_date: Optional[date] = None
    end_date: Optional[date] = None
    is_active: bool = True
    metadata: dict = field(default_factory=dict)

    def validate(self) -> None:
        if not self.employee_id:
            raise ValueError("شناسه کارمند الزامی است")
        if not self.target_id:
            raise ValueError("شناسه مقصد تخصیص الزامی است")
        if self.percentage <= 0 or self.percentage > 100:
            raise ValueError("درصد تخصیص باید بین ۰ تا ۱۰۰ باشد")
