from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status, permissions
from drf_yasg import openapi
from django.db.models import Q
from django.utils.dateparse import parse_date
from django.shortcuts import get_object_or_404


from drf_yasg.utils import swagger_auto_schema
from user.models import Enquiry, UserBlock, UserFavourite, UserReport, UserTransaction, User
from user.serializers import EnquirySerializer, UserBlockSerializer, UserFavouriteSerializer, UserReportSerializer, UserEnquirySerializer, UserReportbySerializer, UserTransactionSerializer
from master.authentication import IsActiveAdmin


def apply_search(queryset, search_term, fields):
    q = Q()
    for field in fields:
        q |= Q(**{f"{field}__icontains": search_term})
    return queryset.filter(q)


class EnquiryListCreateView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    @swagger_auto_schema(
        operation_description="Retrieve all enquiries",
        responses={200: openapi.Response('List of enquiries', EnquirySerializer(many=True))}
    )
    def get(self, request):
        enquiries = Enquiry.objects.all()
        serializer = EnquirySerializer(enquiries, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    @swagger_auto_schema(
        request_body=UserEnquirySerializer,
        operation_description="Create a new enquiry",
        responses={201: openapi.Response('Enquiry created successfully', UserEnquirySerializer)}
    )
    def post(self, request):
        serializer = UserEnquirySerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class EnquiryByUserView(APIView):
    @swagger_auto_schema(
        operation_description="Retrieve enquiries by user ID",
        responses={200: openapi.Response('User-specific enquiries', EnquirySerializer(many=True))}
    )
    def get(self, request, user_id):
        enquiries = Enquiry.objects.filter(user_id=user_id)
        serializer = EnquirySerializer(enquiries, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


class EnquiryStatusUpdateView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    @swagger_auto_schema(
        operation_description="Bulk update the status and admin_description of multiple enquiries by their IDs.",
        request_body=openapi.Schema(
            type=openapi.TYPE_ARRAY,
            items=openapi.Items(
                type=openapi.TYPE_OBJECT,
                properties={
                    "id": openapi.Schema(type=openapi.TYPE_INTEGER, description="Enquiry ID"),
                    "status": openapi.Schema(
                        type=openapi.TYPE_INTEGER,
                        description="New status (1 for Open, 2 for Closed)",
                        enum=[1, 2]
                    ),
                    "admin_description": openapi.Schema(
                        type=openapi.TYPE_STRING,
                        description="Admin response or note for the enquiry"
                    )
                },
                required=["id", "status"]
            )
        ),
        responses={
            200: "Statuses and descriptions updated successfully.",
            400: "Invalid input data.",
        }
    )
    def post(self, request):
        updates = request.data

        if not isinstance(updates, list):
            return Response({"error": "Expected a list of updates."}, status=status.HTTP_400_BAD_REQUEST)

        success_updates = []
        failed_updates = []

        for item in updates:
            enquiry_id = item.get("id")
            status_value = item.get("status")
            admin_description = item.get("admin_description", "")

            if not enquiry_id or status_value not in [1, 2]:
                failed_updates.append({
                    "status": "error",
                    "id": enquiry_id,
                    "message": "Missing or invalid data."
                })
                continue

            try:
                enquiry = Enquiry.objects.get(pk=enquiry_id)
                enquiry.status = status_value
                enquiry.admin_description = admin_description
                enquiry.save()
                success_updates.append(enquiry_id)
            except Enquiry.DoesNotExist:
                failed_updates.append({
                    "status": "error",
                    "id": enquiry_id,
                    "message": "Enquiry not found."
                })

        return Response({
            "status": "success",
            "message": "Status and admin description update completed.",
            "success": success_updates,
            "failed": failed_updates
        }, status=status.HTTP_200_OK)

    
class EnquiryStatusoneView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    @swagger_auto_schema(
        operation_description="Retrieve all enquiries where status = 1",
        manual_parameters=[
            openapi.Parameter(
                'search',
                openapi.IN_QUERY,
                description="Search keyword",
                type=openapi.TYPE_STRING
            )
        ],
        responses={200: openapi.Response('Enquiries with status 1', EnquirySerializer(many=True))}
    )   
    def get(self, request):
        enquiries = Enquiry.objects.filter(status=1)
        search = request.query_params.get("search")
        if search:
            enquiries = apply_search(enquiries, search, ['subject'])
        serializer = EnquirySerializer(enquiries, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    
class EnquiryStatusTwoListView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    @swagger_auto_schema(
        operation_description="Retrieve all enquiries where status = 2",
        manual_parameters=[
            openapi.Parameter(
                'search',
                openapi.IN_QUERY,
                description="Search keyword",
                type=openapi.TYPE_STRING
            )
        ],
        responses={200: openapi.Response('Enquiries with status 2', EnquirySerializer(many=True))}
    )
    def get(self, request):
        enquiries = Enquiry.objects.filter(status=2)
        search = request.query_params.get("search")
        if search:
            enquiries = apply_search(enquiries, search, ['subject'])
        serializer = EnquirySerializer(enquiries, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    
class UserBlockByUserIdView(APIView):
    @swagger_auto_schema(
        manual_parameters=[
            openapi.Parameter(
                'user_id',
                openapi.IN_PATH,
                description="ID of the user to retrieve blocked users for",
                type=openapi.TYPE_INTEGER,
                required=True
            ),
            openapi.Parameter(
                'search',
                openapi.IN_QUERY,
                description="Search by blocked user's display_name, email, or mobile",
                type=openapi.TYPE_STRING
            ),
            openapi.Parameter(
                'start_date',
                openapi.IN_QUERY,
                description="Start date in YYYY-MM-DD format",
                type=openapi.TYPE_STRING
            ),
            openapi.Parameter(
                'end_date',
                openapi.IN_QUERY,
                description="End date in YYYY-MM-DD format",
                type=openapi.TYPE_STRING
            ),
        ],
        responses={200: UserBlockSerializer(many=True)}
    )
    def get(self, request, user_id):
        blocks = UserBlock.objects.filter(user_id=user_id)

        # Date filter
        start_date = parse_date(request.query_params.get("start_date", ""))
        end_date = parse_date(request.query_params.get("end_date", ""))
        if start_date:
            blocks = blocks.filter(created_at__date__gte=start_date)
        if end_date:
            blocks = blocks.filter(created_at__date__lte=end_date)

        # Search filter on related blocked_user
        search = request.query_params.get("search")
        if search:
            blocks = blocks.filter(
                Q(blocked_user__display_name__icontains=search) |
                Q(blocked_user__email__icontains=search) |
                Q(blocked_user__mobile__icontains=search)
            )

        serializer = UserBlockSerializer(blocks, many=True)
        return Response(serializer.data)


class UserBlockAddView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    @swagger_auto_schema(request_body=UserBlockSerializer)
    def post(self, request):
        serializer = UserBlockSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class UserBlockDeleteView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    @swagger_auto_schema(
        manual_parameters=[
            openapi.Parameter(
                'id',
                openapi.IN_PATH,
                description="ID of the block relationship to delete",
                type=openapi.TYPE_INTEGER,
                required=True
            )
        ],
        responses={
            200: openapi.Response("Deleted successfully", openapi.Schema(
                type=openapi.TYPE_OBJECT,
                properties={
                    "status": openapi.Schema(type=openapi.TYPE_STRING),
                    "message": openapi.Schema(type=openapi.TYPE_STRING),
                }
            )),
            404: openapi.Response("Not found")
        }
    )
    def delete(self, request, id):
        try:
            block = UserBlock.objects.get(pk=id)
            block.delete()
            return Response({
                "status": "success",
                "message": "user Unblocked successfully."
            }, status=status.HTTP_200_OK)
        except UserBlock.DoesNotExist:
            return Response({
                "status": "error",
                "message": "Blocked user not found."
            }, status=status.HTTP_404_NOT_FOUND)



class UserFavouriteByUserIdView(APIView):
    @swagger_auto_schema(
        manual_parameters=[
            openapi.Parameter(
                'user_id',
                openapi.IN_PATH,
                description="ID of the user to retrieve favourites for",
                type=openapi.TYPE_INTEGER,
                required=True
            )
        ],
        responses={200: UserFavouriteSerializer(many=True)}
    )
    def get(self, request, user_id):
        favs = UserFavourite.objects.filter(user_id=user_id)
        serializer = UserFavouriteSerializer(favs, many=True)
        return Response(serializer.data)


class UserFavouriteAddView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    @swagger_auto_schema(request_body=UserFavouriteSerializer)
    def post(self, request):
        serializer = UserFavouriteSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class UserFavouriteDeleteView(APIView):
    permission_classes = [permissions.IsAuthenticated]
    @swagger_auto_schema(
        manual_parameters=[
            openapi.Parameter(
                'id',
                openapi.IN_PATH,
                description="ID of the favourite relationship to delete",
                type=openapi.TYPE_INTEGER,
                required=True
            )
        ],
        responses={
            204: 'Deleted successfully',
            404: 'Not found'
        }
    )
    def delete(self, request, id):
        try:
            fav = UserFavourite.objects.get(pk=id)
            fav.delete()
            return Response({"message": "Favourite deleted successfully."}, status=status.HTTP_204_NO_CONTENT)
        except UserFavourite.DoesNotExist:
            return Response({"error": "Favourite not found."}, status=status.HTTP_404_NOT_FOUND)


class UserReportByUserIdView(APIView):
    @swagger_auto_schema(
        manual_parameters=[
            openapi.Parameter(
                'user_id',
                openapi.IN_PATH,
                description="ID of the user to retrieve reported users for",
                type=openapi.TYPE_INTEGER,
                required=True
            ),
            openapi.Parameter(
                'search',
                openapi.IN_QUERY,
                description="Search by reported user's display_name, email, or mobile",
                type=openapi.TYPE_STRING
            ),
            openapi.Parameter(
                'start_date',
                openapi.IN_QUERY,
                description="Start date in YYYY-MM-DD format",
                type=openapi.TYPE_STRING
            ),
            openapi.Parameter(
                'end_date',
                openapi.IN_QUERY,
                description="End date in YYYY-MM-DD format",
                type=openapi.TYPE_STRING
            ),
        ],
        responses={200: UserReportSerializer(many=True)}
    )
    def get(self, request, user_id):
        reports = UserReport.objects.filter(user_id=user_id)

        # Date filter
        start_date = parse_date(request.query_params.get("start_date", ""))
        end_date = parse_date(request.query_params.get("end_date", ""))
        if start_date:
            reports = reports.filter(created_at__date__gte=start_date)
        if end_date:
            reports = reports.filter(created_at__date__lte=end_date)

        # Search filter on reported_user fields
        search = request.query_params.get("search")
        if search:
            reports = reports.filter(
                Q(reported_user__display_name__icontains=search) |
                Q(reported_user__email__icontains=search) |
                Q(reported_user__mobile__icontains=search)
            )

        serializer = UserReportSerializer(reports, many=True)
        return Response(serializer.data)

class UserReportByReporterView(APIView):
    # permission_classes = [permissions.IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        manual_parameters=[
            openapi.Parameter(
                'reporter_id',
                openapi.IN_PATH,
                description="ID of the user who reported others",
                type=openapi.TYPE_INTEGER,
                required=True
            ),
            openapi.Parameter(
                'search',
                openapi.IN_QUERY,
                description="Search by reported user's display_name, email, or mobile",
                type=openapi.TYPE_STRING
            ),
            openapi.Parameter(
                'start_date',
                openapi.IN_QUERY,
                description="Start date in YYYY-MM-DD format",
                type=openapi.TYPE_STRING
            ),
            openapi.Parameter(
                'end_date',
                openapi.IN_QUERY,
                description="End date in YYYY-MM-DD format",
                type=openapi.TYPE_STRING
            ),
        ],
        responses={200: UserReportbySerializer(many=True)},
        operation_description="List of users reported *by* the given user."
    )
    def get(self, request, reporter_id):
        reports = UserReport.objects.filter(reported_user_id=reporter_id)

        # Date filters
        start_date = parse_date(request.query_params.get("start_date", ""))
        end_date = parse_date(request.query_params.get("end_date", ""))
        if start_date:
            reports = reports.filter(created_at__date__gte=start_date)
        if end_date:
            reports = reports.filter(created_at__date__lte=end_date)

        # Search on reported_user
        search = request.query_params.get("search")
        if search:
            reports = reports.filter(
                Q(reported_user__display_name__icontains=search) |
                Q(reported_user__email__icontains=search) |
                Q(reported_user__mobile__icontains=search)
            )

        serializer = UserReportbySerializer(reports, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


class UserReportAddView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    @swagger_auto_schema(request_body=UserReportSerializer)
    def post(self, request):
        serializer = UserReportSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class UserTransactionListAPIView(APIView):
    def get(self, request):
        user_id = request.query_params.get("user_id")
        status_filter = request.query_params.get("status")

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

        queryset = UserTransaction.objects.filter(user_id=user_id)

        if status_filter:
            queryset = queryset.filter(status=status_filter)

        serializer = UserTransactionSerializer(queryset, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)
    

class UserReferralView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    @swagger_auto_schema(
        manual_parameters=[
            openapi.Parameter('user_id', openapi.IN_QUERY, description="User ID to fetch referral info", type=openapi.TYPE_INTEGER, required=True),
            openapi.Parameter('search', openapi.IN_QUERY, description="Search by display_name", type=openapi.TYPE_STRING, required=False),
        ],
        operation_description="Get referrer and referred users based on user_id with optional search on referred list"
    )
    def get(self, request):
        user_id = request.query_params.get('user_id')
        search = request.query_params.get('search', '')

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

        user = get_object_or_404(User, pk=user_id)

        referrer_data = None
        if user.referer_id:
            referrer_data = {
                "id": user.referer_id.id,
                "display_name": user.referer_id.display_name,
                "referral_code": user.referer_id.referral_code,
                "display_image": user.referer_id.display_image
            }

        referred_users = User.objects.filter(referer_id=user)
        if search:
            referred_users = referred_users.filter(
                Q(display_name__icontains=search)
            )

        referred_list = [
            {
                "id": u.id,
                "display_name": u.display_name,
                "display_image": u.display_image,
                "referral_code": u.referral_code,
                "created_at": u.created_at
            }
            for u in referred_users
        ]

        return Response({
            "status": "success",
            "data": {
                "referrer": referrer_data,
                "referred_to": referred_list
            }
        }, status=200)