from rest_framework.generics import ListAPIView, RetrieveAPIView
from django.core import serializers as core_serializer
from blog import serializers as blogSerializers
from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from . import filters as custom_filters
from django_filters.rest_framework import DjangoFilterBackend
from django.http import JsonResponse
from blog import models as blogModel
from . import models as coreModel
from django.db.models import Q, Case, When, Value, IntegerField
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from . import serializers
from rest_framework import filters
from django.shortcuts import get_object_or_404
from . import lookup  # don't remove


class BrandCars(APIView):
    swagger_schema = None
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        brand = request.data['brand']
        cars = {}
        if brand:
            cars = coreModel.Car.objects.filter(brand_id=brand).order_by('name')
        data = core_serializer.serialize('json', cars)
        return JsonResponse(data=data, safe=False)


class CarTypes(APIView):
    swagger_schema = None
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        car = request.data['car']
        types = {}
        if car:
            types = coreModel.Type.objects.filter(car_id=car).order_by('name')
        data = core_serializer.serialize('json', types)
        return JsonResponse(data=data, safe=False)


class SubcategoryProducts(APIView):
    swagger_schema = None
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        subcategory = request.data['subcategory']
        products = {}
        if subcategory:
            products = coreModel.Product.objects.filter(subcategory_id=subcategory).order_by('name')
        data = core_serializer.serialize('json', products)
        return JsonResponse(data=data, safe=False)


class BrandsList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.BrandsListSerializer

    def get_queryset(self):
        return coreModel.Brand.objects.filter(status='approved').order_by('admin_order')


class BrandDetail(RetrieveAPIView):
    permission_classes = [permissions.AllowAny]
    queryset = coreModel.Brand.objects.all()
    serializer_class = serializers.BrandDetailSerializer


class BrandDetailByName(RetrieveAPIView):
    permission_classes = [permissions.AllowAny]
    queryset = coreModel.Brand.objects.all()
    lookup_field = 'english_name'
    serializer_class = serializers.BrandDetailSerializer


class BrandOriginalityList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.BrandOriginalityListSerializer

    def get_queryset(self):
        return coreModel.BrandOriginality.objects.filter(brand_id=self.kwargs['brand'])


