from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Blogs, BlogsDynamicPagination
from products.models import Products
from products.serializers import ProductsCustomSerializer
from .serializers import BlogsSerializer, BlogsCustomSerializer
from rest_framework.permissions import IsAdminUser
from products.permissions import (
    IsCopywriter,
)
from rest_framework.parsers import MultiPartParser, FormParser
from utils.r2.client import R2
import json
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter
from .filters import BlogsFilter
from utils.mixins.archive_mixins import ArchiveViewSetMixin
from activity_logs.models import ActivityLogs


# Create your views here.
class BlogsViewset(viewsets.ModelViewSet, ArchiveViewSetMixin):
    queryset = Blogs.objects.order_by("-date_created")
    filter_backends = [DjangoFilterBackend, SearchFilter]
    filterset_class = BlogsFilter
    permission_classes = [IsCopywriter]
    parser_classes = [MultiPartParser, FormParser]
    pagination_class = BlogsDynamicPagination

    def get_serializer_class(self):
        method = self.request.method

        if method in ["POST", "PUT", "PATCH"]:
            return BlogsCustomSerializer

        return BlogsSerializer

    def get_paginated_response(self, data):
        return Response(
            {
                "count": self.paginator.page.paginator.count,
                "page_size": len(data),
                "next": self.paginator.get_next_link(),
                "previous": self.paginator.get_previous_link(),
                "results": data,
            }
        )

    def create_or_update(self, data, featured_products_ids, instance=None):
        if instance:
            serializer = self.get_serializer(data=data, instance=instance)
        else:
            serializer = self.get_serializer(data=data)

        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data

        title = validated_data.get("title")
        body = validated_data.get("body")
        date_created = validated_data.get("date_created")
        image_banner = validated_data.get("image_banner", None)
        r2_path = None

        if image_banner:
            r2 = R2(file=image_banner, main_folder_name="blogs")
            r2_path = r2.upload_fileobj(
                sub_folder_path=f"blogs_banners/{title}/",
            )  # always end it with /

        modified_content = json.dumps({"delta": "", "html": body})
        products = Products.objects.filter(id__in=featured_products_ids)

        if instance:
            blog: Blogs = instance

            # Add condition to check if a new image banner is uploaded during UPDATE
            if r2_path:
                blog.image_banner = r2_path

            blog.body = modified_content
            blog.date_created = date_created
            blog.title = title
        else:
            # For CREATE, r2_path is automatically included as it is required if creating a new blog
            blog = Blogs(
                title=title,
                body=modified_content,
                date_created=date_created,
                image_banner=r2_path,
            )

        blog._featured_products = products
        blog.save()

        read_serializer_data = BlogsSerializer(blog, many=False).data
        read_serializer_data["featured_products"] = ProductsCustomSerializer(
            products, many=True
        ).data

        return read_serializer_data

    def create(self, request, *args, **kwargs):
        data = request.data
        image_banner = data.get("image_banner", None)
        date_created = data.get("date_created", None)

        if image_banner is None:
            return Response(
                {"message": "Image banner is required in creating a blog."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        if date_created is None:
            return Response(
                {"message": "Date created is required in creating a blog."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        featured_products_ids = data.getlist("featured_products[]", [])
        init_blog_title = data["title"]

        existing_blog_title = Blogs.objects.filter(title__iexact=init_blog_title)

        if existing_blog_title.exists():
            return Response(
                {"message": f"Blog with title '{init_blog_title}' already exists."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        serialized_created_data = self.create_or_update(
            data=data, featured_products_ids=featured_products_ids
        )
        ActivityLogs.record_activity(
            user=request.user,
            action=f"Created the blog '{serialized_created_data['title']}'",
        )
        return Response(serialized_created_data, status=status.HTTP_201_CREATED)

    def update(self, request, *args, **kwargs):
        """
        If image banner is not a new file upload, no need to be included in the payload.
        """
        data = request.data
        instance: Blogs = self.get_object()
        featured_products_ids = data.getlist("featured_products[]", [])
        init_blog_title = data["title"]

        existing_blog_title = Blogs.objects.filter(
            title__iexact=init_blog_title
        ).exclude(id=instance.id)

        if existing_blog_title.exists():
            return Response(
                {"message": f"Blog with title '{init_blog_title}' already exists."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        serialized_updated_data = self.create_or_update(
            data=data, featured_products_ids=featured_products_ids, instance=instance
        )

        ActivityLogs.record_activity(
            user=request.user,
            action=f"Modified the blog '{serialized_updated_data['title']}'",
        )
        return Response(serialized_updated_data, status=status.HTTP_200_OK)
