from django.apps import apps
from django.core.exceptions import ValidationError
from rest_framework import status

from apps.product.exceptions import DistributionException, QuotaException


def get_model(app_label, model_name):
    return apps.get_model(app_label, model_name)


class QuotaStatsValidator:
    """
    Validator static methods for distribution/sale/quota edits.
    """

    @staticmethod
    def _get_stat(quota, organization):
        organization_quota_stats = get_model("product", "OrganizationQuotaStats")
        return organization_quota_stats.objects.filter(quota=quota, organization=organization).first()  # noqa

    @staticmethod
    def validate_quota_weight_update(remaining_amount):
        if remaining_amount < 0:
            raise QuotaException(
                "وزن سهمیه نباید از مقدار توزیع شده کمتر باشد",  # noqa
                status.HTTP_403_FORBIDDEN
            )

    @staticmethod
    def validate_assigner_has_enough(assigner_org, quota, amount, allow_zero=False, update_operation=None):
        """
        if organization has enough remaining weight
        """
        if assigner_org.type.key == "ADM":
            assigner_org = quota.registerer_organization

        stat = QuotaStatsValidator._get_stat(quota, assigner_org)
        if not stat:
            raise DistributionException(
                f"سازمان {assigner_org.name} هیچ مدل میانی برای این سهمیه {quota} ندارد .",  # noqa
                status.HTTP_403_FORBIDDEN)

        remaining = getattr(stat, "remaining_amount", None)
        if remaining is None:
            # fallback to quota.remaining_weight subtraction from totals
            raise DistributionException(
                "فیلد باقی مانده در مدل میانی وجود ندارد",  # noqa
                status.HTTP_403_FORBIDDEN
            )

        if amount < 0:
            raise DistributionException("مقدار وزن نباید منفی باشد", status.HTTP_403_FORBIDDEN)  # noqa

        if remaining + amount < amount and not allow_zero:
            if update_operation:
                raise DistributionException(
                    "مقدار وزن ویرایش شده از وزن باقیمانده بیشتر است",  # noqa
                    status.HTTP_403_FORBIDDEN
                )
            raise DistributionException(
                f"تخصیص مقدار {amount} بیشتر از مقدار باقیمانده {remaining + amount} برای سازمان {assigner_org.name} میباشد.",
                # noqa
                status.HTTP_403_FORBIDDEN
            )

    @staticmethod
    def validate_distribution_create(assigner_org, assigned_org, quota, amount, parent_distribution=None):
        # rule: assigner must have enough remaining weight
        QuotaStatsValidator.validate_assigner_has_enough(assigner_org, quota, amount)

    @staticmethod
    def validate_distribution_update(assigner_org, assigned_org, quota, old_amount, new_amount,
                                     parent_distribution=None):
        # if diff is positive we must check
        diff = new_amount - (old_amount or 0)
        if diff > 0:
            QuotaStatsValidator.validate_assigner_has_enough(assigner_org, quota, diff)

    @staticmethod
    def validate_distribution_delete(distribution):
        been_sold = getattr(distribution, "been_sold", None)
        if been_sold and been_sold > 0:
            raise ValidationError("Cannot delete distribution: it has sold items.")