class BrandOriginalityListByName(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.BrandOriginalityListSerializer

    def get_queryset(self):
        return coreModel.BrandOriginality.objects.filter(brand__english_name=self.kwargs['english_name'])


class CarsCompleteList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['brand', 'brand__english_name']
    serializer_class = serializers.CarsListSerializer

    @swagger_auto_schema(manual_parameters=[
        openapi.Parameter(
            'search',
            openapi.IN_QUERY,
            description="Optional search term",
            type=openapi.TYPE_STRING,
            required=False
        ),
    ])
    def get(self, request, *args, **kwargs):
        return super().get(request, *args, **kwargs)

    def get_queryset(self):
        query = normalize_text(self.request.query_params.get('search', None))
        qs = coreModel.Car.objects.all()

        if query:
            qs = qs.filter(
                Q(name__icontains=query) |
                Q(car_synonyms__name__icontains=query)
            ).annotate(
                match_priority=Case(
                    When(name__icontains=query, then=Value(1)),
                    When(car_synonyms__name__icontains=query, then=Value(2)),
                    default=Value(3),
                    output_field=IntegerField(),
                )
            ).order_by("match_priority")

        return qs.distinct()


class CarsList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarsListSerializer

    def get_queryset(self):
        return coreModel.Car.objects.filter(brand_id=self.kwargs['brand'], status='approved').order_by('admin_order')


class CarsListByName(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarsListSerializer

    def get_queryset(self):
        return coreModel.Car.objects.filter(brand__english_name=self.kwargs['english_name'],
                                            status='approved').order_by('admin_order')


class CarDetail(RetrieveAPIView):
    permission_classes = [permissions.AllowAny]
    queryset = coreModel.Car.objects.all()
    serializer_class = serializers.CarDetailSerializer


class CarDetailByName(RetrieveAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarDetailSerializer
    lookup_field = 'english_name'

    def get_queryset(self):
        return coreModel.Car.objects.filter(brand__english_name=self.kwargs.get('brand_english_name'))


class CarGalleryList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarGalleryListSerializer

    def get_queryset(self):
        return coreModel.CarGallery.objects.filter(car_id=self.kwargs['car'])


class CarGalleryListByName(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarGalleryListSerializer

    def get_queryset(self):
        return coreModel.CarGallery.objects.filter(car__english_name=self.kwargs.get('english_name'),
                                                   car__brand__english_name=self.kwargs.get('brand_english_name'))


class TypesList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.TypesListSerializer

    def get_queryset(self):
        return coreModel.Type.objects.filter(car_id=self.kwargs['car'])


class TypesListByName(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.TypesListSerializer

    def get_queryset(self):
        return coreModel.Type.objects.filter(car__english_name=self.kwargs.get('english_name'),
                                             car__brand__english_name=self.kwargs.get('brand_english_name'))


class CarProductionYears(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request, car):
        years = coreModel.Type.objects.filter(car_id=car).values('start_year', 'end_year')
        res = []
        for year in years:
            start = year['start_year']
            end = year['end_year']
            if start and end:
                for i in range(start, end + 1):
                    if i not in res:
                        res.append(i)
        return Response(res)


class CarProductionYearsByName(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request, english_name, brand_english_name):
        years = coreModel.Type.objects.filter(car__english_name=english_name,
                                              car__brand__english_name=brand_english_name).values('start_year',
                                                                                                  'end_year')
        res = []
        for year in years:
            start = year['start_year']
            end = year['end_year']
            if start and end:
                for i in range(start, end + 1):
                    if i not in res:
                        res.append(i)
        return Response(res)


class CarEngineVolumes(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request, car):
        volumes = coreModel.Type.objects.filter(car_id=car).values('volume')
        res = []
        for obj in volumes:
            if obj['volume'] not in res:
                res.append(obj['volume'])
        return Response(res)


class CarEngineVolumesByName(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request, english_name, brand_english_name):
        volumes = coreModel.Type.objects.filter(car__english_name=english_name,
                                                car__brand__english_name=brand_english_name).values('volume')
        res = []
        for obj in volumes:
            if obj['volume'] not in res:
                res.append(obj['volume'])
        return Response(res)


class CategoriesList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    queryset = coreModel.Category.objects.all()
    serializer_class = serializers.CategoriesListSerializer


class GeneralSubcategoriesList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.SubcategoriesListSerializer

    def get_queryset(self):
        return coreModel.Subcategory.objects.filter(
            category_id=self.kwargs['category'],
            parent_id=None,
            status='approved'
        ).order_by('admin_order')


class SubcategoriesList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarSubcategoriesListSerializer

    def get_queryset(self):
        return coreModel.CarSubcategory.objects.filter(
            car_id=self.kwargs['car'],
            subcategory__category_id=self.kwargs['category'],
            subcategory__parent_id=None,
            subcategory__status='approved'
        ).order_by('subcategory__admin_order')


class SubcategoriesListByName(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarSubcategoriesListSerializer

    def get_queryset(self):
        return coreModel.CarSubcategory.objects.filter(
            car__english_name=self.kwargs['english_name'],
            car__brand__english_name=self.kwargs['brand_english_name'],
            subcategory__category_id=self.kwargs['category'],
            subcategory__parent_id=None,
            subcategory__status='approved'
        ).order_by('subcategory__admin_order')


class SubcategoryDetail(RetrieveAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarSubcategoryDetailSerializer
    queryset = coreModel.CarSubcategory.objects.all()

    def get_object(self):
        return self.queryset.get(car_id=self.kwargs['car'], subcategory_id=self.kwargs['subcategory'],
                                 subcategory__status='approved')


class SubcategoryDetailByName(RetrieveAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarSubcategoryDetailSerializer
    queryset = coreModel.CarSubcategory.objects.all()

    def get_object(self):
        return self.queryset.get(car__english_name=self.kwargs['english_name'],
                                 car__brand__english_name=self.kwargs['brand_english_name'],
                                 subcategory_id=self.kwargs['subcategory'], subcategory__status='approved')


class ProductsList(ListAPIView):
    permission_classes = [permissions.AllowAny]
    queryset = coreModel.Product.objects.all()
    serializer_class = serializers.ProductsListSerializer


class GeneralProductsListByCategory(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.ProductsListSerializer

    def get_queryset(self):
        return coreModel.Product.objects.filter(
            subcategory_id=self.kwargs['subcategory'],
            subcategory__status='approved',
            status='approved'
        )


class ProductsListByCategory(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarProductsListSerializer

    def get_queryset(self):
        return coreModel.CarProduct.objects.filter(
            car_id=self.kwargs['car'],
            product__subcategory_id=self.kwargs['subcategory'],
            product__subcategory__status='approved',
            product__status='approved'
        )


class ProductsListByCategoryByName(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarProductsListSerializer

    def get_queryset(self):
        return coreModel.CarProduct.objects.filter(
            car__english_name=self.kwargs['english_name'],
            car__brand__english_name=self.kwargs['brand_english_name'],
            product__subcategory_id=self.kwargs['subcategory'],
            product__subcategory__status='approved',
            product__status='approved'
        )


class ProductsListByCar(ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class = serializers.CarProductsListSerializer
    filter_backends = (custom_filters.SimpleFilterBackend,)

    @swagger_auto_schema(manual_parameters=[
        openapi.Parameter(
            'query',
            openapi.IN_QUERY,
            description="Optional search term",
            type=openapi.TYPE_STRING,
            required=False
        ),
    ])
    def get(self, request, *args, **kwargs):
        return super().get(request, *args, **kwargs)

    def get_queryset(self):
        query = self.request.query_params.get('query', None)
        filters = Q(
            car_id=self.kwargs['car'],
            product__subcategory__status='approved',
            product__status='approved'
        )
        qs = coreModel.CarProduct.objects.filter(filters)
        if query:
            qs = qs.filter(
                Q(product__name__icontains=query) |
                Q(product__product_synonyms__name__icontains=query)
            ).annotate(
                match_priority=Case(
                    When(product__name__icontains=query, then=Value(1)),
                    When(product__product_synonyms__name__icontains=query, then=Value(2)),
                    default=Value(3),
                    output_field=IntegerField(),
                )
            ).order_by("match_priority")

        return qs.distinct()


class GlobalSearchList(ListAPIView):
    filter_backends = (custom_filters.SimpleFilterBackend,)
    permission_classes = [permissions.AllowAny]

    def get(self, request, *args, **kwargs):
        query = self.request.query_params.get('query', None)
        stopwords = ['جلو', 'عقب', 'بالا', 'پایین', 'چپ', 'راست']
        filtered_query = [word for word in query.split() if word not in stopwords]
        query = ' '.join(filtered_query)
        subcategories = coreModel.Subcategory.objects.filter(
            Q(name__search=query) | Q(category__name__search=query), status='approved')
        products = coreModel.Product.objects.filter(
            Q(name__search=query) | Q(subcategory__name__search=query), status='approved')
        cars = coreModel.Car.objects.filter(
            Q(name__search=query) | Q(brand__name__search=query), status='approved')
        product_articles = blogModel.ProductArticle.objects.filter(
            Q(abstract__search=query) | Q(title__search=query))
        car_articles = blogModel.CarArticle.objects.filter(
            Q(abstract__search=query) | Q(title__search=query))
        other_articles = blogModel.Other.objects.filter(
            Q(abstract__search=query) | Q(title__search=query))
        news = blogModel.News.objects.filter(
            Q(abstract__search=query) | Q(title__search=query))

        guid = {}
        cars_products = []
        if cars and (subcategories or products):
            for car in cars:
                subcategories_products = []
                if subcategories:
                    subcategories_products = self._subcategory_loop(products, subcategories, subcategories_products)
                else:
                    subcategories = [product.subcategory for product in products if
                                     product.subcategory not in subcategories]
                    subcategories_products = self._subcategory_loop(products, subcategories, subcategories_products)
                cars_products.append({
                    'car': serializers.CarSearchSerializer(car).data,
                    'subcategories': subcategories_products
                })
        elif not cars:
            guid = {'error': 'car'}
        else:
            guid = {'error': 'product'}

        return JsonResponse(
            {
                'articles': {
                    'cars': blogSerializers.CarArticlesListSerializer(car_articles, many=True).data,
                    'products': blogSerializers.ProductArticlesListSerializer(product_articles, many=True).data,
                    'other': blogSerializers.OtherArticlesListSerializer(other_articles, many=True).data,
                },
                'news': blogSerializers.NewsListSerializer(news, many=True).data,
                'results': cars_products,
                'guid': guid,
            }
        )

    @staticmethod
    def _subcategory_loop(products, subcategories, subcategories_products):
        for subcategory in subcategories:
            subcategory_products = [serializers.ProductSearchSerializer(product).data for product in
                                    products if product.subcategory.id == subcategory.id]
            subcategories_products.append({
                'subcategory': serializers.SubcategorySearchSerializer(subcategory).data,
                'products': subcategory_products
            })
        return subcategories_products


def normalize_text(text):
    if not text:
        return ""
    text = text.replace("‌", " ")  # تبدیل نیم فاصله به فاصله
    text = text.replace("ي", "ی")  # ی فارسی → ی عربی
    text = text.replace("ك", "ک")  # ک فارسی → ک عربی
    translation_table = str.maketrans("۰۱۲۳۴۵۶۷۸۹", "0123456789")
    text = text.translate(translation_table)
    return text
