from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404
from django.utils.dateparse import parse_date


from master.models import Gift, AppSetting, FemaleReward
from user.models import Plan
from master.serializers import GiftSerializer, AppSettingSerializer, FemaleRewardSerializer, FemaleRewardInputSerializer, FemaleRewardCustomSerializer
from user.serializers import PlanSerializer
from master.authentication import IsActiveAdmin

import boto3, uuid, mimetypes, io
from io import BytesIO
from django.conf import settings
from rest_framework.parsers import MultiPartParser, FormParser
from uuid import uuid4

from rest_framework.permissions import IsAuthenticated
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from django.db.models import Q


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 GiftView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]
    parser_classes = [MultiPartParser]

    @swagger_auto_schema(
        operation_description="Get all gifts with optional search by name",
        manual_parameters=[
            openapi.Parameter(
                'search',
                openapi.IN_QUERY,
                description="Search gifts by name",
                type=openapi.TYPE_STRING
            )
        ],
        responses={200: GiftSerializer(many=True)}
    )
    def get(self, request):
        gifts = Gift.objects.all().order_by('-created_at')

        search = request.query_params.get("search")
        if search:
            gifts = apply_search(gifts, search, ['name'])

        serializer = GiftSerializer(gifts, many=True)
        return Response({
            "status": "success",
            "data": serializer.data
        }, status=status.HTTP_200_OK)

    @swagger_auto_schema(
        operation_description="Add a new gift with icon upload",
        responses={201: GiftSerializer()}
    )
    def post(self, request):
        icon_file = request.FILES.get('icon')

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

        try:
            icon_copy = io.BytesIO(icon_file.read())
            icon_copy.seek(0)

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

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

            filename = f"chatapp/gifts/{uuid.uuid4()}.{icon_file.name.split('.')[-1]}"
            s3.upload_fileobj(
                icon_copy,
                'foodieninos',
                filename,
                ExtraArgs={'ACL': 'public-read', 'ContentType': content_type}
            )

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

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

        data = request.data.copy()
        data['icon'] = icon_url

        serializer = GiftSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "Gift uploaded successfully",
                "data": serializer.data
            }, status=status.HTTP_201_CREATED)

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


class GiftEditView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]
    parser_classes = [MultiPartParser]

    @swagger_auto_schema(
        operation_description="Edit a gift by ID",
        manual_parameters=[
            openapi.Parameter('id', openapi.IN_PATH, description="Gift ID", type=openapi.TYPE_INTEGER)
        ],
        responses={200: GiftSerializer()}
    )
    def post(self, request, pk):
        try:
            gift = Gift.objects.get(pk=pk)
        except Gift.DoesNotExist:
            return Response({"status": "error", "message": "Gift not found."}, status=status.HTTP_404_NOT_FOUND)

        icon_file = request.FILES.get('icon')
        update_data = request.data.copy()

        if icon_file:
            try:
                icon_copy = io.BytesIO(icon_file.read())
                icon_copy.seek(0)

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

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

                filename = f"chatapp/gifts/{uuid.uuid4()}.{icon_file.name.split('.')[-1]}"
                s3.upload_fileobj(
                    icon_copy,
                    'foodieninos',
                    filename,
                    ExtraArgs={'ACL': 'public-read', 'ContentType': content_type}
                )

                icon_url = f"https://foodieninos.sgp1.cdn.digitaloceanspaces.com/{filename}"
                update_data['icon'] = icon_url

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

        serializer = GiftSerializer(gift, data=update_data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "Gift 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 GiftDeleteView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        operation_description="Delete a gift by ID (using POST)",
        manual_parameters=[
            openapi.Parameter('pk', openapi.IN_PATH, description="Gift ID", type=openapi.TYPE_INTEGER)
        ],
        responses={
            200: openapi.Response(description="Gift deleted successfully"),
            404: openapi.Response(description="Gift not found")
        }
    )
    def post(self, request, pk):
        try:
            gift = Gift.objects.get(pk=pk)
            gift.delete()
            return Response({
                "status": "success",
                "message": f"Gift deleted successfully."
            }, status=status.HTTP_200_OK)
        except Gift.DoesNotExist:
            return Response({
                "status": "error",
                "message": f"Gift with ID {pk} not found."
            }, status=status.HTTP_404_NOT_FOUND)


class GiftActiveUserListView(APIView):
    permission_classes = [IsAuthenticated]
    
    @swagger_auto_schema(
        operation_description="Get all active gifts (status=True)",
        responses={200: GiftSerializer(many=True)}
    )
    def get(self, request):
        active_gifts = Gift.objects.filter(status=True).order_by('-created_at')
        serializer = GiftSerializer(active_gifts, many=True)
        return Response({
            "status": "success",
            "data": serializer.data
        }, status=status.HTTP_200_OK)


