"""
HRM Repository Interfaces - Domain Layer Contracts.

Repository interfaces define the contract for data persistence.
Infrastructure layer provides concrete implementations.
"""
from abc import ABC, abstractmethod
from datetime import date
from decimal import Decimal
from typing import Optional, List
from uuid import UUID

from shared.base_classes.repository import BaseRepository
from ..entities.legal_entity import LegalEntity
from ..entities.location import Location
from ..entities.employee import Employee
from ..entities.employment_record import EmploymentRecord, EmployeeDocument
from ..entities.position import JobFamily, JobTitle, Position, ReportingLine
from ..entities.time_attendance import (
    WorkSchedule, ShiftPattern, Timesheet, AttendanceRecord,
)
from ..entities.leave import LeavePolicy, LeaveBalance, LeaveRequest
from ..entities.payroll import (
    PayGrade, CompensationRecord, BankAccount, CostAllocation,
)


# ─────────────────────────────────────────────
# Organization Structure Repositories
# ─────────────────────────────────────────────

class ILegalEntityRepository(BaseRepository[LegalEntity]):
    """Interface - مخزن شخصیت حقوقی."""

    @abstractmethod
    def find_by_national_id(self, national_id: str) -> Optional[LegalEntity]:
        pass

    @abstractmethod
    def find_by_registration_number(self, reg_number: str) -> Optional[LegalEntity]:
        pass

    @abstractmethod
    def find_active(self, tenant_id: UUID) -> List[LegalEntity]:
        pass


class ILocationRepository(BaseRepository[Location]):
    """Interface - مخزن مکان."""

    @abstractmethod
    def find_by_code(self, code: str) -> Optional[Location]:
        pass

    @abstractmethod
    def find_by_legal_entity(self, legal_entity_id: UUID) -> List[Location]:
        pass

    @abstractmethod
    def find_active(self, tenant_id: UUID) -> List[Location]:
        pass


# ─────────────────────────────────────────────
# Employee Master Data Repositories
# ─────────────────────────────────────────────

class IEmployeeRepository(BaseRepository[Employee]):
    """Interface - مخزن کارمند."""

    @abstractmethod
    def find_by_employee_code(self, code: str) -> Optional[Employee]:
        pass

    @abstractmethod
    def find_by_national_code(self, national_code: str) -> Optional[Employee]:
        pass

    @abstractmethod
    def find_by_org_unit(self, org_unit_id: UUID) -> List[Employee]:
        pass

    @abstractmethod
    def find_by_position(self, position_id: UUID) -> List[Employee]:
        pass

    @abstractmethod
    def find_by_manager(self, manager_id: UUID) -> List[Employee]:
        pass

    @abstractmethod
    def find_active(self, tenant_id: UUID) -> List[Employee]:
        pass

    @abstractmethod
    def search(self, query: str, tenant_id: UUID) -> List[Employee]:
        pass


class IEmploymentRecordRepository(BaseRepository[EmploymentRecord]):
    """Interface - مخزن سوابق استخدامی."""

    @abstractmethod
    def find_by_employee(self, employee_id: UUID) -> List[EmploymentRecord]:
        pass

    @abstractmethod
    def find_current(self, employee_id: UUID) -> Optional[EmploymentRecord]:
        pass


class IEmployeeDocumentRepository(BaseRepository[EmployeeDocument]):
    """Interface - مخزن مدارک کارمند."""

    @abstractmethod
    def find_by_employee(self, employee_id: UUID) -> List[EmployeeDocument]:
        pass

    @abstractmethod
    def find_expiring(self, before_date: date) -> List[EmployeeDocument]:
        pass


# ─────────────────────────────────────────────
# Position & Job Repositories
# ─────────────────────────────────────────────

class IJobFamilyRepository(BaseRepository[JobFamily]):
    """Interface - مخزن خانواده شغلی."""

    @abstractmethod
    def find_by_code(self, code: str) -> Optional[JobFamily]:
        pass


class IJobTitleRepository(BaseRepository[JobTitle]):
    """Interface - مخزن عنوان شغلی."""

    @abstractmethod
    def find_by_code(self, code: str) -> Optional[JobTitle]:
        pass

    @abstractmethod
    def find_by_family(self, family_id: UUID) -> List[JobTitle]:
        pass


class IPositionRepository(BaseRepository[Position]):
    """Interface - مخزن پست سازمانی."""

    @abstractmethod
    def find_by_code(self, code: str) -> Optional[Position]:
        pass

    @abstractmethod
    def find_by_org_unit(self, org_unit_id: UUID) -> List[Position]:
        pass

    @abstractmethod
    def find_vacant(self, tenant_id: UUID) -> List[Position]:
        pass

    @abstractmethod
    def find_by_incumbent(self, employee_id: UUID) -> Optional[Position]:
        pass

    @abstractmethod
    def find_key_positions(self, tenant_id: UUID) -> List[Position]:
        pass


