from rest_framework import status
from rest_framework.views import APIView, exception_handler
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
from .models import CustomUser, OTP
from .serializers import CustomUserSerializer, OTPSerializer
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.contrib.auth import authenticate
from datetime import timedelta
from rest_framework_simplejwt.tokens import AccessToken
from rest_framework.exceptions import AuthenticationFailed, NotAuthenticated
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework.permissions import IsAuthenticated
import random
from django.core.mail import send_mail
from django.urls import reverse
from django.conf import settings
import uuid
import traceback


class AdminLoginAPIView(APIView):
    """
    View to authenticate admin users and return JWT Token
    """

    def post(self, request, *args, **kwargs):
        mobile_number = request.data.get("mobile_number")
        password = request.data.get("password")
        try:
            user = authenticate(mobile_number=mobile_number, password=password)
            if user is not None and user.is_staff:  # type: ignore
                token = AccessToken.for_user(user)

                return Response(
                    {"status": 1, "message": "Login successful", "token": str(token)},
                    status=status.HTTP_200_OK,
                )
            else:
                return Response(
                    {
                        "status": 0,
                        "message": "Invalid credentials or user is not an admin",
                    },
                    status=status.HTTP_401_UNAUTHORIZED,
                )
        except Exception as e:
            return Response(
                {"status": 0, "message": "An unexpected error occured", "exc":str(e), "traceback":traceback.format_exc()},
                status=status.HTTP_400_BAD_REQUEST,
            )


class UserLoginView(APIView):
    """
    View for user login (also used for registration).
    """

    def post(self, request):
        mobile_number = request.data.get("mobile_number")

        # Check if user exists
        user, created = CustomUser.objects.get_or_create(mobile_number=mobile_number)
        OTP.objects.filter(user=user).delete()
        otp_code = random.randint(1000, 9999)
        OTP.objects.create(user=user, otp_code=otp_code)

        return Response(
            {"status": 1, "message": "OTP sent successfully!", "otp": otp_code},
            status=status.HTTP_200_OK,
        )


class OTPVerificationView(APIView):
    """
    View for OTP verification.
    """

    def post(self, request):
        try:
            mobile_number = request.data.get("mobile_number")
            otp_code = request.data.get("otp_code")

            # Get the most recent OTP that is not older than 2 minutes
            two_minutes_ago = timezone.now() - timedelta(minutes=2)
            otp = (
                OTP.objects.filter(
                    user__mobile_number=mobile_number,
                    otp_code=otp_code,
                    created_at__gte=two_minutes_ago,
                )
                .order_by("-created_at")
                .first()
            )

            if otp:
                user = get_object_or_404(CustomUser, mobile_number=mobile_number)
                token, created = Token.objects.get_or_create(user=user)
                new_user = not (user.first_name)
                otp.delete()  # Delete the OTP once it's used
                return Response(
                    {
                        "status": 1,
                        "message": "OTP verified successfully!",
                        "token": token.key,
                        "new_user": new_user,
                        "is_verified": user.is_verified,
                    },
                    status=status.HTTP_200_OK,
                )
            else:
                return Response(
                    {"status": 0, "message": "Invalid or expired OTP."},
                    status=status.HTTP_200_OK,
                )
        except Exception as e:
            return Response(
                {"status": 0, "message": "An unexpected error occurred."},
                status=status.HTTP_400_BAD_REQUEST,
            )


class UserIsVerifiedView(APIView):
    """
    View to check if the user is verified.
    """

    def get(self, request):
        # Retrieve the user associated with the provided token
        token_key = request.META.get("HTTP_AUTHORIZATION").split()[1]
        try:
            token = Token.objects.get(key=token_key)
            user = token.user
            if user.is_verified:
                response_data = {"status": 1, "message": "User is verified."}
            else:
                response_data = {"status": 0, "message": "User is not verified"}
            return Response(response_data, status=status.HTTP_200_OK)
        except Token.DoesNotExist:
            response_data = {"status": 0, "message": "Invalid or expired token."}
            return Response(response_data, status=status.HTTP_401_UNAUTHORIZED)
        except Exception as e:
            response_data = {"status": 0, "message": "An unexpected error occurred."}
            return Response(response_data, status=status.HTTP_400_BAD_REQUEST)


