"""
SCM Repository Implementations — Django ORM.

پیاده‌سازی repositoryها با Django ORM.
"""
from typing import Optional, List
from uuid import UUID

from ...domain.entities.vendor import Vendor, VendorCategory
from ...domain.entities.purchase_requisition import PurchaseRequisition
from ...domain.entities.purchase_order import PurchaseOrder
from ...domain.entities.goods_receipt import GoodsReceipt
from ...domain.entities.purchase_return import PurchaseReturn
from ...domain.entities.vendor_evaluation import (
    VendorEvaluation, EvaluationCriteria, EvaluationPeriod,
)
from ...domain.entities.price_management import VendorPriceList, PurchaseDiscount
from ...domain.repositories.interfaces import (
    IVendorRepository,
    IVendorCategoryRepository,
    IPurchaseRequisitionRepository,
    IPurchaseOrderRepository,
    IGoodsReceiptRepository,
    IPurchaseReturnRepository,
    IVendorEvaluationRepository,
    IEvaluationCriteriaRepository,
    IEvaluationPeriodRepository,
    IVendorPriceListRepository,
    IPurchaseDiscountRepository,
)
from ..persistence.models import (
    VendorModel, VendorCategoryModel,
)
from ..persistence.models_extended import (
    PurchaseRequisitionModel, PurchaseRequisitionLineModel,
    PurchaseOrderModel, PurchaseOrderLineModel,
    GoodsReceiptModel, GoodsReceiptLineModel,
    PurchaseReturnModel, PurchaseReturnLineModel,
    VendorEvaluationModel, VendorEvaluationScoreModel,
    EvaluationCriteriaModel, EvaluationPeriodModel,
    VendorPriceListModel, VendorPriceListItemModel,
    PurchaseDiscountModel,
)
from .mappers import (
    VendorMapper, VendorCategoryMapper,
    PRMapper, PRLineMapper,
    POMapper, POLineMapper,
    GRMapper, GRLineMapper,
    ReturnMapper, ReturnLineMapper,
    EvaluationMapper, EvaluationScoreMapper,
    EvaluationCriteriaMapper, EvaluationPeriodMapper,
    PriceListMapper, PriceListItemMapper,
    DiscountMapper,
)


# ═══════════════════════════════════════════════════
# Vendor Repositories
# ═══════════════════════════════════════════════════