class GiftStatusUpdateView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        operation_description="Update the status of a gift (active/inactive)",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=["status"],
            properties={
                "status": openapi.Schema(type=openapi.TYPE_BOOLEAN, description="New status (true or false)")
            }
        ),
        responses={200: openapi.Response("Status updated successfully")}
    )
    def post(self, request, pk):
        try:
            gift = Gift.objects.get(pk=pk)
        except Gift.DoesNotExist:
            return Response({"status": "error", "message": "Gift not found."}, status=status.HTTP_404_NOT_FOUND)

        new_status = request.data.get("status")
        if new_status is None:
            return Response({"status": "error", "message": "'status' field is required."}, status=status.HTTP_400_BAD_REQUEST)

        gift.status = new_status
        gift.save()

        return Response({
            "status": "success",
            "message": "Gift status updated successfully.",
            "data": GiftSerializer(gift).data
        }, status=status.HTTP_200_OK)

# Minumum amount wuthdraw


class UserAppSettingView(APIView):
    permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        operation_description="Get all app settings or filter by code or search",
        manual_parameters=[
            openapi.Parameter(
                'code', openapi.IN_QUERY, description="Filter by exact code", type=openapi.TYPE_STRING
            ),
            openapi.Parameter(
                'search', openapi.IN_QUERY, description="Search in name or code", type=openapi.TYPE_STRING
            ),
        ],
        responses={200: AppSettingSerializer(many=True)}
    )
    def get(self, request):
        code = request.query_params.get("code")
        search = request.query_params.get("search")

        queryset = AppSetting.objects.all().order_by('-created_at')

        if code:
            queryset = queryset.filter(code=code)

        if search:
            queryset = apply_search(queryset, search, ['name'])

        serializer = AppSettingSerializer(queryset, many=True)
        return Response({
            "status": "success",
            "data": serializer.data
        }, status=status.HTTP_200_OK)


class AppSettingView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        operation_description="Get all app settings or filter by code or search",
        manual_parameters=[
            openapi.Parameter(
                'code', openapi.IN_QUERY, description="Filter by exact code", type=openapi.TYPE_STRING
            ),
            openapi.Parameter(
                'search', openapi.IN_QUERY, description="Search in name or code", type=openapi.TYPE_STRING
            ),
        ],
        responses={200: AppSettingSerializer(many=True)}
    )
    def get(self, request):
        code = request.query_params.get("code")
        search = request.query_params.get("search")

        queryset = AppSetting.objects.all().order_by('-created_at')

        if code:
            queryset = queryset.filter(code=code)

        if search:
            queryset = apply_search(queryset, search, ['name'])

        serializer = AppSettingSerializer(queryset, many=True)
        return Response({
            "status": "success",
            "data": serializer.data
        }, status=status.HTTP_200_OK)


    @swagger_auto_schema(
        operation_description="Create a new app setting",
        request_body=AppSettingSerializer,
        responses={201: AppSettingSerializer()}
    )
    def post(self, request):
        serializer = AppSettingSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "App setting created successfully",
                "data": serializer.data
            }, status=status.HTTP_201_CREATED)

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

class AppSettingEditView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        operation_description="Edit app setting by ID (POST instead of PUT)",
        request_body=AppSettingSerializer,
        responses={200: AppSettingSerializer()}
    )
    def post(self, request, pk):
        try:
            setting = AppSetting.objects.get(pk=pk)
        except AppSetting.DoesNotExist:
            return Response({"error": "AppSetting not found"}, status=status.HTTP_404_NOT_FOUND)

        serializer = AppSettingSerializer(setting, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "App setting updated successfully",
                "data": serializer.data
            }, status=status.HTTP_200_OK)

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

        #plans funcrions

class PlanListView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        operation_description="Retrieve all plans with optional search filter",
        manual_parameters=[
            openapi.Parameter(
                'search',
                openapi.IN_QUERY,
                description="Search by coins, amount",
                type=openapi.TYPE_STRING
            )
        ],
        responses={200: PlanSerializer(many=True)}
    )
    def get(self, request):
        plans = Plan.objects.all()
        search_term = request.query_params.get('search')

        if search_term:
            search_fields = ['coins', 'amount']
            plans = apply_search(plans, search_term, search_fields)

        serializer = PlanSerializer(plans, many=True)
        return Response({"status": "success", "message": "Plans retrieved successfully", "data": serializer.data}, status=status.HTTP_200_OK)


