from recipes.models import Information, Review, RawIngredient, Unit
from profiles.models import Pantry
from rest_framework import generics, status, permissions
from rest_framework.response import Response
from .serializers import (
    RecipeInformationSerializer,
    ReviewSerializer,
    RecipeDetailSerializer,
    RecipeIngredientsSerializer,
    RawIngredientSerializer,
    UnitSerializer
)
from .models import Ingredient
from django.http import JsonResponse


class IsAuthenticatedOrReadOnly(permissions.BasePermission):
    def has_permission(self, request, view):
        if request.method == 'GET' or request.user.is_authenticated:
            return True
        return False


class RecipeListView(generics.GenericAPIView):
    serializer_class = RecipeInformationSerializer

    def get(self, request):
        recipes = Information.objects.all()[:30]
        recipes_serializer = self.serializer_class(
            recipes, context={'request': request}, many=True)
        return Response(recipes_serializer.data)


class OwnedIngredientView(generics.GenericAPIView):
    serializer_class = RecipeIngredientsSerializer

    def get(self, request, recipe_id):
        user = request.user

        if not user.is_authenticated:
            return Response([])

        owned_raw_ingredient_ids = Pantry.objects.filter(
            user=user).values_list('raw_ingredient_id', flat=True)
        owned_ingredients = Ingredient.objects.filter(
            raw_ingredient__in=owned_raw_ingredient_ids, recipe_id=recipe_id).distinct()
        serializer = RecipeIngredientsSerializer(owned_ingredients, many=True)
        return Response(serializer.data)


class NotOwnedIngredientViews(generics.GenericAPIView):
    serializer_class = RecipeIngredientsSerializer

    def get(self, request, recipe_id):
        user = request.user

        if not user.is_authenticated:
            all_ingredients = Ingredient.objects.filter(recipe_id=recipe_id)
            serializer = RecipeIngredientsSerializer(
                all_ingredients, many=True)
            return Response(serializer.data)

        owned_raw_ingredient_ids = Pantry.objects.filter(
            user=user).values_list('raw_ingredient_id', flat=True)
        not_owned_ingredients = Ingredient.objects.filter(
            recipe_id=recipe_id).exclude(raw_ingredient__in=owned_raw_ingredient_ids)
        serializer = RecipeIngredientsSerializer(
            not_owned_ingredients, many=True)
        return Response(serializer.data)


class RecipeDetailView(generics.GenericAPIView):
    serializer_class = RecipeDetailSerializer
    permission_classes = [permissions.AllowAny]

    def get(self, request, recipe_id):
        recipes = Information.objects.get(pk=recipe_id)
        recipes_serializer = self.serializer_class(
            recipes, context={'request': request})
        return Response(recipes_serializer.data)


class SearchRecipeView(generics.GenericAPIView):
    def get(self, request):
        keyword = request.GET.get('keyword')

        if not keyword or not keyword.strip():
            return Response({'message': 'Kata kunci yang Anda masukkan tidak valid'}, status=status.HTTP_400_BAD_REQUEST)

        recipes = Information.objects.filter(title__icontains=keyword)

        if not recipes:
            return Response({'message': 'Resep tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)

        recipes_list = RecipeInformationSerializer(
            recipes, context={'request': request}, many=True).data
        sorted_recipes = sorted(
            recipes_list, key=lambda x: x['completeness_percentage'], reverse=True)
        return Response(sorted_recipes, status=status.HTTP_200_OK)


class ReviewView(generics.GenericAPIView):
    permission_classes = [IsAuthenticatedOrReadOnly]
    serializer_class = ReviewSerializer

    def get(self, request, recipe_id, review_id=None):
        if review_id is not None:
            try:
                review = Review.objects.get(
                    recipe_id=recipe_id, pk=review_id, user=request.user)
            except Review.DoesNotExist:
                return Response({"message": "Ulasan tidak ditemukan"}, status=status.HTTP_404_NOT_FOUND)

            review_serializer = self.serializer_class(review)
            return Response(review_serializer.data)
        else:
            reviews = Review.objects.filter(recipe_id=recipe_id)

            if not reviews:
                return Response({"message": "Tidak ada ulasan"}, status=status.HTTP_404_NOT_FOUND)

            review_serializer = self.serializer_class(reviews, many=True)
            return Response(review_serializer.data)

    def post(self, request, recipe_id):
        try:
            recipe = Information.objects.get(pk=recipe_id)
        except Information.DoesNotExist:
            return JsonResponse({'message': 'Resep tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)

        review_serializer = self.serializer_class(data=request.data)

        if Review.objects.filter(user=request.user, recipe=recipe).exists():
            return Response({'message': 'Anda sudah memberikan ulasan'}, status=status.HTTP_400_BAD_REQUEST)

        if review_serializer.is_valid():
            saved_review = review_serializer.save(
                user=request.user, recipe=recipe)
            return Response(self.serializer_class(saved_review).data, status=status.HTTP_201_CREATED)

        return Response(review_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def put(self, request, recipe_id, review_id):
        review = Review.objects.get(
            pk=review_id, user=request.user, recipe_id=recipe_id)

        if not review:
            return Response({"message": "Ulasan tidak ditemukan"}, status=status.HTTP_404_NOT_FOUND)

        review_serializer = self.serializer_class(
            instance=review, data=request.data)

        if review_serializer.is_valid():
            review_serializer.save()
            return Response(review_serializer.data)
        else:
            return Response(review_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, recipe_id, review_id):
        try:
            review = Review.objects.get(
                pk=review_id, user=request.user)
            review.delete()
            return Response({'message': 'Berhasil menghapus ulasan'}, status=status.HTTP_200_OK)
        except Review.DoesNotExist:
            return Response({'message': 'Ulasan tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)


class RawIngredientView(generics.GenericAPIView):
    serializer_class = RawIngredientSerializer

    def get(self, request):
        if request.GET.get('name'):
            raw_materials = RawIngredient.objects.filter(
                name__icontains=request.GET.get('name'))
        else:
            raw_materials = RawIngredient.objects.all()
        serializer = self.get_serializer(raw_materials, many=True)
        return Response(serializer.data)


class UnitView(generics.GenericAPIView):
    def get(self, request):
        raw_ingredient_id = request.GET.get('raw_ingredient_id')

        units = Unit.objects.filter(
            ingredient__raw_ingredient_id=raw_ingredient_id).distinct()

        units_list = UnitSerializer(units, many=True).data
        return Response(units_list, status=status.HTTP_200_OK)
