"""
SCM Domain Repository Interfaces.

اینترفیس‌های Repository برای تمام Aggregate Root‌های ماژول SCM.
"""
from abc import ABC, abstractmethod
from typing import Optional, List
from uuid import UUID

from ..entities.vendor import Vendor, VendorCategory
from ..entities.purchase_requisition import PurchaseRequisition
from ..entities.rfq import RFQ
from ..entities.purchase_order import PurchaseOrder
from ..entities.goods_receipt import GoodsReceipt
from ..entities.purchase_return import PurchaseReturn
from ..entities.vendor_evaluation import (
    VendorEvaluation, EvaluationCriteria, EvaluationPeriod,
)
from ..entities.price_management import VendorPriceList, PurchaseDiscount


class IVendorRepository(ABC):
    @abstractmethod
    def save(self, vendor: Vendor) -> Vendor: ...

    @abstractmethod
    def get_by_id(self, vendor_id: UUID) -> Optional[Vendor]: ...

    @abstractmethod
    def find_by_code(self, code: str) -> Optional[Vendor]: ...

    @abstractmethod
    def find(self, **criteria) -> List[Vendor]: ...

    @abstractmethod
    def delete(self, vendor_id: UUID) -> bool: ...

    @abstractmethod
    def exists(self, vendor_id: UUID) -> bool: ...

    @abstractmethod
    def count(self, **criteria) -> int: ...


class IVendorCategoryRepository(ABC):
    @abstractmethod
    def save(self, category: VendorCategory) -> VendorCategory: ...

    @abstractmethod
    def get_by_id(self, category_id: UUID) -> Optional[VendorCategory]: ...

    @abstractmethod
    def find_by_code(self, code: str) -> Optional[VendorCategory]: ...

    @abstractmethod
    def find(self, **criteria) -> List[VendorCategory]: ...

    @abstractmethod
    def delete(self, category_id: UUID) -> bool: ...


class IPurchaseRequisitionRepository(ABC):
    @abstractmethod
    def save(self, pr: PurchaseRequisition) -> PurchaseRequisition: ...

    @abstractmethod
    def get_by_id(self, pr_id: UUID) -> Optional[PurchaseRequisition]: ...

    @abstractmethod
    def find_by_number(self, number: str) -> Optional[PurchaseRequisition]: ...

    @abstractmethod
    def find(self, **criteria) -> List[PurchaseRequisition]: ...

    @abstractmethod
    def delete(self, pr_id: UUID) -> bool: ...

    @abstractmethod
    def generate_number(self, tenant_id: UUID) -> str: ...


class IRFQRepository(ABC):
    @abstractmethod
    def save(self, rfq: RFQ) -> RFQ: ...

    @abstractmethod
    def get_by_id(self, rfq_id: UUID) -> Optional[RFQ]: ...

    @abstractmethod
    def find_by_number(self, number: str) -> Optional[RFQ]: ...

    @abstractmethod
    def find(self, **criteria) -> List[RFQ]: ...

    @abstractmethod
    def delete(self, rfq_id: UUID) -> bool: ...

    @abstractmethod
    def generate_number(self, tenant_id: UUID) -> str: ...


class IPurchaseOrderRepository(ABC):
    @abstractmethod
    def save(self, po: PurchaseOrder) -> PurchaseOrder: ...

    @abstractmethod
    def get_by_id(self, po_id: UUID) -> Optional[PurchaseOrder]: ...

    @abstractmethod
    def find_by_number(self, number: str) -> Optional[PurchaseOrder]: ...

    @abstractmethod
    def find(self, **criteria) -> List[PurchaseOrder]: ...

    @abstractmethod
    def delete(self, po_id: UUID) -> bool: ...

    @abstractmethod
    def generate_number(self, tenant_id: UUID) -> str: ...


class IGoodsReceiptRepository(ABC):
    @abstractmethod
    def save(self, gr: GoodsReceipt) -> GoodsReceipt: ...

    @abstractmethod
    def get_by_id(self, gr_id: UUID) -> Optional[GoodsReceipt]: ...

    @abstractmethod
    def find_by_number(self, number: str) -> Optional[GoodsReceipt]: ...

    @abstractmethod
    def find(self, **criteria) -> List[GoodsReceipt]: ...

    @abstractmethod
    def delete(self, gr_id: UUID) -> bool: ...

    @abstractmethod
    def generate_number(self, tenant_id: UUID) -> str: ...


class IPurchaseReturnRepository(ABC):
    @abstractmethod
    def save(self, ret: PurchaseReturn) -> PurchaseReturn: ...

    @abstractmethod
    def get_by_id(self, return_id: UUID) -> Optional[PurchaseReturn]: ...

    @abstractmethod
    def find_by_number(self, number: str) -> Optional[PurchaseReturn]: ...

    @abstractmethod
    def find(self, **criteria) -> List[PurchaseReturn]: ...

    @abstractmethod
    def delete(self, return_id: UUID) -> bool: ...

    @abstractmethod
    def generate_number(self, tenant_id: UUID) -> str: ...


class IVendorEvaluationRepository(ABC):
    @abstractmethod
    def save(self, evaluation: VendorEvaluation) -> VendorEvaluation: ...

    @abstractmethod
    def get_by_id(self, evaluation_id: UUID) -> Optional[VendorEvaluation]: ...

    @abstractmethod
    def find(self, **criteria) -> List[VendorEvaluation]: ...

    @abstractmethod
    def delete(self, evaluation_id: UUID) -> bool: ...


class IEvaluationCriteriaRepository(ABC):
    @abstractmethod
    def save(self, criteria: EvaluationCriteria) -> EvaluationCriteria: ...

    @abstractmethod
    def get_by_id(self, criteria_id: UUID) -> Optional[EvaluationCriteria]: ...

    @abstractmethod
    def find(self, **criteria_filters) -> List[EvaluationCriteria]: ...

    @abstractmethod
    def find_active(self) -> List[EvaluationCriteria]: ...


class IEvaluationPeriodRepository(ABC):
    @abstractmethod
    def save(self, period: EvaluationPeriod) -> EvaluationPeriod: ...

    @abstractmethod
    def get_by_id(self, period_id: UUID) -> Optional[EvaluationPeriod]: ...

    @abstractmethod
    def find(self, **criteria) -> List[EvaluationPeriod]: ...


class IVendorPriceListRepository(ABC):
    @abstractmethod
    def save(self, price_list: VendorPriceList) -> VendorPriceList: ...

    @abstractmethod
    def get_by_id(self, price_list_id: UUID) -> Optional[VendorPriceList]: ...

    @abstractmethod
    def find_by_vendor(self, vendor_id: UUID) -> List[VendorPriceList]: ...

    @abstractmethod
    def find(self, **criteria) -> List[VendorPriceList]: ...

    @abstractmethod
    def delete(self, price_list_id: UUID) -> bool: ...


class IPurchaseDiscountRepository(ABC):
    @abstractmethod
    def save(self, discount: PurchaseDiscount) -> PurchaseDiscount: ...

    @abstractmethod
    def get_by_id(self, discount_id: UUID) -> Optional[PurchaseDiscount]: ...

    @abstractmethod
    def find_for_vendor_item(
        self, vendor_id: UUID, item_id: UUID
    ) -> List[PurchaseDiscount]: ...

    @abstractmethod
    def find(self, **criteria) -> List[PurchaseDiscount]: ...

    @abstractmethod
    def delete(self, discount_id: UUID) -> bool: ...