class UserUpdateView(APIView):
    """
    View to update user information.
    """

    def patch(self, request):
        # Retrieve the user associated with the provided token
        token_key = request.META.get("HTTP_AUTHORIZATION").split()[1]
        try:
            token = Token.objects.get(key=token_key)
            user = token.user

            # Partial update of the user
            serializer = CustomUserSerializer(user, data=request.data, partial=True)
            if serializer.is_valid():
                serializer.save()
                return Response(
                    {
                        "status": 1,
                        "message": "User information updated successfully.",
                        "data": serializer.data,
                    },
                    status=status.HTTP_200_OK,
                )
            else:
                return Response(
                    {
                        "status": 0,
                        "message": "Invalid data.",
                        "errors": serializer.errors,
                    },
                    status=status.HTTP_200_OK,
                )
        except Token.DoesNotExist:
            return Response(
                {"status": 0, "message": "Bad request: Token is not valid."},
                status=status.HTTP_401_UNAUTHORIZED,
            )
        except Exception as e:
            response_data = {"status": 0, "message": "An unexpected error occurred."}
            return Response(response_data, status=status.HTTP_400_BAD_REQUEST)


def custom_exception_handler(exc, context):
    response = exception_handler(exc, context)
    if isinstance(exc, AuthenticationFailed):
        response.data = {  # type: ignore
            "status": 0,
            "message": "Invalid or expired token.",
        }
        return response


