from decimal import Decimal, ROUND_UP
from rest_framework import generics, permissions
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework.views import APIView
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.response import Response
from rest_framework import status
from .models import *
from .serializers import *
from geopy.distance import geodesic
from vehiclehub.models import VehicleType, Vehicle, VehicleAssignment
from accounts.models import DriverLocation, Device
from vehiclehub.serializers import VehicleTypeSerializer
from rest_framework.exceptions import ValidationError
from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.measure import D
from django.contrib.gis.geos import fromstr
from django.contrib.gis.geos import Point
from django.utils import timezone
from datetime import timedelta
from .process import *
import asyncio
import traceback
from django.db import transaction


class LocationListCreateAPIView(generics.ListCreateAPIView):
    queryset = Location.objects.all()
    serializer_class = LocationSerializer
    authentication_classes = [JWTAuthentication]
    permission_classes = [permissions.IsAuthenticated]


class LocationRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Location.objects.all()
    serializer_class = LocationSerializer
    authentication_classes = [JWTAuthentication]
    permission_classes = [permissions.IsAuthenticated]


class NearbyLocationsView(APIView):
    """
    View to get a list of locations within a 30 km radius of the user's current location.
    """

    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request):
        # Retrieve the user's current location from the request body
        user_latitude = request.data.get("latitude")
        user_longitude = request.data.get("longitude")

        if user_latitude is None or user_longitude is None:
            return Response(
                {"status": 0, "message": "Latitude and longitude are required."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Convert latitude and longitude to floats
        user_latitude = float(user_latitude)
        user_longitude = float(user_longitude)
        user_location = (user_latitude, user_longitude)

        # Initialize an empty list to hold nearby locations
        nearby_locations = []

        # Iterate over each location in the database
        for location in Location.objects.all():
            location_coords = (location.latitude, location.longitude)
            distance = geodesic(user_location, location_coords).kilometers

            # Check if the location is within 30 km
            if distance <= 30:
                nearby_locations.append(location)

        # Serialize the queryset
        serializer = LocationSerializer(nearby_locations, many=True)
        return Response(
            {
                "status": 1,
                "message": "Nearby locations retrieved successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )


class AvailableVehicleTypesView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        from_address = request.data.get("from_address")
        to_address = request.data.get("to_address")
        ride_time = request.data.get("ride_time")

        if not (from_address and to_address and ride_time):
            return Response(
                {
                    "status": 0,
                    "message": "From address, to address, and ride time details are required.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            from_latitude = from_address["latitude"]
            from_longitude = from_address["longitude"]
            to_latitude = to_address["latitude"]
            to_longitude = to_address["longitude"]
        except (TypeError, KeyError):
            return Response(
                {
                    "status": 0,
                    "message": "Invalid address format. Latitude and longitude are required for both from and to addresses.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )
        try:
            ride_time = timezone.datetime.strptime(ride_time, "%Y-%m-%dT%H:%M:%S%z")
        except ValueError:
            return Response(
                {
                    "status": 0,
                    "message": "Invalid ride time format. Use ISO format: YYYY-MM-DDTHH:MM:SS+HH:MM.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )
        try:
            distance = calculate_distance(
                from_latitude, from_longitude, to_latitude, to_longitude
            )
        except ValidationError as e:
            return Response(
                {"status": 0, "message": str(e)},
                status=status.HTTP_400_BAD_REQUEST,
            )
        # Find the nearest available drivers
        from_point = fromstr(f"POINT({from_longitude} {from_latitude})", srid=4326)
        adjusted_current_time = timezone.now() - timedelta(minutes=3)
        if (
            adjusted_current_time
            <= ride_time
            <= adjusted_current_time + timedelta(minutes=15)
        ):
            nearest_drivers = DriverLocation.objects.annotate(
                distance=Distance("last_known_location", from_point)
            ).order_by("distance")[:5]
            available_vehicle_types = VehicleType.objects.filter(
                vehicle__status=True,
                vehicle__assignments__driver__in=[
                    driver.driver for driver in nearest_drivers
                ],
                vehicle__assignments__active=True,
                vehicle__assignments__on_ride=False,
            ).distinct()
        else:
            available_vehicle_types = VehicleType.objects.all().distinct()
        vehicle_types_with_fares = []
        for vehicle_type in available_vehicle_types:
            estimated_fare = distance * vehicle_type.per_km_charge  # type: ignore
            rounded_fare = estimated_fare.quantize(Decimal("0.01"), rounding=ROUND_UP)
            vehicle_types_with_fares.append(
                {
                    "id": vehicle_type.id,  # type: ignore
                    "vehicle_type": vehicle_type.vehicle_type,
                    "seating_capacity": vehicle_type.seating_capacity,
                    "per_km_charge": vehicle_type.per_km_charge,
                    "estimated_fare": float(rounded_fare),
                }
            )

        return Response(
            {
                "status": 1,
                "message": "Available vehicle types with estimated fares retrieved successfully.",
                "data": vehicle_types_with_fares,
            },
            status=status.HTTP_200_OK,
        )


class FareEstimationView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        print("Step 1: Retrieving request data")
        vehicle_type_id = request.data.get("vehicle_type_id")
        from_address = request.data.get("from_address")
        to_address = request.data.get("to_address")
        ride_time = request.data.get("ride_time")
        if not (vehicle_type_id and from_address and to_address and ride_time):
            print("Step 2: Checking if all required data is present")
            return Response(
                {
                    "status": 0,
                    "message": "Vehicle type, address details, ride time are required.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            print("Step 3: Extracting latitude and longitude from address")
            from_latitude = from_address["latitude"]
            from_longitude = from_address["longitude"]
            to_latitude = to_address["latitude"]
            to_longitude = to_address["longitude"]
        except (TypeError, KeyError):
            print("Step 4: Handling invalid address format")
            return Response(
                {
                    "status": 0,
                    "message": "Invalid address format. Latitude and longitude are required for both from and to addresses.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            print("Step 5: Calculating distance")
            distance = calculate_distance(
                from_latitude, from_longitude, to_latitude, to_longitude
            )
        except ValidationError as e:
            print("Step 6: Handling validation error")
            return Response(
                {"status": 0, "message": str(e)},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            print("Step 7: Retrieving vehicle type")
            vehicle_type = VehicleType.objects.get(id=vehicle_type_id)
        except VehicleType.DoesNotExist:
            print("Step 8: Handling vehicle type not found error")
            return Response(
                {"status": 0, "message": "Vehicle type not found."},
                status=status.HTTP_404_NOT_FOUND,
            )

        print("Step 9: Calculating estimated fare")
        estimated_fare = distance * vehicle_type.per_km_charge  # type: ignore
        rounded_fare = estimated_fare.quantize(Decimal("0.01"), rounding=ROUND_UP)

        print("Step 13: Returning response")
        return Response(
            {
                "status": 1,
                "message": "Estimated fare calculated successfully.",
                "base_fare": "20",
                "rate_per_km": vehicle_type.per_km_charge,
                "total_km": distance,
                "estimated_fare": float(rounded_fare),
            },
            status=status.HTTP_200_OK,
        )


class ConfirmRideView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        vehicle_type_id = request.data.get("vehicle_type_id")
        pickup_name = request.data.get("pickup_name")
        dropoff_name = request.data.get("dropoff_name")
        pickup_location = request.data.get("pickup_location")
        dropoff_location = request.data.get("dropoff_location")
        ride_time = request.data.get("ride_time")
        device_token = request.data.get("device_token")

        if not all(
            [
                vehicle_type_id,
                pickup_location,
                dropoff_location,
                ride_time,
                device_token,
            ]
        ):
            return Response(
                {
                    "status": 0,
                    "message": "All fields  vehicle_type_id, pickup_location, dropoff_location, ride_time, device_token are required.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        user_device, _ = Device.objects.get_or_create(
            user=request.user, defaults={"device_token": device_token}
        )

        # Create the new ride
        new_ride = Ride.objects.create(
            user=request.user,
            user_device=user_device,
            vehicle_type_id=vehicle_type_id,
            pickup_location=fromstr(
                f"POINT({pickup_location['longitude']} {pickup_location['latitude']})",
                srid=4326,
            ),
            dropoff_location=fromstr(
                f"POINT({dropoff_location['longitude']} {dropoff_location['latitude']})",
                srid=4326,
            ),
            pickup_name=pickup_name,
            dropoff_name=dropoff_name,
            ride_time=timezone.datetime.strptime(ride_time, "%Y-%m-%dT%H:%M:%S%z"),
            status="pending",
        )

        setup_async_tasks(process_new_ride, new_ride)

        return Response(
            {
                "status": 1,
                "message": "Ride confirmed successfully.",
                "ride_id": new_ride.id,  # type: ignore
            },
            status=status.HTTP_200_OK,
        )


class DriverRideDetailView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request, ride_id):
        try:
            ride = Ride.objects.get(id=ride_id)
        except Ride.DoesNotExist:
            return Response(
                {"status": 0, "message": "Ride not found."},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {
                "status": 1,
                "message": "Ride details retrieved successfully.",
                "ride_details": {
                    "user_name": f"{ride.user.first_name} {ride.user.last_name}",
                    "pickup_name": ride.pickup_name,
                    "dropoff_name": ride.dropoff_name,
                    "pickup_coordinates": {
                        "latitude": ride.pickup_location.y,
                        "longitude": ride.pickup_location.x,
                    },
                    "dropoff_coordinates": {
                        "latitude": ride.dropoff_location.y,
                        "longitude": ride.dropoff_location.x,
                    },
                    "distance": float(ride.distance) if ride.distance else None,
                    "estimated_fare": (
                        float(ride.estimated_fare) if ride.estimated_fare else None
                    ),
                },
            },
            status=status.HTTP_200_OK,
        )


class UpdateDriverLocationView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

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

        if latitude is None or longitude is None:
            return Response(
                {"status": "error", "message": "Latitude and longitude are required."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            # Update the driver's location
            driver_location, created = DriverLocation.objects.update_or_create(
                driver=request.user,
                defaults={
                    "last_known_location": Point(float(longitude), float(latitude))
                },
            )
            return Response(
                {"status": "success", "message": "Location updated successfully."},
                status=status.HTTP_200_OK,
            )
        except ValueError:
            return Response(
                {"status": "error", "message": "Invalid latitude or longitude."},
                status=status.HTTP_400_BAD_REQUEST,
            )


class AcceptRideView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request, ride_id):
        driver = request.user

        if not driver.is_driver:
            return Response(
                {"status": 0, "message": "Only drivers can accept rides."},
                status=status.HTTP_403_FORBIDDEN,
            )

        try:
            ride = Ride.objects.get(id=ride_id)
            vehicle_assignment = VehicleAssignment.objects.filter(
                driver=driver, active=True
            ).first()
            if vehicle_assignment:
                ride.status = "accepted"
                ride.driver = driver
                ride.vehicle = vehicle_assignment.vehicle
                ride.save()
                vehicle_assignment.on_ride = True
                vehicle_assignment.save()
                DriverResponseLog.objects.create(
                    ride=ride,
                    driver=driver,
                    response="accepted",
                )
                # Send notification to the user with the ride ID
                notify_user_ride_accepted(ride.user, ride)
            else:
                return Response(
                    {
                        "status": 0,
                        "message": "No active vehicle assignment found for driver.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

        except Ride.DoesNotExist:
            return Response(
                {
                    "status": 0,
                    "message": "Ride request not found or already processed.",
                },
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {"status": 1, "message": "Ride accepted successfully."},
            status=status.HTTP_200_OK,
        )


class RejectRideView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request, ride_id):
        driver = request.user
        reason = request.data.get("reason")

        if not driver.is_driver:
            return Response(
                {"status": 0, "message": "Only drivers can reject rides."},
                status=status.HTTP_403_FORBIDDEN,
            )

        try:
            ride = Ride.objects.get(id=ride_id)
            ride.status = "rejected"
            ride.save()
            DriverResponseLog.objects.create(
                ride=ride, driver=driver, response="rejected", reason=reason
            )

        except Ride.DoesNotExist:
            return Response(
                {
                    "status": 0,
                    "message": "Ride request not found or already processed.",
                },
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {"status": 1, "message": "Ride rejected successfully."},
            status=status.HTTP_200_OK,
        )


class DriverLocationView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request, ride_id):
        user = request.user

        try:
            ride = Ride.objects.get(id=ride_id, user=user, status__in=["accepted"])
            driver_location = DriverLocation.objects.get(driver=ride.driver)
            return Response(
                {
                    "status": 1,
                    "message": "Driver location retrieved successfully.",
                    "driver_location": {
                        "latitude": driver_location.last_known_location.y,
                        "longitude": driver_location.last_known_location.x,
                    },
                },
                status=status.HTTP_200_OK,
            )
        except Ride.DoesNotExist:
            return Response(
                {"status": 0, "message": "Ride not found or not active."},
                status=status.HTTP_404_NOT_FOUND,
            )
        except DriverLocation.DoesNotExist:
            return Response(
                {"status": 0, "message": "Driver location not available."},
                status=status.HTTP_404_NOT_FOUND,
            )


class StartRideView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request, ride_id):
        otp = request.data.get("otp")
        driver = request.user

        if not otp:
            return Response(
                {"status": 0, "message": "OTP is required to start the ride."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            ride = Ride.objects.get(id=ride_id, driver=driver, status="accepted")
            if str(ride.otp) == str(otp):
                ride.start_time = timezone.now()
                ride.status = "started"
                ride.save()
                notify_user_ride_started(ride.user, ride)
                return Response(
                    {"status": 1, "message": "Ride started successfully."},
                    status=status.HTTP_200_OK,
                )
            else:
                return Response(
                    {"status": 0, "message": "Invalid OTP."},
                    status=status.HTTP_400_BAD_REQUEST,
                )
        except Ride.DoesNotExist:
            return Response(
                {"status": 0, "message": "Ride not found or already in progress."},
                status=status.HTTP_404_NOT_FOUND,
            )


class EndRideView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request, ride_id):
        driver = request.user

        try:
            ride = Ride.objects.get(id=ride_id, driver=driver, status="in_progress")
            ride.status = "completed"
            ride.end_time = timezone.now()
            ride.save()
            notify_user_ride_finished(ride.user, ride)
            vehicle_assignment = VehicleAssignment.objects.get(driver=driver)
            vehicle_assignment.on_ride = False
            vehicle_assignment.save()
            return Response(
                {"status": 1, "message": "Ride completed successfully."},
                status=status.HTTP_200_OK,
            )
        except Ride.DoesNotExist:
            return Response(
                {"status": 0, "message": "Ride not found or not in progress."},
                status=status.HTTP_404_NOT_FOUND,
            )


class RideDetailView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request, ride_id):
        user = request.user

        try:
            ride = Ride.objects.get(id=ride_id, user=user)
            return Response(
                {
                    "status": 1,
                    "message": "Ride details retrieved successfully.",
                    "ride_details": {
                        "vehicle_type": ride.vehicle_type.vehicle_type,  # type: ignore
                        "vehicle": ride.vehicle.plate_number,  # type: ignore
                        "driver_name": ride.driver.first_name,  # type: ignore
                        "otp": ride.otp,
                        "status": ride.status,
                    },
                },
                status=status.HTTP_200_OK,
            )
        except Ride.DoesNotExist:
            return Response(
                {"status": 0, "message": "Ride not found."},
                status=status.HTTP_404_NOT_FOUND,
            )


class DriverApproachingView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request, ride_id):
        driver = request.user

        if not driver.is_driver:
            return Response(
                {
                    "status": 0,
                    "message": "Only drivers can send approaching notifications.",
                },
                status=status.HTTP_403_FORBIDDEN,
            )

        try:
            ride = Ride.objects.get(id=ride_id, driver=driver, status="accepted")
            notify_user_driver_reaching(ride.user, ride)
        except Ride.DoesNotExist:
            return Response(
                {"status": 0, "message": "Ride not found or not in an accepted state."},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {
                "status": 1,
                "message": "Driver approaching notification sent successfully.",
            },
            status=status.HTTP_200_OK,
        )


class DriverArrivedView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request, ride_id):
        driver = request.user

        if not driver.is_driver:
            return Response(
                {
                    "status": 0,
                    "message": "Only drivers can send arrived notifications.",
                },
                status=status.HTTP_403_FORBIDDEN,
            )

        try:
            ride = Ride.objects.get(id=ride_id, driver=driver, status="accepted")
            notify_user_driver_arrived(ride.user, ride)
        except Ride.DoesNotExist:
            return Response(
                {"status": 0, "message": "Ride not found or not in an accepted state."},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {"status": 1, "message": "Driver arrived notification sent successfully."},
            status=status.HTTP_200_OK,
        )


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

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAdminUser]

    def post(self, request):
        try:
            filter_params = request.data  # Get all parameters from the request body
            rides = Ride.objects.filter(**filter_params)
            serializer = RideSerializer(rides, many=True)
            return Response(
                {
                    "status": 1,
                    "message": "Rides 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 CreateSharedRideView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        vehicle_type_id = request.data.get("vehicle_type_id")
        pickup_name = request.data.get("pickup_name")
        dropoff_name = request.data.get("dropoff_name")
        pickup_location = request.data.get("pickup_location")
        dropoff_location = request.data.get("dropoff_location")
        ride_time = request.data.get("ride_time")
        device_token = request.data.get("device_token")
        seats_required = request.data.get("seats_required")

        # Validate required fields
        if not all(
            [
                vehicle_type_id,
                pickup_location,
                dropoff_location,
                ride_time,
                device_token,
                seats_required,
            ]
        ):
            return Response(
                {
                    "status": 0,
                    "message": "All fields are required: vehicle_type_id, pickup_location, dropoff_location, ride_time, device_token, seats_required.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        if int(seats_required) <= 0:
            return Response(
                {
                    "status": 0,
                    "message": "The number of seats required must be greater than zero.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Get the vehicle type and validate it
        try:
            vehicle_type = VehicleType.objects.get(id=vehicle_type_id)
        except VehicleType.DoesNotExist:
            return Response(
                {"status": 0, "message": "Invalid vehicle type ID."},
                status=status.HTTP_404_NOT_FOUND,
            )

        # Get or create the device for the user
        user_device, _ = Device.objects.get_or_create(
            user=request.user, defaults={"device_token": device_token}
        )

        # Create the shared ride
        shared_ride = SharedRide.objects.create(
            primary_user=request.user,
            vehicle_type=vehicle_type,
            primary_pickup_location=fromstr(
                f"POINT({pickup_location['longitude']} {pickup_location['latitude']})",
                srid=4326,
            ),
            primary_dropoff_location=fromstr(
                f"POINT({dropoff_location['longitude']} {dropoff_location['latitude']})",
                srid=4326,
            ),
            ride_time=timezone.datetime.strptime(ride_time, "%Y-%m-%dT%H:%M:%S%z"),
            seats_total=vehicle_type.seating_capacity,
            seats_occupied=int(seats_required),
            seats_required=int(seats_required),
            status="pending",
            user_device=user_device,
            pickup_name=pickup_name,
            dropoff_name=dropoff_name,
        )

        return Response(
            {
                "status": 1,
                "message": "Shared ride created successfully.",
                "shared_ride_id": shared_ride.id,  # type: ignore
            },
            status=status.HTTP_201_CREATED,
        )


class ListAvailableSharedRidesView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        pickup_location = request.data.get("pickup_location")
        dropoff_location = request.data.get("dropoff_location")
        ride_time = request.data.get("ride_time")

        # Validate required fields
        if not all([pickup_location, dropoff_location, ride_time]):
            return Response(
                {
                    "status": 0,
                    "message": "All fields are required: pickup_location, dropoff_location, ride_time.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Convert input locations to Point objects
        user_pickup_point = Point(
            float(pickup_location["longitude"]),
            float(pickup_location["latitude"]),
            srid=4326,
        )
        user_dropoff_point = Point(
            float(dropoff_location["longitude"]),
            float(dropoff_location["latitude"]),
            srid=4326,
        )

        # Parse the ride time and set the time window
        user_ride_time = timezone.datetime.strptime(ride_time, "%Y-%m-%dT%H:%M:%S%z")
        time_window_start = user_ride_time - timezone.timedelta(minutes=30)
        time_window_end = user_ride_time + timezone.timedelta(minutes=30)

        # Filter for shared rides within the time window and distance criteria
        available_rides = SharedRide.objects.filter(
            ride_time__range=(time_window_start, time_window_end),
            primary_pickup_location__distance_lte=(user_pickup_point, D(km=0.5)),
            primary_dropoff_location__distance_lte=(user_dropoff_point, D(km=0.5)),
            status="pending",
        )

        # Prepare the list of rides to return
        rides_list = []
        for ride in available_rides:
            rides_list.append(
                {
                    "shared_ride_id": ride.id,  # type: ignore
                    "vehicle_type": ride.vehicle_type.vehicle_type,  # type: ignore
                    "vehicle_type_id": ride.vehicle_type.id,  # type: ignore
                    "seats_occupied": ride.seats_occupied,
                    "seats_remaining": ride.seats_total - ride.seats_occupied,
                    "pickup_name": ride.pickup_name,
                    "dropoff_name": ride.dropoff_name,
                    "ride_time": ride.ride_time.isoformat(),
                }
            )

        return Response(
            {
                "status": 1,
                "message": "Available shared rides listed successfully.",
                "rides": rides_list,
            },
            status=status.HTTP_200_OK,
        )


class JoinSharedRideView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        shared_ride_id = request.data.get("shared_ride_id")
        device_token = request.data.get("device_token")
        seats_required = request.data.get("seats_required")

        # Validate required fields
        if not all([shared_ride_id, device_token, seats_required]):
            return Response(
                {
                    "status": 0,
                    "message": "All fields are required: shared_ride_id, device_token, seats_required.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Validate seats_required
        if int(seats_required) <= 0:
            return Response(
                {
                    "status": 0,
                    "message": "The number of seats required must be greater than zero.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Get the shared ride
        try:
            shared_ride = SharedRide.objects.get(id=shared_ride_id, status="pending")
        except SharedRide.DoesNotExist:
            return Response(
                {"status": 0, "message": "Shared ride not found or not available."},
                status=status.HTTP_404_NOT_FOUND,
            )

        # Check if there are enough seats available
        if shared_ride.seats_occupied + int(seats_required) > shared_ride.seats_total:
            return Response(
                {"status": 0, "message": "Not enough seats available."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Get or create the device for the user
        user_device, _ = Device.objects.get_or_create(
            user=request.user, defaults={"device_token": device_token}
        )

        # Create a new participant for the shared ride
        SharedRideParticipant.objects.create(
            shared_ride=shared_ride,
            participant_user=request.user,
            pickup_location=shared_ride.primary_pickup_location,
            dropoff_location=shared_ride.primary_dropoff_location,
            seats_required=int(seats_required),
            device_token=user_device,
        )

        # Update the seats occupied
        shared_ride.seats_occupied += int(seats_required)
        shared_ride.save()

        return Response(
            {
                "status": 1,
                "message": "Successfully joined the shared ride.",
                "shared_ride_id": shared_ride.id,  # type: ignore
            },
            status=status.HTTP_200_OK,
        )


class SharedRideListView(generics.ListAPIView):
    """
    View to list shared rides with optional filtering.
    """

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAdminUser]

    def get_queryset(self):
        return SharedRide.objects.all()

    def perform_queryset(self, queryset):
        combined_data = []
        for ride in queryset:
            ride_data = {
                "ride": ride,
                "participants": [
                    {
                        "participant": participant,
                        "device_token": participant.device_token,
                        "pickup_location": participant.pickup_location,
                        "dropoff_location": participant.dropoff_location,
                        "pickup_name": participant.pickup_name,
                        "dropoff_name": participant.dropoff_name,
                        "seats_required": participant.seats_required,
                        "joined_at": participant.joined_at,
                    }
                    for participant in ride.participants.all()
                ],
            }
            combined_data.append(ride_data)
        return combined_data

    def get_serializer_class(self):
        return SharedRideSerializer


class RouteCreateView(APIView):
    """
    View to add a new route and its sequences.
    """

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAdminUser]

    def post(self, request):
        try:
            # Extract data from request
            pickup_point_data = request.data.get("pickup_point")
            dropoff_point_data = request.data.get("dropoff_point")
            intermediate_points_data = request.data.get("intermediate_points")

            # Create pickup and dropoff points if they don't exist
            pickup_point, created = RoutePoint.objects.update_or_create(
                name=pickup_point_data["name"],
                defaults={
                    "latitude": pickup_point_data["latitude"],
                    "longitude": pickup_point_data["longitude"],
                },
            )
            dropoff_point, created = RoutePoint.objects.update_or_create(
                name=dropoff_point_data["name"],
                defaults={
                    "latitude": dropoff_point_data["latitude"],
                    "longitude": dropoff_point_data["longitude"],
                },
            )

            # Create intermediate points if they don't exist and store them with order
            intermediate_points = []
            for point_data in intermediate_points_data:
                order = point_data.get("order")
                point, created = RoutePoint.objects.update_or_create(
                    name=point_data["name"],
                    defaults={
                        "latitude": point_data["latitude"],
                        "longitude": point_data["longitude"],
                    },
                )
                intermediate_points.append({"point": point, "order": order})

            # Create the route with the points
            route = Route.objects.create(
                name=request.data.get("name"),
                description=request.data.get("description"),
                pickup_point=pickup_point,
                dropoff_point=dropoff_point,
            )

            # Create sequences for the route based on the order of intermediate points
            for sequence_data in sorted(intermediate_points, key=lambda x: x["order"]):
                Sequence.objects.create(
                    route=route,
                    point=sequence_data["point"],
                    order=sequence_data["order"],
                )

            # Serialize the route and return success response
            serializer = RouteSerializer(route)
            return Response(serializer.data, status=status.HTTP_201_CREATED)

        except Exception as e:
            return Response(
                {"status": 0, "message": str(e), "t": traceback.format_exc()},
                status=status.HTTP_400_BAD_REQUEST,
            )


class RouteUpdateView(APIView):
    """
    View to update an existing route and its sequences.
    """

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAdminUser]

    def put(self, request, route_id):
        try:
            # Get the existing route object
            route = Route.objects.get(id=route_id)

            # Extract data from request
            pickup_point_data = request.data.get("pickup_point")
            dropoff_point_data = request.data.get("dropoff_point")
            intermediate_points_data = request.data.get("intermediate_points")

            # Update pickup point if provided
            if pickup_point_data:
                pickup_point, created = RoutePoint.objects.update_or_create(
                    name=pickup_point_data["name"],
                    defaults={
                        "latitude": pickup_point_data["latitude"],
                        "longitude": pickup_point_data["longitude"],
                    },
                )
                route.pickup_point = pickup_point

            # Update dropoff point if provided
            if dropoff_point_data:
                dropoff_point, created = RoutePoint.objects.update_or_create(
                    name=dropoff_point_data["name"],
                    defaults={
                        "latitude": dropoff_point_data["latitude"],
                        "longitude": dropoff_point_data["longitude"],
                    },
                )
                route.dropoff_point = dropoff_point

            # Update intermediate points if provided
            if intermediate_points_data:
                intermediate_points = []
                for point_data in intermediate_points_data:
                    order = point_data.get("order")
                    point, created = RoutePoint.objects.update_or_create(
                        name=point_data["name"],
                        defaults={
                            "latitude": point_data["latitude"],
                            "longitude": point_data["longitude"],
                        },
                    )
                    intermediate_points.append({"point": point, "order": order})

                # Delete existing sequences for the route
                route.sequences.all().delete()  # type: ignore

                # Create new sequences for the route based on the updated order of intermediate points
                for sequence_data in sorted(
                    intermediate_points, key=lambda x: x["order"]
                ):
                    Sequence.objects.create(
                        route=route,
                        point=sequence_data["point"],
                        order=sequence_data["order"],
                    )

            # Update other fields of the route if provided
            route.name = request.data.get("name", route.name)
            route.description = request.data.get("description", route.description)
            route.save()

            # Serialize the updated route and return success response
            serializer = RouteSerializer(route)
            return Response(serializer.data, status=status.HTTP_200_OK)

        except Route.DoesNotExist:
            return Response(
                {"status": 0, "message": "Route not found"},
                status=status.HTTP_404_NOT_FOUND,
            )

        except Exception as e:
            return Response(
                {"status": 0, "message": str(e), "t": traceback.format_exc()},
                status=status.HTTP_400_BAD_REQUEST,
            )


class RouteListView(APIView):
    """
    View to list all routes.
    """

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAdminUser]

    def get(self, request):
        try:
            # Get all routes
            routes = Route.objects.all()

            # Serialize the routes
            serializer = RouteSerializer(routes, many=True)

            # Return the serialized routes
            return Response(serializer.data, status=status.HTTP_200_OK)

        except Exception as e:
            return Response(
                {"status": 0, "message": str(e)}, status=status.HTTP_400_BAD_REQUEST
            )


class RouteDeleteView(APIView):
    """
    View to delete a route.
    """

    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAdminUser]

    def delete(self, request, route_id):
        try:
            # Get the route object to delete
            route = Route.objects.get(id=route_id)

            # Delete the route
            route.delete()

            return Response(
                {"status": "Route deleted successfully"},
                status=status.HTTP_204_NO_CONTENT,
            )

        except Route.DoesNotExist:
            return Response(
                {"status": 0, "message": "Route not found"},
                status=status.HTTP_404_NOT_FOUND,
            )

        except Exception as e:
            return Response(
                {"status": 0, "message": str(e)}, status=status.HTTP_400_BAD_REQUEST
            )


# class ScheduledRideMasterCreateView(APIView):
#     authentication_classes = [JSONWebTokenAuthentication]
#     permission_classes = [IsAdminUser]

#     def post(self, request):
#         try:
#             # Extract data from request
#             name = request.data.get("name")
#             starting_time = request.data.get("starting_time")
#             ending_time = request.data.get("ending_time")
#             route_id = request.data.get("route")
#             vehicles_data = request.data.get("vehicles")
#             master_status = request.data.get("status")

#             if not all(
#                 [
#                     name,
#                     starting_time,
#                     ending_time,
#                     route_id,
#                     vehicles_data,
#                     master_status is not None,
#                 ]
#             ):
#                 return Response(
#                     {"status": 0, "message": "All fields are required."},
#                     status=status.HTTP_400_BAD_REQUEST,
#                 )

#             # Get route object
#             route = Route.objects.get(id=route_id)

#             with transaction.atomic():
#                 # Create the scheduled ride master
#                 scheduled_ride_master = ScheduledRideMaster.objects.create(
#                     name=name,
#                     starting_time=starting_time,
#                     ending_time=ending_time,
#                     route=route,
#                     status=master_status,
#                 )

#                 # Add vehicles to the scheduled ride master
#                 vehicle_ids = [vehicle_data.get("id") for vehicle_data in vehicles_data]
#                 vehicles = Vehicle.objects.filter(id__in=vehicle_ids)

#                 if vehicles.count() != len(vehicle_ids):
#                     raise ValueError("Some vehicles not found")

#                 scheduled_ride_master.vehicles.set(vehicles)

#             # Serialize the scheduled ride master and return success response
#             serializer = ScheduledRideMasterSerializer(scheduled_ride_master)
#             return Response(serializer.data, status=status.HTTP_201_CREATED)

#         except Route.DoesNotExist:
#             return Response(
#                 {"status": 0, "message": "Route not found."},
#                 status=status.HTTP_404_NOT_FOUND,
#             )
#         except Vehicle.DoesNotExist:
#             return Response(
#                 {"status": 0, "message": "One or more vehicles not found."},
#                 status=status.HTTP_404_NOT_FOUND,
#             )
#         except Exception as e:
#             return Response(
#                 {"status": 0, "message": str(e), "traceback": traceback.format_exc()},
#                 status=status.HTTP_400_BAD_REQUEST,
#             )


# class ScheduledRideMasterUpdateView(APIView):
#     authentication_classes = [JSONWebTokenAuthentication]
#     permission_classes = [IsAdminUser]

#     def put(self, request, id):
#         try:
#             # Extract data from request
#             name = request.data.get("name")
#             starting_time = request.data.get("starting_time")
#             ending_time = request.data.get("ending_time")
#             route_id = request.data.get("route")
#             vehicles_data = request.data.get("vehicles")
#             master_status = request.data.get("status")

#             # Check for the presence of all necessary fields
#             if not all(
#                 [
#                     name,
#                     starting_time,
#                     ending_time,
#                     route_id,
#                     vehicles_data,
#                     master_status is not None,
#                 ]
#             ):
#                 return Response(
#                     {"status": 0, "message": "All fields are required."},
#                     status=status.HTTP_400_BAD_REQUEST,
#                 )

#             # Validate route existence
#             try:
#                 route = Route.objects.get(id=route_id)
#             except Route.DoesNotExist:
#                 return Response(
#                     {"status": 0, "message": "Route not found."},
#                     status=status.HTTP_404_NOT_FOUND,
#                 )

#             # Validate vehicle existence
#             vehicle_ids = [vehicle_data.get("id") for vehicle_data in vehicles_data]
#             vehicles = Vehicle.objects.filter(id__in=vehicle_ids)
#             if vehicles.count() != len(vehicle_ids):
#                 return Response(
#                     {"status": 0, "message": "One or more vehicles not found."},
#                     status=status.HTTP_404_NOT_FOUND,
#                 )

#             # Validate scheduled ride master existence
#             try:
#                 scheduled_ride_master = ScheduledRideMaster.objects.get(id=id)
#             except ScheduledRideMaster.DoesNotExist:
#                 return Response(
#                     {"status": 0, "message": "Scheduled Ride Master not found."},
#                     status=status.HTTP_404_NOT_FOUND,
#                 )

#             # Update the scheduled ride master
#             scheduled_ride_master.name = name
#             scheduled_ride_master.starting_time = starting_time
#             scheduled_ride_master.ending_time = ending_time
#             scheduled_ride_master.route = route
#             scheduled_ride_master.status = master_status
#             scheduled_ride_master.save()

#             # Update vehicles for the scheduled ride master
#             scheduled_ride_master.vehicles.set(vehicles)

#             # Serialize the updated scheduled ride master and return success response
#             serializer = ScheduledRideMasterSerializer(scheduled_ride_master)
#             return Response(serializer.data, status=status.HTTP_200_OK)

#         except Exception as e:
#             return Response(
#                 {"status": 0, "message": str(e)}, status=status.HTTP_400_BAD_REQUEST
#             )


# class ScheduledRideMasterDeleteView(APIView):
#     authentication_classes = [JSONWebTokenAuthentication]
#     permission_classes = [IsAdminUser]

#     def delete(self, request, id):
#         try:
#             scheduled_ride_master = ScheduledRideMaster.objects.get(id=id)
#             scheduled_ride_master.delete()
#             return Response(
#                 {"status": 1, "message": "Scheduled Ride Master deleted successfully."},
#                 status=status.HTTP_204_NO_CONTENT,
#             )
#         except ScheduledRideMaster.DoesNotExist:
#             return Response(
#                 {"status": 0, "message": "Scheduled Ride Master not found."},
#                 status=status.HTTP_404_NOT_FOUND,
#             )
#         except Exception as e:
#             return Response(
#                 {"status": 0, "message": str(e)}, status=status.HTTP_400_BAD_REQUEST
#             )


# class ScheduledRideMasterListView(APIView):
#     authentication_classes = [JSONWebTokenAuthentication]
#     permission_classes = [IsAdminUser]

#     def get(self, request):
#         try:
#             scheduled_ride_masters = ScheduledRideMaster.objects.all()
#             serializer = ScheduledRideMasterSerializer(
#                 scheduled_ride_masters, many=True
#             )
#             return Response(serializer.data, status=status.HTTP_200_OK)
#         except Exception as e:
#             return Response(
#                 {"status": 0, "message": str(e)}, status=status.HTTP_400_BAD_REQUEST
#             )


class ScheduledRideMasterCreateView(APIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAdminUser]

    def post(self, request):
        try:
            name = request.data.get("name")
            starting_time = request.data.get("starting_time")
            ending_time = request.data.get("ending_time")
            route_id = request.data.get("route")
            vehicle_id = request.data.get("vehicle")
            master_status = request.data.get("status")

            if not all(
                [name, starting_time, ending_time, route_id, vehicle_id, master_status]
            ):
                return Response(
                    {"status": 0, "message": "All fields are required."},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            route = Route.objects.get(id=route_id)
            vehicle = Vehicle.objects.get(id=vehicle_id)

            with transaction.atomic():
                scheduled_ride_master = ScheduledRideMaster.objects.create(
                    name=name,
                    starting_time=starting_time,
                    ending_time=ending_time,
                    route=route,
                    vehicle=vehicle,
                    status=master_status,
                )

            serializer = ScheduledRideMasterSerializer(scheduled_ride_master)
            return Response(serializer.data, status=status.HTTP_201_CREATED)

        except Route.DoesNotExist:
            return Response(
                {"status": 0, "message": "Route not found."},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Vehicle.DoesNotExist:
            return Response(
                {"status": 0, "message": "Vehicle not found."},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"status": 0, "message": str(e)}, status=status.HTTP_400_BAD_REQUEST
            )


class ScheduledRideMasterUpdateView(APIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAdminUser]

    def put(self, request, id):
        try:
            name = request.data.get("name")
            starting_time = request.data.get("starting_time")
            ending_time = request.data.get("ending_time")
            route_id = request.data.get("route")
            vehicle_id = request.data.get("vehicle")
            master_status = request.data.get("status")

            if not all(
                [name, starting_time, ending_time, route_id, vehicle_id, master_status]
            ):
                return Response(
                    {"status": 0, "message": "All fields are required."},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            route = Route.objects.get(id=route_id)
            vehicle = Vehicle.objects.get(id=vehicle_id)
            scheduled_ride_master = ScheduledRideMaster.objects.get(id=id)

            scheduled_ride_master.name = name
            scheduled_ride_master.starting_time = starting_time
            scheduled_ride_master.ending_time = ending_time
            scheduled_ride_master.route = route
            scheduled_ride_master.vehicle = vehicle
            scheduled_ride_master.status = master_status
            scheduled_ride_master.save()

            serializer = ScheduledRideMasterSerializer(scheduled_ride_master)
            return Response(serializer.data, status=status.HTTP_200_OK)

        except Route.DoesNotExist:
            return Response(
                {"status": 0, "message": "Route not found."},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Vehicle.DoesNotExist:
            return Response(
                {"status": 0, "message": "Vehicle not found."},
                status=status.HTTP_404_NOT_FOUND,
            )
        except ScheduledRideMaster.DoesNotExist:
            return Response(
                {"status": 0, "message": "Scheduled Ride Master not found."},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"status": 0, "message": str(e)}, status=status.HTTP_400_BAD_REQUEST
            )


class ScheduledRideMasterDeleteView(APIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAdminUser]

    def delete(self, request, id):
        try:
            scheduled_ride_master = ScheduledRideMaster.objects.get(id=id)
            scheduled_ride_master.delete()
            return Response(
                {"status": 1, "message": "Scheduled Ride Master deleted successfully."},
                status=status.HTTP_204_NO_CONTENT,
            )
        except ScheduledRideMaster.DoesNotExist:
            return Response(
                {"status": 0, "message": "Scheduled Ride Master not found."},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Exception as e:
            return Response(
                {"status": 0, "message": str(e)}, status=status.HTTP_400_BAD_REQUEST
            )


class ScheduledRideMasterListView(APIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAdminUser]

    def get(self, request):
        try:
            scheduled_rides = ScheduledRideMaster.objects.all()
            serializer = ScheduledRideMasterSerializer(scheduled_rides, many=True)
            return Response(serializer.data, status=status.HTTP_200_OK)
        except Exception as e:
            return Response(
                {"status": 0, "message": str(e)}, status=status.HTTP_400_BAD_REQUEST
            )


# class ScheduledRideMobileListView(APIView):
#     def get(self, request):
#         # Extract user's current location from request
#         user_latitude = float(request.data.get("latitude"))
#         user_longitude = float(request.data.get("longitude"))
#         user_location = (user_latitude, user_longitude)

#         # Get the current time
#         current_time = timezone.now().time()

#         # Filter rides based on the current time
#         scheduled_rides = ScheduledRideMaster.objects.filter(
#             status="active"  # Only rides that haven't ended
#         )

#         # Filter and order based on proximity to user's location
#         filtered_rides = []
# for ride in scheduled_rides:
#     route = ride.route
#     points = [route.pickup_point] + list(route.intermediate_points.all())  # type: ignore
#     for point in points:
#         point_location = (point.latitude, point.longitude)
#         distance = geodesic(user_location, point_location).km
#         if distance <= 20:  # Within 20 km range
#             if current_time <= ride.ending_time.time():
#                 ride.distance_to_start = geodesic(user_location, (route.pickup_point.latitude, route.pickup_point.longitude)).km  # type: ignore
#                 filtered_rides.append(ride)
#             break

# # Sort rides based on distance to starting point
# filtered_rides.sort(key=lambda ride: ride.distance_to_start)

#         # Serialize the filtered and sorted rides
#         serializer = ScheduledRideMobileSerializer(filtered_rides, many=True)
#         return Response(
#                 {"status": 1, "message": "Scheduled Rides Fetched successfully.","Rides":serializer.data},
#                 status=status.HTTP_200_OK,
#             )


# class JoinScheduledRideView(APIView):

#     authentication_classes = [TokenAuthentication]
#     permission_classes = [IsAuthenticated]

#     def post(self, request):
#         user = request.user
#         scheduled_ride_id = request.data.get('scheduled_ride_id')
#         join_point_data = request.data.get('join_point')
#         end_point_data = request.data.get('end_point')
#         seats_required = request.data.get('seats_required')
#         vehicle_id = request.data.get('vehicle_id')
#         device_token = request.data.get("device_token")

#         try:
#             scheduled_ride = ScheduledRideMaster.objects.get(id=scheduled_ride_id)
#         except ScheduledRideMaster.DoesNotExist:
#             return Response(
#                 {"status": 0, "message": "Scheduled ride not found or not available."},
#                 status=status.HTTP_404_NOT_FOUND,
#             )

#         try:
#             vehicle = Vehicle.objects.get(id=vehicle_id)
#         except Vehicle.DoesNotExist:
#             return Response({'error': 'Vehicle not found.'}, status=status.HTTP_404_NOT_FOUND)

#         join_point = Point(float(join_point_data['longitude']), float(join_point_data['latitude']))
#         end_point = Point(float(end_point_data['longitude']), float(end_point_data['latitude']))

#         if seats_required > vehicle.vehicle_type.seating_capacity:
#             return Response(
#                 {"status": 0, "message": "Not enough seats available."},
#                 status=status.HTTP_400_BAD_REQUEST,
#             )

#         user_device, _ = Device.objects.get_or_create(
#             user=request.user, defaults={"device_token": device_token}
#         )

#         scheduled_ride_instance = ScheduledRideParticipant.objects.create(
#             scheduled_ride=scheduled_ride,
#             user=user,
#             join_point=join_point,
#             end_point=end_point,
#             selected_vehicle=vehicle,
#             seats_required=seats_required,
#         )

#         serializer = ScheduledRideMobileSerializer(scheduled_ride)
#         return Response(
#                 {"status": 1, "message": "Joined ride successfully"}, status=status.HTTP_201_CREATED)


class ScheduledRideMobileListView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            user_latitude = float(request.data.get("latitude"))
            user_longitude = float(request.data.get("longitude"))
        except (TypeError, ValueError):
            return Response(
                {"status": 0, "message": "Invalid latitude or longitude provided."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        user_location = (user_latitude, user_longitude)
        current_time = timezone.now().time()

        try:
            scheduled_rides = ScheduledRideMaster.objects.filter(status="active")

            if not scheduled_rides.exists():
                return Response(
                    {"status": 1, "message": "No rides available."},
                    status=status.HTTP_200_OK,
                )

            filtered_rides = []
            for ride in scheduled_rides:
                try:
                    scheduled_ride_day = ScheduledRideDay.objects.get(
                        scheduled_ride=ride, date=timezone.now().date()
                    )
                    if scheduled_ride_day.status == "pending":
                        available_seats = (
                            scheduled_ride_day.total_seats - scheduled_ride_day.booked_seats
                        )
                        if available_seats > 0:
                            ride_entry = {"ride": ride, "available_seats": available_seats}
                            filtered_rides.append(ride_entry)
                except ScheduledRideDay.DoesNotExist:
                    ride_entry = {
                        "ride": ride,
                        "available_seats": ride.vehicle.vehicle_type.seating_capacity,  # type: ignore
                    }
                    filtered_rides.append(ride_entry)

            if not filtered_rides:
                return Response(
                    {"status": 1, "message": "No rides available."},
                    status=status.HTTP_200_OK,
                )

            final_rides = []
            for entry in filtered_rides:
                ride = entry["ride"]
                route = ride.route
                points = [route.pickup_point] + list(route.intermediate_points.all())
                for point in points:
                    point_location = (point.latitude, point.longitude)
                    distance = geodesic(user_location, point_location).km
                    if distance <= 20:
                        ride.distance_to_start = geodesic(
                            user_location,
                            (route.pickup_point.latitude, route.pickup_point.longitude),
                        ).km
                        final_rides.append(entry)
                        break

            final_rides.sort(key=lambda entry: entry["ride"].distance_to_start)

            response_data = []
            for entry in final_rides:
                ride_serializer = ScheduledRideMobileSerializer(entry["ride"])
                ride_data = ride_serializer.data
                ride_data["available_seats"] = entry["available_seats"]  # type: ignore
                response_data.append(ride_data)

            return Response(
                {
                    "status": 1,
                    "message": "Scheduled Rides Fetched successfully.",
                    "Rides": response_data,
                },
                status=status.HTTP_200_OK,
            )
        except Exception as e:
            return Response(
                {"status": 0, "message": "Unexpected error", "exception": str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )

class ScheduledFareEstimationView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        vehicle_type_id = request.data.get("vehicle_type_id")
        from_address = request.data.get("from_address")
        to_address = request.data.get("to_address")
        seats_required = request.data.get("seats_required", 1)
        ride_time = request.data.get("ride_time")

        if not (vehicle_type_id and from_address and to_address and ride_time):
            return Response(
                {
                    "status": 0,
                    "message": "Vehicle type, address details, ride time, and seats required are mandatory.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            from_latitude = from_address["latitude"]
            from_longitude = from_address["longitude"]
            to_latitude = to_address["latitude"]
            to_longitude = to_address["longitude"]
        except (TypeError, KeyError):
            return Response(
                {
                    "status": 0,
                    "message": "Invalid address format. Latitude and longitude are required for both from and to addresses.",
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            distance = calculate_distance(from_latitude, from_longitude, to_latitude, to_longitude)
        except ValidationError as e:
            return Response(
                {"status": 0, "message": str(e)},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            vehicle_type = VehicleType.objects.get(id=vehicle_type_id)
        except VehicleType.DoesNotExist:
            return Response(
                {"status": 0, "message": "Vehicle type not found."},
                status=status.HTTP_404_NOT_FOUND,
            )

        estimated_fare = distance * vehicle_type.fare_per_km_per_seat * seats_required  # type: ignore
        rounded_fare = estimated_fare.quantize(Decimal("0.01"), rounding=ROUND_UP)

        return Response(
            {
                "status": 1,
                "message": "Estimated fare calculated successfully.",
                "base_fare": vehicle_type.base_fare,
                "rate_per_km_per_seat": vehicle_type.fare_per_km_per_seat,
                "total_km": distance,
                "seats_required": seats_required,
                "estimated_fare": float(rounded_fare),
            },
            status=status.HTTP_200_OK,
        )

class JoinScheduledRideView(APIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request):
        ride_id = request.data.get("ride_id")
        seats_required = request.data.get("seats_required", 1)
        join_point = request.data.get("join_point")
        end_point = request.data.get("end_point")

        if not (ride_id and join_point and end_point):
            return Response(
                {"status": 0, "message": "Ride ID, join point, and end point are required."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            join_latitude = join_point["latitude"]
            join_longitude = join_point["longitude"]
            end_latitude = end_point["latitude"]
            end_longitude = end_point["longitude"]
        except (TypeError, KeyError):
            return Response(
                {"status": 0, "message": "Invalid point format. Latitude and longitude are required for both join and end points."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        user = request.user

        try:
            ride = ScheduledRideMaster.objects.get(id=ride_id, status="active")
        except ScheduledRideMaster.DoesNotExist:
            return Response(
                {"status": 0, "message": "Ride not found or inactive."},
                status=status.HTTP_404_NOT_FOUND,
            )

        today = timezone.now().date()
        try:
            scheduled_ride_day = ScheduledRideDay.objects.get(scheduled_ride=ride, date=today)
            if scheduled_ride_day.status != 'pending':
                return Response(
                    {"status": 0, "message": "Ride is not available for joining."},
                    status=status.HTTP_400_BAD_REQUEST,
                )
        except ScheduledRideDay.DoesNotExist:
            scheduled_ride_day = ScheduledRideDay.objects.create(
                scheduled_ride=ride,
                date=today,
                total_seats=ride.vehicle.vehicle_type.seating_capacity, # type: ignore
                booked_seats=0
            )

        available_seats = scheduled_ride_day.total_seats - scheduled_ride_day.booked_seats
        if seats_required > available_seats:
            return Response(
                {"status": 0, "message": "Not enough available seats."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        scheduled_ride_day.booked_seats += seats_required
        scheduled_ride_day.save()

        ScheduledRideParticipant.objects.create(
            scheduled_ride_day=scheduled_ride_day,
            user=user,
            join_point=Point(join_latitude, join_longitude),
            end_point=Point(end_latitude, end_longitude),
            seats_required=seats_required,
        )

        return Response(
            {"status": 1, "message": "Successfully joined the ride."},
            status=status.HTTP_200_OK,
        )
