from django.shortcuts import get_object_or_404, render
from rest_framework.views import APIView, exception_handler
from rest_framework.response import Response
from rest_framework import status
from rest_framework.authtoken.models import Token
from .models import Users, OTP, Address, UserLocation
from shops.models import Shop
from orders.models import Cart, NotificationStat
from datetime import timedelta
from django.utils import timezone
import random
from rest_framework_simplejwt.tokens import AccessToken
from .serializers import UserProfileSerializer, AddressSerializer
from rest_framework.permissions import IsAuthenticated
import jwt
import uuid
import googlemaps
from django.conf import settings
from django.core.mail import send_mail
from django.urls import reverse
from firebase_admin import messaging
from firebase_admin import credentials
import firebase_admin



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
        if mobile_number:
            mobile_number = mobile_number.replace(" ", "")
        user, created = Users.objects.get_or_create(
            phone_number=mobile_number, user_type="Customer"
        )
        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")
            anonymous_id = request.data.get("anonymous_id")
            fcm_token = request.data.get("fcm_token")
            if mobile_number:
                mobile_number = mobile_number.replace(" ", "")

            # 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__phone_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(Users, phone_number=mobile_number)

                # Create or get the auth token
                token, created = Token.objects.get_or_create(user=user)
                user.fcm_token = fcm_token
                user.save()

                # Generate JWT token
                access_token = AccessToken.for_user(user)

                otp.delete()
                if anonymous_id:
                    Cart.objects.filter(user=user).delete()
                    UserLocation.objects.filter(user=user).delete()
                    Cart.objects.filter(anonymous_id=anonymous_id).update(user=user, anonymous_id=None)
                    UserLocation.objects.filter(anonymous_id=anonymous_id).update(user=user, anonymous_id=None)

                return Response(
                    {
                        "status": 1,
                        "message": "OTP verified successfully!",
                        "auth_token": token.key,
                        "jwt_token": str(access_token),
                    },
                    status=status.HTTP_200_OK,
                )
            else:
                return Response(
                    {"status": 0, "message": "Invalid or expired OTP."},
                    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,
            )