class IReportingLineRepository(BaseRepository[ReportingLine]):
    """Interface - مخزن خطوط گزارش‌دهی."""

    @abstractmethod
    def find_by_employee(self, employee_id: UUID) -> List[ReportingLine]:
        pass

    @abstractmethod
    def find_direct_reports(self, manager_id: UUID) -> List[ReportingLine]:
        pass


# ─────────────────────────────────────────────
# Time & Attendance Repositories
# ─────────────────────────────────────────────

class IWorkScheduleRepository(BaseRepository[WorkSchedule]):
    """Interface - مخزن برنامه کاری."""

    @abstractmethod
    def find_by_code(self, code: str) -> Optional[WorkSchedule]:
        pass

    @abstractmethod
    def find_active(self, tenant_id: UUID) -> List[WorkSchedule]:
        pass


class IShiftPatternRepository(BaseRepository[ShiftPattern]):
    """Interface - مخزن الگوی شیفت."""
    pass


class ITimesheetRepository(BaseRepository[Timesheet]):
    """Interface - مخزن تایم‌شیت."""

    @abstractmethod
    def find_by_employee_period(
        self, employee_id: UUID, period_start: date, period_end: date
    ) -> Optional[Timesheet]:
        pass

    @abstractmethod
    def find_pending_approval(self, tenant_id: UUID) -> List[Timesheet]:
        pass


class IAttendanceRecordRepository(BaseRepository[AttendanceRecord]):
    """Interface - مخزن حضور و غیاب."""

    @abstractmethod
    def find_by_employee_date(
        self, employee_id: UUID, attendance_date: date
    ) -> Optional[AttendanceRecord]:
        pass

    @abstractmethod
    def find_by_employee_range(
        self, employee_id: UUID, start_date: date, end_date: date
    ) -> List[AttendanceRecord]:
        pass


# ─────────────────────────────────────────────
# Leave Management Repositories
# ─────────────────────────────────────────────

class ILeavePolicyRepository(BaseRepository[LeavePolicy]):
    """Interface - مخزن سیاست مرخصی."""

    @abstractmethod
    def find_by_type(self, leave_type: str, tenant_id: UUID) -> Optional[LeavePolicy]:
        pass

    @abstractmethod
    def find_active(self, tenant_id: UUID) -> List[LeavePolicy]:
        pass


class ILeaveBalanceRepository(BaseRepository[LeaveBalance]):
    """Interface - مخزن مانده مرخصی."""

    @abstractmethod
    def find_by_employee_year(
        self, employee_id: UUID, year: int
    ) -> List[LeaveBalance]:
        pass

    @abstractmethod
    def find_by_employee_type(
        self, employee_id: UUID, leave_type: str, year: int
    ) -> Optional[LeaveBalance]:
        pass


class ILeaveRequestRepository(BaseRepository[LeaveRequest]):
    """Interface - مخزن درخواست مرخصی."""

    @abstractmethod
    def find_by_employee(self, employee_id: UUID) -> List[LeaveRequest]:
        pass

    @abstractmethod
    def find_pending_approval(self, tenant_id: UUID) -> List[LeaveRequest]:
        pass

    @abstractmethod
    def find_by_date_range(
        self, employee_id: UUID, start_date: date, end_date: date
    ) -> List[LeaveRequest]:
        pass


# ─────────────────────────────────────────────
# Payroll Foundation Repositories
# ─────────────────────────────────────────────

class IPayGradeRepository(BaseRepository[PayGrade]):
    """Interface - مخزن رتبه حقوقی."""

    @abstractmethod
    def find_by_code(self, code: str) -> Optional[PayGrade]:
        pass

    @abstractmethod
    def find_active(self, tenant_id: UUID) -> List[PayGrade]:
        pass


class ICompensationRecordRepository(BaseRepository[CompensationRecord]):
    """Interface - مخزن سوابق حقوقی."""

    @abstractmethod
    def find_current(self, employee_id: UUID) -> Optional[CompensationRecord]:
        pass

    @abstractmethod
    def find_by_employee(self, employee_id: UUID) -> List[CompensationRecord]:
        pass


class IBankAccountRepository(BaseRepository[BankAccount]):
    """Interface - مخزن حساب بانکی."""

    @abstractmethod
    def find_by_employee(self, employee_id: UUID) -> List[BankAccount]:
        pass

    @abstractmethod
    def find_primary(self, employee_id: UUID) -> Optional[BankAccount]:
        pass


class ICostAllocationRepository(BaseRepository[CostAllocation]):
    """Interface - مخزن تخصیص هزینه."""

    @abstractmethod
    def find_by_employee(self, employee_id: UUID) -> List[CostAllocation]:
        pass

    @abstractmethod
    def find_by_target(
        self, allocation_type: str, target_id: UUID
    ) -> List[CostAllocation]:
        pass
