from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from django.shortcuts import get_object_or_404
from rest_framework.permissions import IsAuthenticated
from django.contrib.auth.models import User as DjangoUser
from rest_framework.authtoken.models import Token


from rest_framework.parsers import MultiPartParser
import boto3
import mimetypes
import uuid
from io import BytesIO
from urllib.parse import urlparse

from user.models import User, UserLanguage, UserImage, UserInterest, UserBlock, UserTransaction
from user.serializers import ( 
    UserInterestSerializer, UserLanguageSerializer, UserImageSerializer, UserSerializer, EditUserSerializer,UserStatusUpdateSerializer,
    UsergetInterestSerializer, UsergetLanguageSerializer, UsertypeUpdateSerializer, UserImageUpdateSerializer, ProfileupdateSerializer,
    FemaleVerifySerializer, UpdateLanguageSerializer, UserDisplayImageUpdateSerializer
    )

class UserInterestView(APIView):
    @swagger_auto_schema(
        operation_description="Replace all user interests with the provided list. Removes any not in the request.",
        request_body=openapi.Schema(
            type=openapi.TYPE_ARRAY,
            items=openapi.Items(type=openapi.TYPE_OBJECT, properties={
                'user': openapi.Schema(type=openapi.TYPE_INTEGER),
                'interest': openapi.Schema(type=openapi.TYPE_INTEGER),
            }),
            description="List of interest objects to set for a user"
        ),
        responses={201: openapi.Response('Interests replaced successfully')}
    )
    def post(self, request):
        if not isinstance(request.data, list):
            return Response({
                "status": "error",
                "message": "Expected a list of interest objects."
            }, status=status.HTTP_400_BAD_REQUEST)

        if not request.data:
            return Response({
                "status": "error",
                "message": "Empty list provided."
            }, status=status.HTTP_400_BAD_REQUEST)

        user_id = request.data[0].get('user')
        if not user_id:
            return Response({
                "status": "error",
                "message": "User ID is required in each entry."
            }, status=status.HTTP_400_BAD_REQUEST)

        UserInterest.objects.filter(user=user_id).delete()

        created = []
        errors = []

        for entry in request.data:
            user = entry.get('user')
            interest = entry.get('interest')

            if not user or not interest:
                errors.append({"entry": entry, "error": "User and interest are required."})
                continue

            serializer = UserInterestSerializer(data=entry)
            if serializer.is_valid():
                serializer.save()
                created.append(serializer.data)
            else:
                errors.append({"entry": entry, "error": serializer.errors})

        return Response({
            "status": "success",
            "created": created,
            "errors": errors
        }, status=status.HTTP_201_CREATED)


class UserLanguageView(APIView):
    @swagger_auto_schema(
        operation_description="Replace all user languages with the provided list. Removes any not in the request.",
        request_body=openapi.Schema(
            type=openapi.TYPE_ARRAY,
            items=openapi.Items(type=openapi.TYPE_OBJECT, properties={
                'user': openapi.Schema(type=openapi.TYPE_INTEGER),
                'language': openapi.Schema(type=openapi.TYPE_INTEGER),
            }),
            description="List of language objects to set for a user"
        ),
        responses={201: "Languages replaced successfully."}
    )
    def post(self, request):
        if not isinstance(request.data, list):
            return Response({
                "status": "error",
                "message": "Expected a list of language objects."
            }, status=status.HTTP_400_BAD_REQUEST)

        if not request.data:
            return Response({
                "status": "error",
                "message": "Empty list provided."
            }, status=status.HTTP_400_BAD_REQUEST)

        user_id = request.data[0].get('user')
        if not user_id:
            return Response({
                "status": "error",
                "message": "User ID is required in each entry."
            }, status=status.HTTP_400_BAD_REQUEST)

        UserLanguage.objects.filter(user=user_id).delete()

        created = []
        errors = []

        for entry in request.data:
            user = entry.get('user')
            language = entry.get('language')

            if not user or not language:
                errors.append({"entry": entry, "error": "User and language are required."})
                continue

            serializer = UserLanguageSerializer(data=entry)
            if serializer.is_valid():
                serializer.save()
                created.append(serializer.data)
            else:
                errors.append({"entry": entry, "error": serializer.errors})

        return Response({
            "status": "success",
            "created": created,
            "errors": errors
        }, status=status.HTTP_201_CREATED)



