from .models import Information
from django.contrib.auth.models import User
from rest_framework import generics, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from django.db.models import Count, Max

from .models import Account, Pantry, History, Favorite
from .serializers import (
    AccountSerializer, FavoriteSerializer, HistorySerializer, PantrySerializer, ProfilePictureSerializer
)
from recipes.models import Information, RawIngredient
from recipes.serializers import RecipeInformationSerializer, RawIngredientSerializer

from .utils import calculate_top_recipes_by_ingredients, get_hybrid_recommendation, get_recommendations_for_user


class AccountView(generics.GenericAPIView):
    permission_classes = [IsAuthenticated]

    serializer_class = AccountSerializer

    def get(self, request):
        account = Account.objects.get(user_id=request.user.id)
        serializer = self.get_serializer(account)
        return Response(serializer.data)

    def post(self, request):
        account = User.objects.get(id=request.user.id)
        account_serializer = self.get_serializer(
            instance=account, data=request.data)
        profile_picture_serializer = ProfilePictureSerializer(
            instance=account.account, data=request.data)

        if profile_picture_serializer.is_valid(raise_exception=True):
            profile_picture_serializer.save()

        if account_serializer.is_valid(raise_exception=True):
            account_serializer.save()

        return Response(account_serializer.data)


class FavoriteView(generics.GenericAPIView):
    permission_classes = [IsAuthenticated]

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

        recipes = Information.objects.filter(
            favorite__user=user).order_by("-favorite__created_at")

        recipes_serializer = RecipeInformationSerializer(
            recipes, context={'request': request}, many=True)
        return Response(recipes_serializer.data)

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

        try:
            recipe = Information.objects.get(id=recipe_id)
        except Information.DoesNotExist:
            return Response({'message': 'Resep tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)

        source = request.data.get('source', '')

        favorite, created = Favorite.objects.get_or_create(
            user=user, recipe=recipe, source=source)

        if created:
            favorite_serializer = FavoriteSerializer(
                favorite, context={'request': request})
            return Response(favorite_serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response({'message': 'Anda sudah menambahkan resep ini ke favorit'}, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, recipe_id):
        favorite = Favorite.objects.filter(
            recipe_id=recipe_id, user=request.user).first()

        if favorite:
            favorite.delete()
            return Response({'message': 'Berhasil menghapus resep dari daftar favorit'}, status=status.HTTP_200_OK)
        else:
            return Response({'message': 'Data tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)


class HistoryView(generics.GenericAPIView):

    def get(self, request):
        user = request.user
        recipes = Information.objects.filter(history__user=user).annotate(
            newest_created_at=Max('history__created_at')).order_by('-newest_created_at')
        recipes_serializer = RecipeInformationSerializer(
            recipes, context={'request': request}, many=True)
        return Response(recipes_serializer.data)

    def post(self, request, recipe_id):
        if request.user.is_authenticated:
            user = request.user
        else:
            user = User.objects.get(id=4)

        try:
            recipe = Information.objects.get(id=recipe_id)
        except Information.DoesNotExist:
            return Response({'message': 'Resep tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)

        source = request.data.get('source', '')

        history = History(
            user=user, recipe=recipe, source=source)
        history.save()

        history_serializer = HistorySerializer(history)
        return Response(history_serializer.data, status=status.HTTP_201_CREATED)

    def delete(self, request, recipe_id):
        history = History.objects.filter(
            recipe_id=recipe_id, user=request.user).first()

        if history:
            history.delete()
            return Response({'message': 'History berhasil dihapus'}, status=status.HTTP_200_OK)
        else:
            return Response({'message': 'History tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)


class PantryView(generics.GenericAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = PantrySerializer

    def get(self, request):
        pantry = Pantry.objects.filter(user=request.user)
        if pantry.exists():
            serializer = PantrySerializer(pantry, many=True)
            return Response(serializer.data, status=status.HTTP_200_OK)
        else:
            return Response({"message": "Penyimpanan kosong."}, status=status.HTTP_204_NO_CONTENT)

    def post(self, request):
        user = request.user

        raw_ingredient_id = request.data.get('id')
        amount = request.data.get('amount')
        unit_id = request.data.get('unit_id')
        raw_ingredient_ids = request.data.get('raw_ingredient_id', [])

        if (len(raw_ingredient_ids) != 0):
            Pantry.objects.filter(user=user).delete()
            raw_ingredients = RawIngredient.objects.filter(
                pk__in=raw_ingredient_ids)
            for raw_ingredient in raw_ingredients:
                pantry = Pantry(user=user, raw_ingredient=raw_ingredient)
                pantry.save()  

            user = request.user

            top_recipes = calculate_top_recipes_by_ingredients(user)[:12]
            top_recipe_ids = [recipe['recipe_id'] for recipe in top_recipes]
            recipes = Information.objects.filter(id__in=top_recipe_ids).annotate()
            recipes_list = RecipeInformationSerializer(
                recipes, context={'request': request, 'top_recipes': top_recipes}, many=True).data
            sorted_recipes = sorted(
                recipes_list,
                key=lambda x: (0.8 * next(
                    (item['similarity'] for item in top_recipes if item['recipe_id'] == x['id']), 0)) +
                (0.2 * x['completeness_percentage']),
                reverse=True
            )

            return Response(sorted_recipes, status=status.HTTP_200_OK)              
        else:
            try:
                pantry = Pantry.objects.get(
                    user=user, raw_ingredient_id=raw_ingredient_id)
                pantry.amount = amount                 
                pantry.unit_id = unit_id
                pantry.save()
                pantry_serializer = PantrySerializer(pantry).data
                return Response(pantry_serializer, status=status.HTTP_200_OK)
            except Pantry.DoesNotExist:                              
                pantry = Pantry.objects.create(
                    user=user, raw_ingredient_id=raw_ingredient_id, amount=amount, unit_id=unit_id)
                pantry_serializer = PantrySerializer(pantry).data
                return Response(pantry_serializer, status=status.HTTP_200_OK)

    def delete(self, request, pantry_id):
        pantry = Pantry.objects.filter(
            user=request.user, id=pantry_id)
        pantry.delete()
        return Response('Berhasil menghapus data', status=status.HTTP_204_NO_CONTENT)


class UpdatePasswordView(generics.GenericAPIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        user = request.user
        current_password = request.data.get('current_password')
        new_password = request.data.get('new_password')
        if user.check_password(current_password):
            user.set_password(new_password)
            user.save()
            return Response("Password berhasil diperbarui", status=status.HTTP_200_OK)
        else:
            return Response("Password saat ini salah", status=status.HTTP_400_BAD_REQUEST)


class PantryRecommendationView(generics.GenericAPIView):
    permission_classes = [IsAuthenticated]

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

        top_recipes = calculate_top_recipes_by_ingredients(user)[:20]
        top_recipe_ids = [recipe['recipe_id'] for recipe in top_recipes]
        recipes = Information.objects.filter(id__in=top_recipe_ids).annotate()
        recipes_list = RecipeInformationSerializer(
            recipes, context={'request': request, 'top_recipes': top_recipes}, many=True).data

        filtered_recipes = [
            recipe for recipe in recipes_list if recipe['completeness_percentage'] > 0]

        sorted_recipes = sorted(
            filtered_recipes,
            key=lambda x: (0.8 * next(
                (item['similarity'] for item in top_recipes if item['recipe_id'] == x['id']), 0)) +
            (0.2 * x['completeness_percentage']),
            reverse=True
        )

        sorted_recipes = sorted_recipes[:12]        
        return Response(sorted_recipes, status=status.HTTP_200_OK)


class CFRecommendationView(generics.GenericAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = RecipeInformationSerializer

    def get(self, request):
        user_id = self.request.user.id
        top_recipes = get_recommendations_for_user(user_id)[:20]
        top_recipes_ids = [recipe['recipe_id']
                           for recipe in top_recipes]

        recipes = Information.objects.filter(
            id__in=top_recipes_ids)
        recipes_list = RecipeInformationSerializer(
            recipes, context={'request': request, 'top_recipes': top_recipes}, many=True).data        
        sorted_recipes = sorted(
            recipes_list, key=lambda x: x['similarity'], reverse=True)
        return Response(sorted_recipes, status=status.HTTP_200_OK)


class MostViewedRecommendationView(generics.GenericAPIView):

    def get(self, request):
        recipe_counts = History.objects.values('recipe_id').annotate(
            count=Count('recipe_id')).order_by('-count')[:9]

        recipe_ids = [count['recipe_id'] for count in recipe_counts]

        recipes = Information.objects.filter(
            id__in=recipe_ids).annotate(history_count=Count('history')).order_by('-history_count')
        recipes_list = RecipeInformationSerializer(
            recipes, context={'request': request}, many=True).data
        return Response(recipes_list, status=status.HTTP_200_OK)


class FavoriteRecommendationView(generics.GenericAPIView):

    def get(self, request):
        recipe_counts = Favorite.objects.values('recipe_id').annotate(
            count=Count('recipe_id')).order_by('-count')[:9]

        recipe_ids = [count['recipe_id'] for count in recipe_counts]

        recipes = Information.objects.filter(
            id__in=recipe_ids).annotate(favorite_count=Count('favorite')).order_by('-favorite_count')
        recipes_list = RecipeInformationSerializer(
            recipes, context={'request': request}, many=True).data
        return Response(recipes_list, status=status.HTTP_200_OK)


# Unused
class HybridRecommendationView(generics.GenericAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = RecipeInformationSerializer

    def get(self, request):
        user_id = self.request.user.id
        recommended_recipe_ids = get_hybrid_recommendation(user_id)[:9]

        recipes = Information.objects.filter(id__in=recommended_recipe_ids)
        recipes_list = RecipeInformationSerializer(
            recipes, context={'request': request}, many=True).data
        sorted_recipes = sorted(
            recipes_list, key=lambda x: x['completeness_percentage'], reverse=True)[:9]

        return Response(sorted_recipes, status=status.HTTP_200_OK)
