from archives.models import Archives
from archives.serializers import ObjectIdsSerializer
from django.db.models import UUIDField
from django.db.models.functions import Cast
import logging
from django_filters import rest_framework as filters

LOGGER = logging.getLogger(__name__)


class BaseFilterWithArchiveFilter(filters.FilterSet):
    is_archived = filters.BooleanFilter(
        method="filter_by_archive_status", label="Filter if archived or unarchived"
    )

    def filter_by_archive_status(self, queryset, name, value):
        model_name = queryset.model.__name__

        archived_objects = (
            Archives.objects.filter(model__iexact=model_name.title())
            .annotate(
                model_object_id_uuid=Cast(
                    "model_object_id", UUIDField()
                )  # Cast to UUID
            )
            .values_list("model_object_id_uuid", flat=True)
        )

        if value in [True, "true", "True"]:
            return queryset.filter(id__in=archived_objects)

        return queryset.exclude(id__in=archived_objects)


class ArchiveUtils:
    def __init__(self, model_object):
        if model_object is None:
            raise ValueError("A Model object is required.")

        self.model_object = model_object
        self.model = str(model_object._meta.model_name).title()
        self.model_object_id = self.model_object.id

    def is_archived(self, raise_exception=True):
        LOGGER.info("Checking if model is archived already.")
        is_archived = Archives.objects.filter(
            model=self.model, model_object_id=self.model_object_id
        ).exists()

        if is_archived:
            if raise_exception:
                raise ValueError(
                    f"Model ID {self.model_object_id} of {self.model} is already archived."
                )

            return True

        return False

    def is_unarchived(self, raise_exception=True):
        LOGGER.info("Checking if model is unarchived already.")

        archived_object = Archives.objects.filter(
            model=self.model, model_object_id=self.model_object_id
        )

        if not archived_object.exists():
            if raise_exception:
                raise ValueError(
                    f"Model ID {self.model_object_id} of {self.model} is already unarchived."
                )

            return True

        return False

    def archive_object(self, raise_exception=True):
        self.is_archived(raise_exception=raise_exception)

        LOGGER.info(f"Archiving model {self.model_object_id} of {self.model}")
        archived_object = Archives.objects.create(
            model=self.model, model_object_id=self.model_object_id
        )
        archived_object.save()
        LOGGER.info(
            f"Model {archived_object.model_object_id} of {archived_object.model} archived successfully."
        )

    def unarchive_object(self, raise_exception=True):
        self.is_unarchived(raise_exception=raise_exception)

        LOGGER.info(f"Unarchiving model {self.model_object_id} of {self.model}")

        try:
            archived_object = Archives.objects.get(
                model=self.model, model_object_id=self.model_object_id
            )
            archived_object.delete()

            LOGGER.info(
                f"Model {archived_object.model_object_id} of {archived_object.model} unarchived successfully."
            )
        except Archives.DoesNotExist:
            LOGGER.error(
                f"Model object id {self.model_object_id} of {self.model} not found in archives."
            )
            raise ModuleNotFoundError(
                f"Model object id {self.model_object_id} of {self.model} not found in archives."
            )