class UserImageView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser]

    def post(self, request):
        image_files = request.FILES.getlist('images')
        user_id = request.data.get('user')

        if not image_files:
            return Response({"error": "At least one image file is required."}, status=400)

        if not user_id:
            return Response({"error": "User ID is required."}, status=400)

        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            return Response({"error": "User not found."}, status=404)

        s3 = boto3.client(
            's3',
            region_name='sgp1',
            endpoint_url='https://sgp1.digitaloceanspaces.com',
            aws_access_key_id='NMQAUQUGQAQ4ZE4QNKFN',
            aws_secret_access_key='IbTaeOcuA8Xb9WFclN1vow53a3D6yjyxbwn1Yzvw5nc'
        )

        results = []

        for image_file in image_files:
            try:
                image_copy = BytesIO(image_file.read())
                image_copy.seek(0)

                content_type, _ = mimetypes.guess_type(image_file.name)
                content_type = content_type or 'application/octet-stream'

                ext = image_file.name.split('.')[-1].lower()
                filename = f"chatapp/user_images/{uuid.uuid4()}.{ext}"

                s3.upload_fileobj(
                    image_copy,
                    'foodieninos',
                    filename,
                    ExtraArgs={'ACL': 'public-read', 'ContentType': content_type}
                )

                image_url = f"https://foodieninos.sgp1.cdn.digitaloceanspaces.com/{filename}"

                image_data = {
                    "user": user.id,
                    "image": image_url
                }

                serializer = UserImageSerializer(data=image_data)
                if serializer.is_valid():
                    serializer.save()
                    results.append({
                        "status": "success",
                        "image_url": image_url,
                        "data": serializer.data
                    })
                else:
                    results.append({
                        "status": "error",
                        "image_name": image_file.name,
                        "errors": serializer.errors
                    })

            except Exception as e:
                results.append({
                    "status": "error",
                    "image_name": image_file.name,
                    "error": str(e)
                })

        return Response(results, status=status.HTTP_207_MULTI_STATUS)
    
    def delete(self, request, pk):
        """
        Delete a user image by its primary key.
        """
        try:
            image_obj = get_object_or_404(UserImage, pk=pk)

            parsed_url = urlparse(image_obj.image)
            image_key = parsed_url.path.lstrip('/')

            s3 = boto3.client(
                's3',
                region_name='sgp1',
                endpoint_url='https://sgp1.digitaloceanspaces.com',
                aws_access_key_id='NMQAUQUGQAQ4ZE4QNKFN',
                aws_secret_access_key='IbTaeOcuA8Xb9WFclN1vow53a3D6yjyxbwn1Yzvw5nc'
            )

            s3.delete_object(Bucket='foodieninos', Key=image_key)

            image_obj.delete()

            return Response({
                "status": "success",
                "message": "Image deleted successfully"
            }, status=status.HTTP_200_OK)

        except Exception as e:
            return Response({
                "status": "error",
                "message": f"Failed to delete image: {str(e)}"
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



class UserDetailView(APIView):
    permission_classes = [IsAuthenticated]

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

        try:
            user = User.objects.get(display_name=logged_in_user)
        except User.DoesNotExist:
            return Response({"error": "Logged-in user not found."}, status=status.HTTP_404_NOT_FOUND)

        blocked_ids = UserBlock.objects.filter(user=user).values_list('blocked_user_id', flat=True)
        blocked_by_others_ids = UserBlock.objects.filter(blocked_user=user).values_list('user_id', flat=True)
        exclude_ids = list(blocked_ids) + list(blocked_by_others_ids)

        users = User.objects.filter(status=1).exclude(id__in=exclude_ids)

        if user.gender == 1:
            users = users.filter(gender=2)
        elif user.gender == 2:
            users = users.filter(gender=1)

        language_ids = request.query_params.get('language_id')
        if language_ids:
            try:
                language_id_list = [int(l.strip()) for l in language_ids.split(',') if l.strip().isdigit()]
                users = users.filter(language_id__in=language_id_list)
            except ValueError:
                return Response({"error": "Invalid language ID format."}, status=status.HTTP_400_BAD_REQUEST)

        interest_ids = request.query_params.get('interests')
        if interest_ids:
            try:
                interest_id_list = [int(i.strip()) for i in interest_ids.split(',') if i.strip().isdigit()]
                users = users.filter(interests__interest__id__in=interest_id_list)
            except ValueError:
                return Response({"error": "Invalid interest ID format."}, status=status.HTTP_400_BAD_REQUEST)


        min_age = request.query_params.get('min_age')
        max_age = request.query_params.get('max_age')
        if min_age:
            users = users.filter(age__gte=int(min_age))
        if max_age:
            users = users.filter(age__lte=int(max_age))

        users = users.distinct()

        result = []
        for user in users:
            user_data = UserSerializer(user).data
            interest_data = UserInterestSerializer(UserInterest.objects.filter(user=user), many=True).data
            language_data = UserLanguageSerializer(UserLanguage.objects.filter(user=user), many=True).data
            image_data = UserImageSerializer(UserImage.objects.filter(user=user), many=True).data

            result.append({
                "user": user_data,
                "interests": interest_data,
                "languages": language_data,
                "images": image_data
            })

        return Response(result, status=status.HTTP_200_OK)


class UpdateUserLanguageView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        user_id = request.data.get('user_id')
        if not user_id:
            return Response({"status": "error", "message": "user_id is required."},
                            status=status.HTTP_400_BAD_REQUEST)
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            return Response({"status": "error", "message": "User not found."},
                            status=status.HTTP_404_NOT_FOUND)

        serializer = UpdateLanguageSerializer(user, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "Language updated successfully.",
                "data": serializer.data
            }, status=status.HTTP_200_OK)
        return Response({
            "status": "error",
            "message": "Invalid data.",
            "errors": serializer.errors
        }, status=status.HTTP_400_BAD_REQUEST)

class UserDetailByPKView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, pk):
        """
        Retrieve full user details by ID, including interests, languages, and images
        (nested inside the user object).
        """
        try:
            user = User.objects.get(pk=pk)
        except User.DoesNotExist:
            return Response(
                {"message": "User not found"},
                status=status.HTTP_404_NOT_FOUND
            )

        user_data = UserSerializer(user).data

        # Add nested data
        interests = UserInterest.objects.filter(user=user)
        languages = UserLanguage.objects.filter(user=user)
        images = UserImage.objects.filter(user=user)

        user_data["interests"] = UsergetInterestSerializer(interests, many=True).data
        user_data["languages"] = UsergetLanguageSerializer(languages, many=True).data
        user_data["images"] = UserImageSerializer(images, many=True).data

        return Response({
            "status": "success",
            "data": user_data
        }, status=status.HTTP_200_OK)

        