class UserProfileView(APIView):
    """
    View for getting and updating user profile.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        user = request.user
        serializer = UserProfileSerializer(user)
        return Response(
            {
                "status": 1,
                "message": "User profile retrieved successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )

    def put(self, request):
        user = request.user
        old_email = user.email
        serializer = UserProfileSerializer(user, data=request.data, partial=True)

        if serializer.is_valid():
            new_email = serializer.validated_data.get("email", old_email)  # type: ignore

            # Check if email has changed
            if new_email != old_email:
                serializer.validated_data["email_verified"] = False  # type: ignore

            serializer.save()
            return Response(
                {
                    "status": 1,
                    "message": "User profile updated successfully.",
                    "data": serializer.data,
                },
                status=status.HTTP_200_OK,
            )
        return Response(
            {
                "status": 0,
                "message": "Profile update failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


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

    permission_classes = [IsAuthenticated]

    def post(self, request):
        user = request.user
        if user.email_verified:
            return Response(
                {"status": 0, "message": "Email already verified."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Create a token
        token = jwt.encode(
            {"user_id": str(user.uuid), "exp": timezone.now() + timedelta(hours=24)},
            settings.SECRET_KEY,
            algorithm="HS256",
        )

        # Create verification link
        verification_link = request.build_absolute_uri(
            reverse("verify-email", args=[token])
        )

        # Send the email
        send_mail(
            "Verify your email",
            f"Click the link to verify your email: {verification_link}",
            settings.DEFAULT_FROM_EMAIL,
            [user.email],
            fail_silently=False,
        )

        return Response(
            {"status": 1, "message": "Verification email sent."},
            status=status.HTTP_200_OK,
        )


class VerifyEmailView(APIView):
    def get(self, request, token):
        try:
            payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
            user = get_object_or_404(Users, uuid=payload["user_id"])

            # Update email verification status
            user.email_verified = True
            user.save()

            return render(
                request,
                "email_verification.html",
                {"status": 1, "message": "Email verified successfully."},
            )
        except jwt.ExpiredSignatureError:
            return render(
                request,
                "email_verification.html",
                {"status": 0, "message": "Verification link has expired."},
            )
        except jwt.InvalidTokenError:
            return render(
                request,
                "email_verification.html",
                {"status": 0, "message": "Invalid verification link."},
            )


class AddressDetailView(APIView):
    """View for retrieving, creating, updating, and deleting a specific address."""

    permission_classes = [IsAuthenticated]

    def get_object(self, user, pk):
        return Address.objects.filter(user=user).get(pk=pk)

    def get(self, request, pk=None, *args, **kwargs):
        if pk is None:
            addresses = Address.objects.filter(user=request.user)
            serializer = AddressSerializer(addresses, many=True)
            return Response(
                {
                    "status": 1,
                    "message": "Addresses retrieved successfully!",
                    "data": serializer.data,
                },
                status=status.HTTP_200_OK,
            )
        else:
            address = self.get_object(request.user, pk)
            serializer = AddressSerializer(address)
            return Response(
                {
                    "status": 1,
                    "message": "Address retrieved successfully!",
                    "data": serializer.data,
                },
                status=status.HTTP_200_OK,
            )

    def post(self, request, *args, **kwargs):
        serializer = AddressSerializer(data=request.data)
        if serializer.is_valid():
            address = serializer.save(user=request.user)
            return Response(
                {
                    "status": 1,
                    "message": "Address created successfully!",
                    "data": AddressSerializer(address).data,
                },
                status=status.HTTP_201_CREATED,
            )
        return Response(
            {
                "status": 0,
                "message": "Address creation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )

    def put(self, request, pk, *args, **kwargs):
        address = self.get_object(request.user, pk)
        serializer = AddressSerializer(address, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(
                {
                    "status": 1,
                    "message": "Address updated successfully!",
                    "data": serializer.data,
                },
                status=status.HTTP_200_OK,
            )
        return Response(
            {
                "status": 0,
                "message": "Address update failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )

    def delete(self, request, pk, *args, **kwargs):
        address = self.get_object(request.user, pk)
        address.delete()
        return Response(
            {"status": 1, "message": "Address deleted successfully!"},
            status=status.HTTP_200_OK,
        )


class SaveUserLocationView(APIView):
    def post(self, request):
        latitude = request.data.get("latitude")
        longitude = request.data.get("longitude")
        address_id = request.data.get("address_id")
        if latitude and longitude:
            if request.user.is_authenticated:
                user = request.user
                anonymous_id = None
            else:
                user = None
                anonymous_id = request.data.get("anonymous_id")
                if not anonymous_id:
                    anonymous_id = uuid.uuid4()

            # Find the nearest shop
            user_location = (float(latitude), float(longitude))
            gmaps = googlemaps.Client(key="AIzaSyBqLt_zwm0JnJR8Rm29_Lqrs0I5P0CkcYU")
            reverse_geocode_result = gmaps.reverse_geocode((latitude, longitude))  # type: ignore

            street_name = city_name = state_name = ""

            if reverse_geocode_result:
                address_components = reverse_geocode_result[0].get("address_components", [])
                for component in address_components:
                    if "route" in component["types"]:
                        street_name = component["long_name"]
                    if "locality" in component["types"]:
                        city_name = component["long_name"]
                    if "administrative_area_level_1" in component["types"]:
                        state_name = component["long_name"]
            shops = Shop.objects.filter(latitude__isnull=False, longitude__isnull=False)

            distances = []
            for shop in shops:
                shop_location = (shop.latitude, shop.longitude)
                result = gmaps.distance_matrix(origins=user_location, destinations=shop_location,
                                               mode="driving")  # type: ignore
                road_distance = result["rows"][0]["elements"][0]["distance"]["value"]
                if road_distance <= shop.delivery_radius * 1000:
                    distances.append((shop, road_distance))

            distances.sort(key=lambda x: x[1])
            nearest_shop = distances[0][0] if distances else None

            if address_id:
                try:
                    address = Address.objects.get(id=address_id, user=user)
                    location, created = UserLocation.objects.update_or_create(
                        anonymous_id=anonymous_id if not user else None,
                        user=user if user else None,
                        defaults={
                            "address": address,
                            "is_selected_address": True,
                            "latitude": latitude,
                            "longitude": longitude,
                            "shop": nearest_shop,
                            "location_address": f"{street_name}, {city_name}, {state_name}",

                        },
                    )
                except Address.DoesNotExist:
                    return Response(
                        {"status": 0, "message": "Address not found."},
                        status=404,
                    )
            else:
                location, created = UserLocation.objects.update_or_create(
                    anonymous_id=anonymous_id if not user else None,
                    user=user if user else None,
                    defaults={
                        "latitude": latitude,
                        "longitude": longitude,
                        "shop": nearest_shop,
                        "is_selected_address": False,
                        "address": None,
                        "location_address": f"{street_name}, {city_name}, {state_name}",

                    },
                )

            return Response(
                {
                    "status": 1,
                    "message": "Location and nearest shop saved successfully.",
                    "location": {
                        "latitude": location.latitude,
                        "longitude": location.longitude,
                        "shop": location.shop.uuid if location.shop else None,
                        "anonymous_id": anonymous_id,
                        "is_selected_address": location.is_selected_address,
                        "address_id": location.address.id if location.address else None,  # type: ignore
                        "location_address": location.location_address,
                    },
                },
                status=200,
            )

        return Response(
            {"status": 0, "message": "Latitude and longitude are required."},
            status=400,
        )




class FetchUserLocationView(APIView):
    def post(self, request):
        anonymous_id = request.data.get("anonymous_id")
        if request.user.is_authenticated:
            user = request.user
            try:
                location = UserLocation.objects.get(user=user)
                response_data = {
                    "latitude": location.latitude,
                    "longitude": location.longitude,
                    "shop": location.shop.uuid if location.shop else None,
                    "anonymous_id": None,  # No anonymous ID for authenticated users
                    "is_selected_address": location.is_selected_address,
                    "address_id": location.address.id if location.address else None, # type: ignore
                    "address": {
                        "flat_no": location.address.flat_no if location.address else None,
                        "landmark": location.address.landmark if location.address else None,
                    } if location.address else None,
                    "location_address": location.location_address,
                }
                return Response(
                    {
                        "status": 1,
                        "message": "Location fetched successfully.",
                        "location": response_data,
                    },
                    status=200,
                )
            except UserLocation.DoesNotExist:
                return Response(
                    {"status": 0, "message": "Location not found for this user."},
                    status=404,
                )

        else:
            if not anonymous_id:
                return Response(
                    {"status": 0, "message": "Anonymous ID is required."},
                    status=400,
                )

            try:
                location = UserLocation.objects.get(anonymous_id=anonymous_id)
                response_data = {
                    "latitude": location.latitude,
                    "longitude": location.longitude,
                    "shop": location.shop.uuid if location.shop else None,
                    "anonymous_id": anonymous_id,
                    "is_selected_address": location.is_selected_address,
                    "address_id": location.address.id if location.address else None, # type: ignore
                    "address": {
                        "flat_no": location.address.flat_no if location.address else None,
                        "landmark": location.address.landmark if location.address else None,
                    } if location.address else None,
                    "location_address": location.location_address
                }
                return Response(
                    {
                        "status": 1,
                        "message": "Location fetched successfully.",
                        "location": response_data,
                    },
                    status=200,
                )
            except UserLocation.DoesNotExist:
                return Response(
                    {"status": 0, "message": "Location not found for anonymous user."},
                    status=404,
                )


def notification_stat_post(Order, Notification_title, sendTo,description ):


    try:

        notification_data = NotificationStat.objects.create(Sendmsg=Notification_title, OrderID=Order,
                                                            sendTo=sendTo, Description= description)
        notification_data.save()
    except Exception as e:

        pass




def send_notification(fcmToken, Order, title, description,sendTo):
    notification_stat_post(Order, title, sendTo, description)
    if not firebase_admin._apps:
        cred = credentials.Certificate(
        r"/var/www/html/Testing_prj/Navya-Bakers/constants/navyabakers-1d955-firebase-adminsdk-fbsvc-d2f9578075.json")
        #
        # cred = credentials.Certificate(
        #     r"C:\NavyaProject\Navya-Bakers\constants\navyabakers-1d955-firebase-adminsdk-fbsvc-d2f9578075.json")

        firebase_admin.initialize_app(cred)

#     "priority": "high",
#     "restricted_package_name": "com.collabll.orderpickyboy"

#     # See documentation on defining a message payload.


        message = messaging.Message(
            data={"title": title, "description": description, "orderID": Order.order_ID},
            android=messaging.AndroidConfig(
                priority='high'

            ),
            apns=messaging.APNSConfig(headers={"apns-priority": "5"}, payload=messaging.APNSPayload(
                aps=messaging.Aps(badge=99, alert=messaging.ApsAlert(title=title, body=description, ),
                                  sound="default", custom_data={"orderID": Order.order_ID}),
            ))
        ,

            token=fcmToken, )


        try:


            response = messaging.send(message)




        except Exception as e:
            pass


    else:
        message = messaging.Message(


        data={"title": title, "description": description, "orderID": Order.order_ID},

        android = messaging.AndroidConfig(
            priority='high'

        ),
            apns=messaging.APNSConfig(headers={"apns-priority": "5"}, payload=messaging.APNSPayload(
                aps=messaging.Aps(badge=99, alert=messaging.ApsAlert(title=title, body=description, ),
                                  sound="default", custom_data={"orderID": Order.order_ID}),
            ))
        ,

        token=fcmToken)
        try:

            response = messaging.send(message)

        except Exception as e:

            pass
def initialize_fcm_app():
    if not firebase_admin._apps:
        # cred = credentials.Certificate(
        #     r"C:\NavyaProject\Navya-Bakers\constants\navyabakers-1d955-firebase-adminsdk-fbsvc-d2f9578075.json")
        cred = credentials.Certificate(
        r"/var/www/html/Testing_prj/Navya-Bakers/constants/navyabakers-1d955-firebase-adminsdk-fbsvc-d2f9578075.json")
        firebase_admin.initialize_app(cred)