class PlanCreateView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        request_body=PlanSerializer,
        responses={201: PlanSerializer, 400: "Invalid input"},
        operation_description="Create a new plan"
    )
    def post(self, request):
        serializer = PlanSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({"status": "success", "message": "Plan created successfully", "data": serializer.data}, status=status.HTTP_201_CREATED)
        return Response({"status": "error", "message": "Invalid input", "errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)


class PlanUpdateView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        request_body=PlanSerializer,
        responses={200: PlanSerializer, 400: "Invalid input", 404: "Plan not found"},
        operation_description="Update an existing plan by ID"
    )
    def post(self, request, pk):
        plan = get_object_or_404(Plan, pk=pk)
        serializer = PlanSerializer(plan, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response({"status": "success", "message": "Plan updated successfully", "data": serializer.data}, status=status.HTTP_200_OK)
        return Response({"status": "error", "message": "Invalid input", "errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)


class PlanDeleteView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        responses={200: "Plan deleted successfully", 404: "Plan not found"},
        operation_description="Delete a plan by ID"
    )
    def post(self, request, pk):
        try:
            plan = Plan.objects.get(pk=pk)
            plan.delete()
            return Response({"status": "success", "message": "Plan deleted successfully."}, status=status.HTTP_200_OK)
        except Plan.DoesNotExist:
            return Response({"status": "error", "message": "Plan not found."}, status=status.HTTP_404_NOT_FOUND)


class PlanStatusUpdateView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=["status"],
            properties={
                "status": openapi.Schema(type=openapi.TYPE_BOOLEAN, description="New status (true/false)"),
            },
        ),
        responses={200: "Status updated successfully", 400: "Status field is required", 404: "Plan not found"},
        operation_description="Update the status of a plan"
    )
    def post(self, request, pk):
        try:
            plan = Plan.objects.get(pk=pk)
        except Plan.DoesNotExist:
            return Response({"status": "error", "message": "Plan not found."}, status=status.HTTP_404_NOT_FOUND)

        status_value = request.data.get('status')
        if status_value is None:
            return Response({"status": "error", "message": "Status field is required."}, status=status.HTTP_400_BAD_REQUEST)

        plan.status = bool(status_value)
        plan.save()
        return Response({"status": "success", "message": "Status updated successfully", "status_value": plan.status}, status=status.HTTP_200_OK)


# Female rewards
class FemaleRewardListView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    @swagger_auto_schema(
        operation_description="Retrieve all female rewards with filters (type, user_type, date, search)",
        manual_parameters=[
            openapi.Parameter('type', openapi.IN_QUERY, description="1 for Voice, 2 for Video", type=openapi.TYPE_INTEGER),
            openapi.Parameter('user_type', openapi.IN_QUERY, description="1 for Normal, 2 for Premium", type=openapi.TYPE_INTEGER),
            openapi.Parameter('search', openapi.IN_QUERY, description="Search by start_min, end_min, coins", type=openapi.TYPE_STRING),
            openapi.Parameter('start_date', openapi.IN_QUERY, description="Start date (YYYY-MM-DD)", type=openapi.TYPE_STRING),
            openapi.Parameter('end_date', openapi.IN_QUERY, description="End date (YYYY-MM-DD)", type=openapi.TYPE_STRING),
        ],
        responses={200: FemaleRewardSerializer(many=True)}
    )
    def get(self, request):
        rewards = FemaleReward.objects.all()

        reward_type = request.query_params.get("type")
        user_type = request.query_params.get("user_type")
        search = request.query_params.get("search")
        start_date = parse_date(request.query_params.get("start_date", ""))
        end_date = parse_date(request.query_params.get("end_date", ""))

        if reward_type:
            rewards = rewards.filter(type=reward_type)

        if user_type:
            rewards = rewards.filter(user_type=user_type)

        if start_date:
            rewards = rewards.filter(created_at__date__gte=start_date)
        if end_date:
            rewards = rewards.filter(created_at__date__lte=end_date)

        if search:
            rewards = rewards.filter(
                Q(start_min__icontains=search) |
                Q(end_min__icontains=search) |
                Q(coins__icontains=search)
            )

        rewards = rewards.order_by('type', 'start_min')
        grouped = {}

        for reward in rewards:
            key = (reward.type, reward.start_min, reward.end_min)
            if key not in grouped:
                grouped[key] = {
                    "Type": reward.type,
                    "Duration": f"{reward.start_min} - {reward.end_min}",
                    "Normal": None,
                    "Normal_id": None,
                    "Normal_status": None,
                    "Premium": None,
                    "Premium_id": None,
                    "Premium_status": None
                }

            if reward.user_type == 1:
                grouped[key]["Normal"] = reward.coins
                grouped[key]["Normal_id"] = reward.id
                grouped[key]["Normal_status"] = reward.status
            elif reward.user_type == 2:
                grouped[key]["Premium"] = reward.coins
                grouped[key]["Premium_id"] = reward.id
                grouped[key]["Premium_status"] = reward.status

        result = list(grouped.values())
        return Response({"status": "success", "data": result}, status=status.HTTP_200_OK)


class FemaleRewardCreateView(APIView):
    permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        request_body=FemaleRewardInputSerializer,
        responses={201: "FemaleRewards created successfully"},
        operation_description="Create new FemaleRewards for Normal and Premium users"
    )
    def post(self, request):
        serializer = FemaleRewardInputSerializer(data=request.data)
        if serializer.is_valid():
            type_value = int(serializer.validated_data['Type'])
            start_min, end_min = serializer.validated_data['Duration']

            normal_coins = serializer.validated_data['Normal']
            premium_coins = serializer.validated_data['Premium']

            rewards = []

            for user_type, coins in [(1, normal_coins), (2, premium_coins)]:
                reward = FemaleReward.objects.create(
                    type=type_value,
                    user_type=user_type,
                    start_min=start_min,
                    end_min=end_min,
                    coins=coins,
                    duration=f"{start_min} - {end_min}"
                )
                rewards.append(FemaleRewardSerializer(reward).data)

            return Response({
                "status": "success",
                "message": "FemaleRewards created successfully",
                "data": rewards
            }, status=status.HTTP_201_CREATED)

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