class UserEditView(APIView):
    permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        request_body=EditUserSerializer,
        responses={
            200: "User details updated successfully",
            400: "Invalid data provided",
            404: "User not found"
        },
        operation_description="Edit user details by user ID."
    )
    def post(self, request, pk):
        """
        Edit the details of a specific user by ID (POST method).
        """
        user = get_object_or_404(User, pk=pk)
        serializer = EditUserSerializer(user, data=request.data)

        if serializer.is_valid():
            serializer.save()
            return Response(
                {"message": "User details updated successfully"},
                status=status.HTTP_200_OK
            )
        return Response(
            {"message": "Invalid data provided", "errors": serializer.errors},
            status=status.HTTP_400_BAD_REQUEST
        )

class ProfileEditView(APIView):
    permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        request_body=ProfileupdateSerializer,
        responses={
            200: "User details updated successfully",
            400: "Invalid data provided",
            404: "User not found"
        },
        operation_description="Edit user details by user ID."
    )
    def post(self, request, pk):

        custom_user = get_object_or_404(User, pk=pk)
        old_display_name = custom_user.display_name
        old_gender = custom_user.gender

        serializer = ProfileupdateSerializer(custom_user, data=request.data, partial=True)

        if serializer.is_valid():
            new_gender = serializer.validated_data.get('gender', old_gender)

            if old_gender != new_gender:
                if old_gender == 1 and new_gender == 2:
                    if UserTransaction.objects.filter(user=custom_user).exists():
                        return Response(
                            {"errors": "error", "message": "Gender change from male to female is not allowed after any transaction."},
                            status=status.HTTP_400_BAD_REQUEST
                        )

                elif old_gender == 2 and new_gender == 1:
                    return Response(
                        {"errors": "error", "message": "Gender change from female to male is not allowed."},
                        status=status.HTTP_400_BAD_REQUEST
                    )

                serializer.validated_data['status'] = 3
                serializer.validated_data['admin_status'] = 0

            updated_user = serializer.save()

            try:
                auth_user = DjangoUser.objects.get(username=old_display_name)
                new_display_name = request.data.get('display_name')
                if new_display_name and new_display_name != old_display_name:
                    auth_user.username = new_display_name
                    auth_user.save()
                    token, created = Token.objects.get_or_create(user=auth_user)
            except DjangoUser.DoesNotExist:
                token = None

            return Response(
                {
                    "message": "User details updated successfully",
                    "token": token.key if 'token' in locals() else None
                },
                status=status.HTTP_200_OK
            )

        return Response(
            {"message": "Invalid data provided", "errors": serializer.errors},
            status=status.HTTP_400_BAD_REQUEST
        )
        

class UserStatusUpdateAPIView(APIView):
    permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        request_body=UserStatusUpdateSerializer,
        responses={
            200: "User status and admin status updated successfully",
            400: "Invalid data",
            404: "User not found"
        },
        operation_description="Update the status and admin status of a user by ID."
    )
    def post(self, request, pk):
        user = get_object_or_404(User, pk=pk)
        serializer = UserStatusUpdateSerializer(user, data=request.data, partial=True)

        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "User status/admin_status updated successfully",
                "data": serializer.data
            }, status=status.HTTP_200_OK)

        return Response({
            "status": "error",
            "message": "Invalid status or admin_status provided",
            "errors": serializer.errors
        }, status=status.HTTP_400_BAD_REQUEST)
    
