from django.core.exceptions import NON_FIELD_ERRORS
from django.db import models

from .manager import SoftDeleteManager
from .utils import related_objects


class SoftDeleteAbstract(models.Model):
    deleted = models.BooleanField(default=False, editable=False, db_index=True)

    class Meta:
        abstract = True

    objects = SoftDeleteManager()

    def delete(self, **kwargs):
        self.deleted = True
        for object in related_objects(self):
            object.delete()
        super(SoftDeleteAbstract, self).save(**kwargs)

    def _perform_unique_checks(self, unique_checks):
        errors = {}

        for model_class, unique_check in unique_checks:
            # Try to look up an existing object with the same values as this
            # object's values for all the unique field.

            lookup_kwargs = {}
            for field_name in unique_check:
                f = self._meta.get_field(field_name)
                lookup_value = getattr(self, f.attname)
                if lookup_value is None:
                    # no value, skip the lookup
                    continue
                if f.primary_key and not self._state.adding:
                    # no need to check for unique primary key when editing
                    continue
                lookup_kwargs[str(field_name)] = lookup_value

            # some fields were skipped, no reason to do the check
            if len(unique_check) != len(lookup_kwargs):
                continue

            """
            Addition:
            This is the only changed section from the original code
            and is to ensure that when unique checks are made we have all records including deleted
            as these do not appear in the default queryset
            """
            qs = model_class._default_manager.all_with_deleted().filter(**lookup_kwargs)
            # end change

            # Exclude the current object from the query if we are editing an
            # instance (as opposed to creating a new one)
            # Note that we need to use the pk as defined by model_class, not
            # self.pk. These can be different fields because model inheritance
            # allows single model to have effectively multiple primary keys.
            # Refs #17615.
            model_class_pk = self._get_pk_val(model_class._meta)
            if not self._state.adding and model_class_pk is not None:
                qs = qs.exclude(pk=model_class_pk)
            if qs.exists():
                if len(unique_check) == 1:
                    key = unique_check[0]
                else:
                    key = NON_FIELD_ERRORS
                errors.setdefault(key, []).append(self.unique_error_message(model_class, unique_check))

        return errors