class FemaleRewardEditView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    def post(self, request, pk=None):
        serializer = FemaleRewardCustomSerializer(data=request.data)
        if not serializer.is_valid():
            return Response({
                "status": "error",
                "message": "Invalid data",
                "errors": serializer.errors
            }, status=status.HTTP_400_BAD_REQUEST)

        data = serializer.validated_data
        start_min, end_min = map(float, data["Duration"].split("-"))
        reward_type = data["Type"]

        updated_instances = []

        if data.get("Normal_id") is not None and data.get("Normal") is not None:
            normal = get_object_or_404(FemaleReward, id=data["Normal_id"], user_type=1)
            normal.type = reward_type
            normal.start_min = start_min
            normal.end_min = end_min
            normal.coins = data["Normal"]
            normal.save()
            updated_instances.append(normal)

        if data.get("Premium_id") is not None and data.get("Premium") is not None:
            premium = get_object_or_404(FemaleReward, id=data["Premium_id"], user_type=2)
            premium.type = reward_type
            premium.start_min = start_min
            premium.end_min = end_min
            premium.coins = data["Premium"]
            premium.save()
            updated_instances.append(premium)

        return Response({
            "status": "success",
            "message": "Reward(s) updated successfully",
            "data": [FemaleRewardCustomSerializer(instance).data for instance in updated_instances]
        }, status=status.HTTP_200_OK)




class FemaleRewardStatusUpdateView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    def post(self, request):
        status_value = request.data.get('status')
        normal_id = request.data.get('Normal_id')
        premium_id = request.data.get('Premium_id')

        if status_value is None:
            return Response({"status": "error", "message": "Status field is required."}, status=status.HTTP_400_BAD_REQUEST)

        updated = []

        if normal_id:
            normal_reward = get_object_or_404(FemaleReward, pk=normal_id, user_type=1)
            normal_reward.status = status_value
            normal_reward.save()
            updated.append({
                "id": normal_reward.id,
                "user_type": "Normal",
                "status": normal_reward.status
            })

        if premium_id:
            premium_reward = get_object_or_404(FemaleReward, pk=premium_id, user_type=2)
            premium_reward.status = status_value
            premium_reward.save()
            updated.append({
                "id": premium_reward.id,
                "user_type": "Premium",
                "status": premium_reward.status
            })

        if not updated:
            return Response({"status": "error", "message": "At least one of Normal_id or Premium_id is required."}, status=status.HTTP_400_BAD_REQUEST)

        return Response({
            "status": "success",
            "message": "Status updated successfully",
            "updated_rewards": updated
        }, status=status.HTTP_200_OK)
    

class FemaleRewardDeleteView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    def post(self, request):
        normal_id = request.data.get('Normal_id')
        premium_id = request.data.get('Premium_id')

        deleted = []

        if normal_id:
            normal_reward = get_object_or_404(FemaleReward, pk=normal_id, user_type=1)
            normal_reward.delete()
            deleted.append({
                "id": normal_id,
                "user_type": "Normal",
                "deleted": True
            })

        if premium_id:
            premium_reward = get_object_or_404(FemaleReward, pk=premium_id, user_type=2)
            premium_reward.delete()
            deleted.append({
                "id": premium_id,
                "user_type": "Premium",
                "deleted": True
            })

        if not deleted:
            return Response({
                "status": "error",
                "message": "At least one of Normal_id or Premium_id is required."
            }, status=status.HTTP_400_BAD_REQUEST)

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