class FemaleVerifyAPIView(APIView):
    # permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        request_body=FemaleVerifySerializer(many=True),
        responses={
            200: "Users verified successfully",
            400: "Invalid data",
        },
        operation_description="Bulk update admin_status for multiple users."
    )
    def post(self, request):
        serializer = FemaleVerifySerializer(data=request.data, many=True)
        if serializer.is_valid():
            for item in serializer.validated_data:
                user_id = item['id']
                admin_status = item['admin_status']
                try:
                    user = User.objects.get(id=user_id)
                    user.admin_status = admin_status
                    user.save()
                except User.DoesNotExist:
                    continue

            return Response({
                "status": "success",
                "message": "Users verified successfully"
            }, status=status.HTTP_200_OK)

        return Response({
            "status": "error",
            "message": "Invalid input",
            "errors": serializer.errors
        }, status=status.HTTP_400_BAD_REQUEST)

class UserTypeUpdateAPIView(APIView):
    permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        request_body=UsertypeUpdateSerializer,
        responses={
            200: "User type updated successfully",
            400: "Invalid data",
            404: "User not found"
        },
        operation_description="Update the type of a user by ID."
    )
    def post(self, request, pk):
        user = get_object_or_404(User, pk=pk)
        serializer = UsertypeUpdateSerializer(user, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "User type updated successfully",
                "data": serializer.data
            }, status=status.HTTP_200_OK)

        return Response({
            "status": "error",
            "message": "Invalid type provided",
            "errors": serializer.errors
        }, status=status.HTTP_400_BAD_REQUEST)
    

class UserImageUpdateView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser]

    def post(self, request):
        user_id = request.data.get('user')

        if not user_id:
            return Response({"error": "User ID is required."}, status=status.HTTP_400_BAD_REQUEST)

        try:
            user = User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return Response({"error": "User not found."}, status=status.HTTP_404_NOT_FOUND)

        default_image_file = request.FILES.get('default_image')
        profile_image_file = request.FILES.get('profile_image')


        if not default_image_file and not profile_image_file:
            return Response({"error": "At least one image (default_image or profile_image) is required."}, status=400)

        # S3 client setup
        s3 = boto3.client(
            's3',
            region_name='sgp1',
            endpoint_url='https://sgp1.digitaloceanspaces.com',
            aws_access_key_id='NMQAUQUGQAQ4ZE4QNKFN',
            aws_secret_access_key='IbTaeOcuA8Xb9WFclN1vow53a3D6yjyxbwn1Yzvw5nc'
        )

        update_data = {}

        try:
            default_url = None
            profile_url = None

            if default_image_file:
                default_filename = f"chatapp/user_default_images/{uuid.uuid4()}.{default_image_file.name.split('.')[-1]}"
                s3.upload_fileobj(default_image_file, 'foodieninos', default_filename, ExtraArgs={'ACL': 'public-read'})
                default_url = f"https://foodieninos.sgp1.cdn.digitaloceanspaces.com/{default_filename}"
                update_data["default_image"] = default_url

            if profile_image_file:
                profile_filename = f"chatapp/user_profile_images/{uuid.uuid4()}.{profile_image_file.name.split('.')[-1]}"
                s3.upload_fileobj(profile_image_file, 'foodieninos', profile_filename, ExtraArgs={'ACL': 'public-read'})
                profile_url = f"https://foodieninos.sgp1.cdn.digitaloceanspaces.com/{profile_filename}"
                update_data["profile_image"] = profile_url

            if profile_url:
                update_data["display_image"] = profile_url
            elif default_url:
                update_data["display_image"] = default_url

        except Exception as e:
            return Response({"error": f"Image upload failed: {str(e)}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        serializer = UserImageUpdateSerializer(user, data=update_data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "User image(s) updated successfully.",
                "data": serializer.data
            }, status=status.HTTP_200_OK)

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

class UpdateDisplayImageView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        user_id = request.data.get('user_id')
        image_url = request.data.get('display_image')
        

        if not user_id:
            return Response({"error": "User ID is required."}, status=status.HTTP_400_BAD_REQUEST)

        if not image_url:
            return Response({"error": "Display image URL is required."}, status=status.HTTP_400_BAD_REQUEST)

        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            return Response({"error": "User not found."}, status=status.HTTP_404_NOT_FOUND)

        serializer = UserDisplayImageUpdateSerializer(user, data={'display_image': image_url}, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "Display image updated successfully.",
                "data": serializer.data
            }, status=status.HTTP_200_OK)

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