class DjangoVendorRepository(IVendorRepository):
    """پیاده‌سازی مخزن تأمین‌کننده با Django ORM."""

    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: Vendor) -> Vendor:
        try:
            model = VendorModel.objects.get(id=entity.id)
            model = VendorMapper.to_model(entity, model)
        except VendorModel.DoesNotExist:
            model = VendorMapper.to_model(entity)
        model.save()
        return VendorMapper.to_entity(model)

    def get_by_id(self, id: UUID) -> Optional[Vendor]:
        try:
            model = VendorModel.objects.get(id=id, tenant_id=self._tenant_id)
            return VendorMapper.to_entity(model)
        except VendorModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[Vendor]:
        qs = VendorModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [VendorMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = VendorModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0

    def find_by_code(self, code: str) -> Optional[Vendor]:
        try:
            model = VendorModel.objects.get(
                vendor_code=code, tenant_id=self._tenant_id
            )
            return VendorMapper.to_entity(model)
        except VendorModel.DoesNotExist:
            return None

    def find_active(self) -> List[Vendor]:
        qs = VendorModel.objects.filter(
            tenant_id=self._tenant_id, is_active=True, status="ACTIVE"
        )
        return [VendorMapper.to_entity(m) for m in qs]

    def find_by_category(self, category_id: UUID) -> List[Vendor]:
        qs = VendorModel.objects.filter(
            tenant_id=self._tenant_id, category_id=category_id
        )
        return [VendorMapper.to_entity(m) for m in qs]


class DjangoVendorCategoryRepository(IVendorCategoryRepository):
    """پیاده‌سازی مخزن دسته‌بندی تأمین‌کننده."""

    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: VendorCategory) -> VendorCategory:
        try:
            model = VendorCategoryModel.objects.get(id=entity.id)
            model = VendorCategoryMapper.to_model(entity, model)
        except VendorCategoryModel.DoesNotExist:
            model = VendorCategoryMapper.to_model(entity)
        model.save()
        return VendorCategoryMapper.to_entity(model)

    def get_by_id(self, id: UUID) -> Optional[VendorCategory]:
        try:
            model = VendorCategoryModel.objects.get(id=id, tenant_id=self._tenant_id)
            return VendorCategoryMapper.to_entity(model)
        except VendorCategoryModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[VendorCategory]:
        qs = VendorCategoryModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [VendorCategoryMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = VendorCategoryModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0

    def find_by_code(self, code: str) -> Optional[VendorCategory]:
        try:
            model = VendorCategoryModel.objects.get(
                category_code=code, tenant_id=self._tenant_id
            )
            return VendorCategoryMapper.to_entity(model)
        except VendorCategoryModel.DoesNotExist:
            return None

    def find_root_categories(self) -> List[VendorCategory]:
        qs = VendorCategoryModel.objects.filter(
            tenant_id=self._tenant_id, parent_category__isnull=True
        )
        return [VendorCategoryMapper.to_entity(m) for m in qs]


# ═══════════════════════════════════════════════════
# Aggregate Repositories (PR, PO, GR, Return)
# ═══════════════════════════════════════════════════

class DjangoPRRepository(IPurchaseRequisitionRepository):
    """پیاده‌سازی مخزن درخواست خرید."""

    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: PurchaseRequisition) -> PurchaseRequisition:
        try:
            model = PurchaseRequisitionModel.objects.get(id=entity.id)
            model = PRMapper.to_model(entity, model)
        except PurchaseRequisitionModel.DoesNotExist:
            model = PRMapper.to_model(entity)
        model.save()

        # Save lines
        existing_ids = set()
        for line in entity.lines:
            line.requisition_id = entity.id
            try:
                lm = PurchaseRequisitionLineModel.objects.get(id=line.id)
                lm = PRLineMapper.to_model(line, lm)
            except PurchaseRequisitionLineModel.DoesNotExist:
                lm = PRLineMapper.to_model(line)
            lm.save()
            existing_ids.add(line.id)

        # Delete removed lines
        PurchaseRequisitionLineModel.objects.filter(
            requisition_id=entity.id
        ).exclude(id__in=existing_ids).delete()

        return self.get_by_id(entity.id)

    def get_by_id(self, id: UUID) -> Optional[PurchaseRequisition]:
        try:
            model = PurchaseRequisitionModel.objects.get(id=id, tenant_id=self._tenant_id)
            line_models = PurchaseRequisitionLineModel.objects.filter(requisition_id=id).order_by("line_number")
            lines = [PRLineMapper.to_entity(lm) for lm in line_models]
            return PRMapper.to_entity(model, lines)
        except PurchaseRequisitionModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[PurchaseRequisition]:
        qs = PurchaseRequisitionModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [PRMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = PurchaseRequisitionModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0

    def find_by_number(self, number: str) -> Optional[PurchaseRequisition]:
        try:
            model = PurchaseRequisitionModel.objects.get(
                pr_number=number, tenant_id=self._tenant_id
            )
            return self.get_by_id(model.id)
        except PurchaseRequisitionModel.DoesNotExist:
            return None

    def find_by_status(self, status: str) -> List[PurchaseRequisition]:
        qs = PurchaseRequisitionModel.objects.filter(
            tenant_id=self._tenant_id, status=status
        )
        return [PRMapper.to_entity(m) for m in qs]

    def find_by_requester(self, requester_id: UUID) -> List[PurchaseRequisition]:
        qs = PurchaseRequisitionModel.objects.filter(
            tenant_id=self._tenant_id, requester_id=requester_id
        )
        return [PRMapper.to_entity(m) for m in qs]


class DjangoPORepository(IPurchaseOrderRepository):
    """پیاده‌سازی مخزن سفارش خرید."""

    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: PurchaseOrder) -> PurchaseOrder:
        try:
            model = PurchaseOrderModel.objects.get(id=entity.id)
            model = POMapper.to_model(entity, model)
        except PurchaseOrderModel.DoesNotExist:
            model = POMapper.to_model(entity)
        model.save()

        existing_ids = set()
        for line in entity.lines:
            line.order_id = entity.id
            try:
                lm = PurchaseOrderLineModel.objects.get(id=line.id)
                lm = POLineMapper.to_model(line, lm)
            except PurchaseOrderLineModel.DoesNotExist:
                lm = POLineMapper.to_model(line)
            lm.save()
            existing_ids.add(line.id)

        PurchaseOrderLineModel.objects.filter(
            order_id=entity.id
        ).exclude(id__in=existing_ids).delete()

        return self.get_by_id(entity.id)

    def get_by_id(self, id: UUID) -> Optional[PurchaseOrder]:
        try:
            model = PurchaseOrderModel.objects.get(id=id, tenant_id=self._tenant_id)
            line_models = PurchaseOrderLineModel.objects.filter(order_id=id).order_by("line_number")
            lines = [POLineMapper.to_entity(lm) for lm in line_models]
            return POMapper.to_entity(model, lines)
        except PurchaseOrderModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[PurchaseOrder]:
        qs = PurchaseOrderModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [POMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = PurchaseOrderModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0

    def find_by_number(self, number: str) -> Optional[PurchaseOrder]:
        try:
            model = PurchaseOrderModel.objects.get(
                po_number=number, tenant_id=self._tenant_id
            )
            return self.get_by_id(model.id)
        except PurchaseOrderModel.DoesNotExist:
            return None

    def find_by_vendor(self, vendor_id: UUID) -> List[PurchaseOrder]:
        qs = PurchaseOrderModel.objects.filter(
            tenant_id=self._tenant_id, vendor_id=vendor_id
        )
        return [POMapper.to_entity(m) for m in qs]

    def find_by_status(self, status: str) -> List[PurchaseOrder]:
        qs = PurchaseOrderModel.objects.filter(
            tenant_id=self._tenant_id, status=status
        )
        return [POMapper.to_entity(m) for m in qs]

    def find_open_by_vendor(self, vendor_id: UUID) -> List[PurchaseOrder]:
        qs = PurchaseOrderModel.objects.filter(
            tenant_id=self._tenant_id,
            vendor_id=vendor_id,
            status__in=["APPROVED", "SENT", "PARTIALLY_RECEIVED"],
        )
        return [POMapper.to_entity(m) for m in qs]


class DjangoGRRepository(IGoodsReceiptRepository):
    """پیاده‌سازی مخزن رسید کالا."""

    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: GoodsReceipt) -> GoodsReceipt:
        try:
            model = GoodsReceiptModel.objects.get(id=entity.id)
            model = GRMapper.to_model(entity, model)
        except GoodsReceiptModel.DoesNotExist:
            model = GRMapper.to_model(entity)
        model.save()

        existing_ids = set()
        for line in entity.lines:
            line.receipt_id = entity.id
            try:
                lm = GoodsReceiptLineModel.objects.get(id=line.id)
                lm = GRLineMapper.to_model(line, lm)
            except GoodsReceiptLineModel.DoesNotExist:
                lm = GRLineMapper.to_model(line)
            lm.save()
            existing_ids.add(line.id)

        GoodsReceiptLineModel.objects.filter(
            receipt_id=entity.id
        ).exclude(id__in=existing_ids).delete()

        return self.get_by_id(entity.id)

    def get_by_id(self, id: UUID) -> Optional[GoodsReceipt]:
        try:
            model = GoodsReceiptModel.objects.get(id=id, tenant_id=self._tenant_id)
            line_models = GoodsReceiptLineModel.objects.filter(receipt_id=id).order_by("line_number")
            lines = [GRLineMapper.to_entity(lm) for lm in line_models]
            return GRMapper.to_entity(model, lines)
        except GoodsReceiptModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[GoodsReceipt]:
        qs = GoodsReceiptModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [GRMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = GoodsReceiptModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0

    def find_by_number(self, number: str) -> Optional[GoodsReceipt]:
        try:
            model = GoodsReceiptModel.objects.get(
                gr_number=number, tenant_id=self._tenant_id
            )
            return self.get_by_id(model.id)
        except GoodsReceiptModel.DoesNotExist:
            return None

    def find_by_po(self, po_id: UUID) -> List[GoodsReceipt]:
        qs = GoodsReceiptModel.objects.filter(
            tenant_id=self._tenant_id, po_id=po_id
        )
        result = []
        for m in qs:
            lines = [GRLineMapper.to_entity(lm) for lm in
                     GoodsReceiptLineModel.objects.filter(receipt_id=m.id).order_by("line_number")]
            result.append(GRMapper.to_entity(m, lines))
        return result


class DjangoReturnRepository(IPurchaseReturnRepository):
    """پیاده‌سازی مخزن برگشت از خرید."""

    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: PurchaseReturn) -> PurchaseReturn:
        try:
            model = PurchaseReturnModel.objects.get(id=entity.id)
            model = ReturnMapper.to_model(entity, model)
        except PurchaseReturnModel.DoesNotExist:
            model = ReturnMapper.to_model(entity)
        model.save()

        existing_ids = set()
        for line in entity.lines:
            line.return_id = entity.id
            try:
                lm = PurchaseReturnLineModel.objects.get(id=line.id)
                lm = ReturnLineMapper.to_model(line, lm)
            except PurchaseReturnLineModel.DoesNotExist:
                lm = ReturnLineMapper.to_model(line)
            lm.save()
            existing_ids.add(line.id)

        PurchaseReturnLineModel.objects.filter(
            purchase_return_id=entity.id
        ).exclude(id__in=existing_ids).delete()

        return self.get_by_id(entity.id)

    def get_by_id(self, id: UUID) -> Optional[PurchaseReturn]:
        try:
            model = PurchaseReturnModel.objects.get(id=id, tenant_id=self._tenant_id)
            line_models = PurchaseReturnLineModel.objects.filter(purchase_return_id=id).order_by("line_number")
            lines = [ReturnLineMapper.to_entity(lm) for lm in line_models]
            return ReturnMapper.to_entity(model, lines)
        except PurchaseReturnModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[PurchaseReturn]:
        qs = PurchaseReturnModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [ReturnMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = PurchaseReturnModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0

    def find_by_number(self, number: str) -> Optional[PurchaseReturn]:
        try:
            model = PurchaseReturnModel.objects.get(
                return_number=number, tenant_id=self._tenant_id
            )
            return self.get_by_id(model.id)
        except PurchaseReturnModel.DoesNotExist:
            return None

    def find_by_vendor(self, vendor_id: UUID) -> List[PurchaseReturn]:
        qs = PurchaseReturnModel.objects.filter(
            tenant_id=self._tenant_id, vendor_id=vendor_id
        )
        return [ReturnMapper.to_entity(m) for m in qs]


# ═══════════════════════════════════════════════════
# Evaluation Repositories
# ═══════════════════════════════════════════════════

class DjangoEvaluationRepository(IVendorEvaluationRepository):
    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: VendorEvaluation) -> VendorEvaluation:
        try:
            model = VendorEvaluationModel.objects.get(id=entity.id)
            model = EvaluationMapper.to_model(entity, model)
        except VendorEvaluationModel.DoesNotExist:
            model = EvaluationMapper.to_model(entity)
        model.save()

        existing_ids = set()
        for score in entity.scores:
            score.evaluation_id = entity.id
            try:
                sm = VendorEvaluationScoreModel.objects.get(id=score.id)
                sm = EvaluationScoreMapper.to_model(score, sm)
            except VendorEvaluationScoreModel.DoesNotExist:
                sm = EvaluationScoreMapper.to_model(score)
            sm.save()
            existing_ids.add(score.id)

        VendorEvaluationScoreModel.objects.filter(
            evaluation_id=entity.id
        ).exclude(id__in=existing_ids).delete()

        return self.get_by_id(entity.id)

    def get_by_id(self, id: UUID) -> Optional[VendorEvaluation]:
        try:
            model = VendorEvaluationModel.objects.get(id=id, tenant_id=self._tenant_id)
            score_models = VendorEvaluationScoreModel.objects.filter(evaluation_id=id)
            scores = [EvaluationScoreMapper.to_entity(sm) for sm in score_models]
            return EvaluationMapper.to_entity(model, scores)
        except VendorEvaluationModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[VendorEvaluation]:
        qs = VendorEvaluationModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [EvaluationMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = VendorEvaluationModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0

    def find_by_vendor(self, vendor_id: UUID) -> List[VendorEvaluation]:
        qs = VendorEvaluationModel.objects.filter(
            tenant_id=self._tenant_id, vendor_id=vendor_id
        )
        return [EvaluationMapper.to_entity(m) for m in qs]


class DjangoEvaluationCriteriaRepository(IEvaluationCriteriaRepository):
    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: EvaluationCriteria) -> EvaluationCriteria:
        try:
            model = EvaluationCriteriaModel.objects.get(id=entity.id)
            model = EvaluationCriteriaMapper.to_model(entity, model)
        except EvaluationCriteriaModel.DoesNotExist:
            model = EvaluationCriteriaMapper.to_model(entity)
        model.save()
        return EvaluationCriteriaMapper.to_entity(model)

    def get_by_id(self, id: UUID) -> Optional[EvaluationCriteria]:
        try:
            model = EvaluationCriteriaModel.objects.get(id=id, tenant_id=self._tenant_id)
            return EvaluationCriteriaMapper.to_entity(model)
        except EvaluationCriteriaModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[EvaluationCriteria]:
        qs = EvaluationCriteriaModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [EvaluationCriteriaMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = EvaluationCriteriaModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0

    def find_active(self) -> List[EvaluationCriteria]:
        qs = EvaluationCriteriaModel.objects.filter(
            tenant_id=self._tenant_id, is_active=True
        )
        return [EvaluationCriteriaMapper.to_entity(m) for m in qs]


class DjangoEvaluationPeriodRepository(IEvaluationPeriodRepository):
    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: EvaluationPeriod) -> EvaluationPeriod:
        try:
            model = EvaluationPeriodModel.objects.get(id=entity.id)
            model = EvaluationPeriodMapper.to_model(entity, model)
        except EvaluationPeriodModel.DoesNotExist:
            model = EvaluationPeriodMapper.to_model(entity)
        model.save()
        return EvaluationPeriodMapper.to_entity(model)

    def get_by_id(self, id: UUID) -> Optional[EvaluationPeriod]:
        try:
            model = EvaluationPeriodModel.objects.get(id=id, tenant_id=self._tenant_id)
            return EvaluationPeriodMapper.to_entity(model)
        except EvaluationPeriodModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[EvaluationPeriod]:
        qs = EvaluationPeriodModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [EvaluationPeriodMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = EvaluationPeriodModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0


# ═══════════════════════════════════════════════════
# Price Management Repositories
# ═══════════════════════════════════════════════════

class DjangoPriceListRepository(IVendorPriceListRepository):
    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: VendorPriceList) -> VendorPriceList:
        try:
            model = VendorPriceListModel.objects.get(id=entity.id)
            model = PriceListMapper.to_model(entity, model)
        except VendorPriceListModel.DoesNotExist:
            model = PriceListMapper.to_model(entity)
        model.save()

        existing_ids = set()
        for item in entity.items:
            item.price_list_id = entity.id
            try:
                im = VendorPriceListItemModel.objects.get(id=item.id)
                im = PriceListItemMapper.to_model(item, im)
            except VendorPriceListItemModel.DoesNotExist:
                im = PriceListItemMapper.to_model(item)
            im.save()
            existing_ids.add(item.id)

        VendorPriceListItemModel.objects.filter(
            price_list_id=entity.id
        ).exclude(id__in=existing_ids).delete()

        return self.get_by_id(entity.id)

    def get_by_id(self, id: UUID) -> Optional[VendorPriceList]:
        try:
            model = VendorPriceListModel.objects.get(id=id, tenant_id=self._tenant_id)
            items = [PriceListItemMapper.to_entity(im) for im in
                     VendorPriceListItemModel.objects.filter(price_list_id=id)]
            return PriceListMapper.to_entity(model, items)
        except VendorPriceListModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[VendorPriceList]:
        qs = VendorPriceListModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [PriceListMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = VendorPriceListModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0

    def find_by_vendor(self, vendor_id: UUID) -> List[VendorPriceList]:
        qs = VendorPriceListModel.objects.filter(
            tenant_id=self._tenant_id, vendor_id=vendor_id
        )
        return [PriceListMapper.to_entity(m) for m in qs]


class DjangoDiscountRepository(IPurchaseDiscountRepository):
    def __init__(self, tenant_id: UUID):
        self._tenant_id = tenant_id

    def save(self, entity: PurchaseDiscount) -> PurchaseDiscount:
        try:
            model = PurchaseDiscountModel.objects.get(id=entity.id)
            model = DiscountMapper.to_model(entity, model)
        except PurchaseDiscountModel.DoesNotExist:
            model = DiscountMapper.to_model(entity)
        model.save()
        return DiscountMapper.to_entity(model)

    def get_by_id(self, id: UUID) -> Optional[PurchaseDiscount]:
        try:
            model = PurchaseDiscountModel.objects.get(id=id, tenant_id=self._tenant_id)
            return DiscountMapper.to_entity(model)
        except PurchaseDiscountModel.DoesNotExist:
            return None

    def find(self, **criteria) -> List[PurchaseDiscount]:
        qs = PurchaseDiscountModel.objects.filter(tenant_id=self._tenant_id, **criteria)
        return [DiscountMapper.to_entity(m) for m in qs]

    def delete(self, id: UUID) -> bool:
        deleted, _ = PurchaseDiscountModel.objects.filter(
            id=id, tenant_id=self._tenant_id
        ).delete()
        return deleted > 0

    def find_by_vendor(self, vendor_id: UUID) -> List[PurchaseDiscount]:
        qs = PurchaseDiscountModel.objects.filter(
            tenant_id=self._tenant_id, vendor_id=vendor_id
        )
        return [DiscountMapper.to_entity(m) for m in qs]
