from rest_framework import viewsets, permissions
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from rest_framework.authtoken.models import Token
from rest_framework.permissions import IsAuthenticated
from rest_framework.authtoken.views import ObtainAuthToken
from django.contrib.auth.models import User
from drf_yasg.utils import swagger_auto_schema
from rest_framework import status
from drf_yasg import openapi
from django.db.models import Q
from django.shortcuts import get_object_or_404

from rest_framework.parsers import MultiPartParser, FormParser
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
import os
import time
import logging


import boto3
import uuid
import mimetypes
import io

from master.models import Module, Permission, Role, PermissionRole, Admin, Master
from master.authentication import IsActiveAdmin
from master.serializers import (
    ModuleSerializer, PermissionSerializer, RoleSerializer, AdminLoginSerializer,AdminUpdateSerializer,AdminStatusUpdateSerializer,
    PermissionRoleSerializer, AdminSerializer, MasterSerializer, AdminConfirmResetPasswordSerializer, AdminRequestPasswordResetSerializer,
    MasterStatusUpdateSerializer,
)

logger = logging.getLogger('admin_reset')

# Helper function to apply search
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 ModuleViewSet(viewsets.ModelViewSet):
    queryset = Module.objects.all()
    serializer_class = ModuleSerializer
    permission_classes = [permissions.IsAuthenticated, IsActiveAdmin]


class PermissionViewSet(viewsets.ModelViewSet):
    queryset = Permission.objects.all()
    serializer_class = PermissionSerializer
    permission_classes = [permissions.IsAuthenticated, IsActiveAdmin]


class RoleViewSet(viewsets.ModelViewSet):
    queryset = Role.objects.all()
    serializer_class = RoleSerializer
    permission_classes = [permissions.IsAuthenticated, IsActiveAdmin]


class PermissionRoleViewSet(viewsets.ModelViewSet):
    queryset = PermissionRole.objects.all()
    serializer_class = PermissionRoleSerializer
    permission_classes = [permissions.IsAuthenticated, IsActiveAdmin]

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

    @swagger_auto_schema(responses={200: AdminSerializer(many=True)})
    def get(self, request):
        admins = Admin.objects.all()
        search = request.query_params.get("search")
        if search:
            admins = apply_search(admins, search, ['name', 'email'])
        serializer = AdminSerializer(admins, many=True)
        return Response(serializer.data)

    @swagger_auto_schema(request_body=AdminSerializer, responses={201: AdminSerializer})
    def post(self, request):
        serializer = AdminSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "Admin added successfully",
                "data": serializer.data
            }, status=status.HTTP_201_CREATED)
        return Response({
            "status": "error",
            # "message": "Invalid data provided",
            "message": serializer.errors
    }, status=status.HTTP_400_BAD_REQUEST)

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

    @swagger_auto_schema(responses={200: AdminUpdateSerializer, 404: "Admin not found"})
    def get(self, request, pk):
        admin = get_object_or_404(Admin, pk=pk)
        serializer = AdminUpdateSerializer(admin)
        return Response(serializer.data)

    @swagger_auto_schema(
        request_body=AdminUpdateSerializer,
        responses={
            200: AdminUpdateSerializer,
            404: "Admin not found"
        }
    )
    def post(self, request, pk):
        admin = get_object_or_404(Admin, pk=pk)
        serializer = AdminUpdateSerializer(admin, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "Admin updated successfully",
                "data": serializer.data
            }, status=status.HTTP_200_OK)
        
        return Response({
            "status": "error",
            # "message": "Invalid data provided",
            "message": serializer.errors
    }, status=status.HTTP_400_BAD_REQUEST)

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

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

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


class AdminDeleteAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated, IsActiveAdmin]
    @swagger_auto_schema(
        responses={
            200: "Admin deleted successfully",
            404: "Admin not found"
        }
    )
    def post(self, request, pk):
        admin = get_object_or_404(Admin, pk=pk)
        admin.delete()
        return Response({
            "status": "success",
            "message": "Admin deleted successfully"
        }, status=status.HTTP_200_OK)

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

    @swagger_auto_schema(responses={200: MasterSerializer(many=True)})
    def get(self, request):
        masters = Master.objects.all()
        search = request.query_params.get("search")
        if search:
            masters = apply_search(masters, search, ['name', 'email'])
        serializer = MasterSerializer(masters, many=True)
        return Response(serializer.data)

    @swagger_auto_schema(request_body=MasterSerializer, responses={201: MasterSerializer})
    def post(self, request):
        image = request.FILES.get('image')
        value1_path = None

        if image:
            try:
                image_copy = io.BytesIO(image.read())
                image_copy.seek(0)

                content_type, _ = mimetypes.guess_type(image.name)
                if not content_type:
                    content_type = '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/masters/{uuid.uuid4()}.{image.name.split('.')[-1]}"

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

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

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

        # Prepare serializer data
        data = request.data.copy()
        if value1_path:
            data['value1'] = value1_path

        serializer = MasterSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "Master created successfully",
                "data": serializer.data
            }, status=status.HTTP_201_CREATED)

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


class MasterDetailAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated, IsActiveAdmin]
    parser_classes = [MultiPartParser]

    @swagger_auto_schema(responses={200: MasterSerializer, 404: "Master not found"})
    def get(self, request, pk):
        master = get_object_or_404(Master, pk=pk)
        serializer = MasterSerializer(master)
        return Response(serializer.data)

    
    def post(self, request, pk):
        master = get_object_or_404(Master, pk=pk)
        image = request.FILES.get('image')
        value1_path = None

        if image:
            try:
                image_copy = io.BytesIO(image.read())
                image_copy.seek(0)

                content_type, _ = mimetypes.guess_type(image.name)
                if not content_type:
                    content_type = '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/masters/{uuid.uuid4()}.{image.name.split('.')[-1]}"
                s3.upload_fileobj(
                    image_copy,
                    'foodieninos',
                    filename,
                    ExtraArgs={
                        'ACL': 'public-read',
                        'ContentType': content_type
                    }
                )

                value1_path = f"https://foodieninos.sgp1.cdn.digitaloceanspaces.com/{filename}"
            except Exception as e:
                return Response({"error": f"Image upload failed: {str(e)}"}, status=500)

        data = request.data.copy()
        if value1_path:
            data['value1'] = value1_path

        serializer = MasterSerializer(master, data=data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response({
                "status": "success",
                "message": "Master updated successfully",
                "data": serializer.data
            }, status=status.HTTP_200_OK)

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

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

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

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

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

    @swagger_auto_schema(responses={200: "Master deleted successfully", 404: "Master not found"})
    def post(self, request, pk):
        master = get_object_or_404(Master, pk=pk)
        master.delete()
        return Response({
            "status": "success",
            "message": "Master deleted successfully"
        }, status=status.HTTP_200_OK)

#Admin Auth
class AdminLoginView(ObtainAuthToken):
    permission_classes = [AllowAny]

    def post(self, request):
        serializer = AdminLoginSerializer(data=request.data)

        if not serializer.is_valid():
            return Response({
                "status": "error",
                "message": "Enter valid email or password"
            }, status=status.HTTP_400_BAD_REQUEST)

        admin = serializer.validated_data['admin']

        if not admin.status:
            return Response({
                "status": "error",
                "message": "Your account has been deactivated"
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            user = User.objects.get(username=admin.name)
        except User.DoesNotExist:
            return Response({
                "status": "error",
                "message": "Associated user not found."
            }, status=status.HTTP_400_BAD_REQUEST)

        token, created = Token.objects.get_or_create(user=user)

        admin_data = AdminSerializer(admin).data

        return Response({
            "status": "success",
            "token": token.key,
            "admin": admin_data,
        })
    
class AdminLogoutView(APIView):
    permission_classes = [IsAuthenticated, IsActiveAdmin]

    def post(self, request):
        request.auth.delete()
        return Response({
            "status": "success",
            "message": "Logged out successfully"
        })
    
class AdminRequestPasswordResetView(APIView):
    permission_classes = [AllowAny]

    @swagger_auto_schema(
        request_body=AdminRequestPasswordResetSerializer,
        operation_description="Request password reset email",
        responses={200: 'Reset link sent'}
    )
    def post(self, request):
        serializer = AdminRequestPasswordResetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            logger.info({
                "event": "request_password_reset",
                "email": serializer.validated_data.get("email"),
                "status": "success"
            })
            return Response({"status": "success", "message": "Password reset link sent to your email."})

        logger.warning({
            "event": "request_password_reset",
            "errors": serializer.errors,
            "status": "failed"
        })
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)



class AdminConfirmResetPasswordView(APIView):
    permission_classes = [AllowAny]

    @swagger_auto_schema(
        request_body=AdminConfirmResetPasswordSerializer,
        operation_description="Reset password using UID and token",
        responses={200: "Password reset successful"}
    )
    def post(self, request):
        serializer = AdminConfirmResetPasswordSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            logger.info({
                "event": "confirm_password_reset",
                "status": "success",
                "uid": request.data.get("uid", "N/A")
            })
            return Response({"status": "success", "message": "Password reset successful"})

        logger.warning({
            "event": "confirm_password_reset",
            "errors": serializer.errors,
            "status": "failed",
            "uid": request.data.get("uid", "N/A")
        })
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)