"""
Inventory Domain Repository Interfaces.

اینترفیس‌های ریپازیتوری دامنه — فقط ABC (بدون پیاده‌سازی).
"""
from abc import ABC, abstractmethod
from datetime import date
from decimal import Decimal
from typing import List, Optional
from uuid import UUID


class IItemRepository(ABC):
    """ریپازیتوری کالا."""

    @abstractmethod
    def get_by_id(self, item_id: UUID) -> Optional["Item"]:
        ...

    @abstractmethod
    def find_by_code(self, code: str) -> Optional["Item"]:
        ...

    @abstractmethod
    def find_by_group(self, group_id: UUID) -> List["Item"]:
        ...

    @abstractmethod
    def save(self, entity) -> "Item":
        ...

    @abstractmethod
    def list_all(self, **filters) -> List["Item"]:
        ...


class IWarehouseRepository(ABC):
    """ریپازیتوری انبار."""

    @abstractmethod
    def get_by_id(self, warehouse_id: UUID) -> Optional["Warehouse"]:
        ...

    @abstractmethod
    def find_by_code(self, code: str) -> Optional["Warehouse"]:
        ...

    @abstractmethod
    def save(self, entity) -> "Warehouse":
        ...

    @abstractmethod
    def list_all(self, **filters) -> List["Warehouse"]:
        ...


class IStockLedgerRepository(ABC):
    """ریپازیتوری دفتر کل موجودی."""

    @abstractmethod
    def save(self, entity) -> "StockLedgerEntry":
        ...

    @abstractmethod
    def get_by_id(self, sle_id: UUID) -> Optional["StockLedgerEntry"]:
        ...

    @abstractmethod
    def find_by_item_warehouse(
        self, item_id: UUID, warehouse_id: UUID,
        from_date: Optional[date] = None,
        to_date: Optional[date] = None,
    ) -> List["StockLedgerEntry"]:
        ...

    @abstractmethod
    def find_by_document(
        self, doc_type: str, doc_id: UUID,
    ) -> List["StockLedgerEntry"]:
        ...


class IStockBalanceRepository(ABC):
    """ریپازیتوری موجودی فعلی."""

    @abstractmethod
    def get_balance(
        self, item_id: UUID, warehouse_id: UUID,
        batch_id: Optional[UUID] = None,
        location_id: Optional[UUID] = None,
        stock_status_id: Optional[UUID] = None,
    ) -> Optional["StockBalance"]:
        ...

    @abstractmethod
    def save(self, entity) -> "StockBalance":
        ...

    @abstractmethod
    def find_by_item(self, item_id: UUID) -> List["StockBalance"]:
        ...

    @abstractmethod
    def find_by_warehouse(self, warehouse_id: UUID) -> List["StockBalance"]:
        ...


class IBatchRepository(ABC):
    """ریپازیتوری بچ."""

    @abstractmethod
    def get_by_id(self, batch_id: UUID) -> Optional["Batch"]:
        ...

    @abstractmethod
    def find_by_number(self, batch_number: str) -> Optional["Batch"]:
        ...

    @abstractmethod
    def find_expiring_before(self, date: date) -> List["Batch"]:
        ...

    @abstractmethod
    def save(self, entity) -> "Batch":
        ...


class ISerialNumberRepository(ABC):
    """ریپازیتوری شماره سریال."""

    @abstractmethod
    def get_by_id(self, serial_id: UUID) -> Optional["SerialNumber"]:
        ...

    @abstractmethod
    def find_by_serial_no(self, serial_no: str) -> Optional["SerialNumber"]:
        ...

    @abstractmethod
    def find_by_item(self, item_id: UUID) -> List["SerialNumber"]:
        ...

    @abstractmethod
    def save(self, entity) -> "SerialNumber":
        ...


class IStockReservationRepository(ABC):
    """ریپازیتوری رزرو."""

    @abstractmethod
    def get_by_id(self, reservation_id: UUID) -> Optional["StockReservation"]:
        ...

    @abstractmethod
    def find_active_by_item(self, item_id: UUID) -> List["StockReservation"]:
        ...

    @abstractmethod
    def find_expired(self) -> List["StockReservation"]:
        ...

    @abstractmethod
    def save(self, entity) -> "StockReservation":
        ...


class ICostLayerRepository(ABC):
    """ریپازیتوری لایه هزینه."""

    @abstractmethod
    def find_available_layers(
        self, item_id: UUID, warehouse_id: UUID
    ) -> List["CostLayer"]:
        ...

    @abstractmethod
    def save(self, entity) -> "CostLayer":
        ...


class IPhysicalInventoryRepository(ABC):
    """ریپازیتوری شمارش فیزیکی."""

    @abstractmethod
    def get_by_id(self, pi_id: UUID) -> Optional["PhysicalInventory"]:
        ...

    @abstractmethod
    def save(self, entity) -> "PhysicalInventory":
        ...


class IInspectionLotRepository(ABC):
    """ریپازیتوری بازرسی."""

    @abstractmethod
    def get_by_id(self, lot_id: UUID) -> Optional["InspectionLot"]:
        ...

    @abstractmethod
    def save(self, entity) -> "InspectionLot":
        ...

    @abstractmethod
    def find_pending(self) -> List["InspectionLot"]:
        ...