class UserListView(APIView):
    """
    View to list users with optional filtering.
    """

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            filter_params = request.data  # Get all parameters from the request body
            users = CustomUser.objects.filter(**filter_params)
            serializer = CustomUserSerializer(users, many=True)
            return Response(
                {
                    "status": 1,
                    "message": "Users retrieved successfully",
                    "data": serializer.data,
                },
                status=status.HTTP_200_OK,
            )
        except Exception as e:
            return Response(
                {"status": 0, "message": "An unexpected error occurred"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class CreateDriverView(APIView):
    """
    View to create a new driver.
    """

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        try:
            serializer = CustomUserSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save(is_driver=True)
                return Response(
                    {"status": 1, "message": "Driver created successfully"},
                    status=status.HTTP_201_CREATED,
                )
            else:
                return Response(
                    {"status": 0, "message": "Invalid data", "errors": serializer.errors},
                    status=status.HTTP_400_BAD_REQUEST,
                )
        except Exception as e:
            respose_data ={"status":0,
                           "message":"An unexpected error occured."
                           }
            return Response(
                respose_data, status=status.HTTP_400_BAD_REQUEST
            )


class DeleteDriverView(APIView):
    """
    View to delete a driver by ID.
    """

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def delete(self, request, driver_id):
        try:
            driver = CustomUser.objects.get(id=driver_id)
            driver.delete()  # Delete the associated User
            return Response(
                {"status": 1, "message": "Driver deleted successfully"},
                status=status.HTTP_200_OK,
            )
        except CustomUser.DoesNotExist:
            return Response(
                {"status": 0, "message": "Driver not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"status": 0, "message": "An unexpected error occurred"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class UpdateDriverView(APIView):
    """
    View to update driver information by ID.
    """

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def patch(self, request, driver_id):
        try:
            driver = CustomUser.objects.get(id=driver_id)
            serializer = CustomUserSerializer(driver, data=request.data, partial=True)
            if serializer.is_valid():
                serializer.save()
                return Response(
                    {
                        "status": 1,
                        "message": "Driver information updated successfully",
                        "data":serializer.data
                        },
                    status=status.HTTP_200_OK,
                )
            else:
                return Response(
                    {
                     "status": 0, 
                     "message": "Invalid data", 
                     "errors": serializer.errors
                     },
                    status=status.HTTP_400_BAD_REQUEST,
                )
        except CustomUser.DoesNotExist:
            return Response(
                {
                    "status":0,
                    "message":"Driver not found",
                },status=status.HTTP_404_NOT_FOUND
            )
        
        except Exception as e:
            respose_data ={"status":0,"message":"An unexpected error occured."}
            return Response(
                respose_data, status=status.HTTP_400_BAD_REQUEST
            )


class DriverDetailView(APIView):
    """
    View to retrieve driver information by ID.
    """

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request, driver_id):
        try:
            driver = CustomUser.objects.get(id=driver_id)
            serializer = CustomUserSerializer(driver)
            return Response(
                {
                    "status": 1,
                    "message": "Driver information retrieved successfully",
                    "data": serializer.data,
                },
                status=status.HTTP_200_OK,
            )
        except CustomUser.DoesNotExist:
            return Response(
                {"status": 0, "message": "Driver not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"status": 0, "message": "An unexpected error occurred"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


class SendVerificationEmailView(APIView):
    """
    View to send a verification email to the user.
    """

    def post(self, request):
        token_key = request.META.get("HTTP_AUTHORIZATION").split()[1]
        try:
            token = Token.objects.get(key=token_key)
            user = token.user
            verification_token = uuid.uuid4()
            user.verification_token = str(verification_token)
            user.token_created_at = timezone.now()
            user.save(update_fields=["verification_token", "token_created_at"])
            verification_link = request.build_absolute_uri(
                reverse("verify-email", args=[verification_token])
            )
            send_mail(
                "Verify your account",
                f"Please click on the link to verify your account: {verification_link}",
                settings.DEFAULT_FROM_EMAIL,
                [user.email],
                fail_silently=False,
            )
            return Response(
                {
                    "status": 1,
                    "message": "Verification email sent successfully.",
                    "verification link": verification_link,
                },
                status=status.HTTP_200_OK,
            )
        except Token.DoesNotExist:
            return Response(
                {"status": 0, "message": "Bad request: Token is not valid."},
                status=status.HTTP_401_UNAUTHORIZED,
            )
        except Exception as e:
            response_data = {
                "status": 0,
                "message": "An unexpected error occurred.",
                "exception": str(e),
            }
            return Response(response_data, status=status.HTTP_400_BAD_REQUEST)


class VerifyEmailView(APIView):
    """
    View to handle email verification with token expiration check.
    """

    def get(self, request, verification_token):
        try:
            # Find the user with the given verification token
            user = CustomUser.objects.get(verification_token=verification_token)

            # Check if the token has expired (1 day from token creation)
            token_age = timezone.now() - user.token_created_at  # type: ignore
            if token_age > timedelta(days=1):
                return Response(
                    {"status": 0, "message": "Verification token has expired."},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Verify the user's email if the token is valid and not expired
            if user and not user.is_verified:
                user.is_verified = True
                user.verification_token = None  # Clear the verification token
                user.token_created_at = None  # Clear the token creation timestamp
                user.save(
                    update_fields=[
                        "is_verified",
                        "verification_token",
                        "token_created_at",
                    ]
                )
                return Response(
                    {"status": 1, "message": "Email verified successfully."},
                    status=status.HTTP_200_OK,
                )
            else:
                return Response(
                    {"status": 0, "message": "Email is already verified."},
                    status=status.HTTP_200_OK,
                )
        except CustomUser.DoesNotExist:
            return Response(
                {"status": 0, "message": "Invalid verification token."},
                status=status.HTTP_400_BAD_REQUEST,
            )
        except Exception as e:
            return Response(
                {
                    "status": 0,
                    "message": "An unexpected error occurred.",
                    "exception": str(e),
                },
                status=status.HTTP_400_BAD_REQUEST,
            )
