from django.utils import timezone
from datetime import timedelta
from django.contrib.gis.db.models.functions import Distance
from accounts.models import DriverLocation
from .models import Ride
from .notifications import *
from asgiref.sync import sync_to_async
from decimal import Decimal
import requests
from rest_framework.exceptions import ValidationError
from decimal import Decimal, ROUND_UP
import asyncio


# Helper function to calculate distance using Google Maps API
def calculate_distance(from_latitude, from_longitude, to_latitude, to_longitude):
    api_key = "AIzaSyAEWPwKw_tv81JSa0x_glii-pz51JCX_PU"
    origins = f"{from_latitude},{from_longitude}"
    destinations = f"{to_latitude},{to_longitude}"
    endpoint = f"https://maps.googleapis.com/maps/api/distancematrix/json?origins={origins}&destinations={destinations}&key={api_key}"
    response = requests.get(endpoint)
    data = response.json()
    if data["status"] != "OK":
        raise ValidationError(data["error_message"])

    distance_in_km = Decimal(
        str(data["rows"][0]["elements"][0]["distance"]["value"] / 1000)
    )
    return distance_in_km


def setup_async_tasks(async_func,*args, **kwargs):
    try:
        loop = asyncio.get_running_loop()
    except RuntimeError:
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
    loop.create_task(async_func(*args, **kwargs))
    

@sync_to_async
def process_new_ride(ride):
    print("Step 1: Adjusting current time to account for potential delays")
    adjusted_current_time = timezone.now() - timedelta(minutes=3)

    print("Step 2: Checking if the ride time is within the next 15 minutes")
    if (
        adjusted_current_time
        <= ride.ride_time
        <= adjusted_current_time + timedelta(minutes=15)
    ):
        print("Step 3: Finding the nearest available driver for the vehicle type")
        nearest_driver = find_nearest_available_driver(
            ride.pickup_location, ride.vehicle_type
        )
        print("Step 4: Calculating distance and estimated fare")
        distance = calculate_distance(
            ride.pickup_location.y,  # Latitude
            ride.pickup_location.x,  # Longitude
            ride.dropoff_location.y,  # Latitude
            ride.dropoff_location.x,  # Longitude
        )
        estimated_fare = distance * ride.vehicle_type.per_km_charge
        rounded_fare = estimated_fare.quantize(Decimal("0.01"), rounding=ROUND_UP)
        ride.distance = distance
        ride.estimated_fare = rounded_fare
        ride.save()
        if nearest_driver:
            print("Step 6: Sending a notification to the driver with the ride details")
            notify_driver_new_ride(nearest_driver, ride)

            print("Step 7: Updating the ride status to 'processing'")
            ride.status = "processing"
            ride.save()
    else:
        print("The ride time is not within the next 15 minutes.")


def find_nearest_available_driver(pickup_location, vehicle_type):
    # Find drivers who are not currently on a ride and are nearest to the pickup location
    available_drivers = (
        DriverLocation.objects.filter(
            driver__assigned_vehicles__on_ride=False,
            driver__assigned_vehicles__vehicle__vehicle_type=vehicle_type,
            driver__assigned_vehicles__active=True,
        )
        .annotate(distance=Distance("last_known_location", pickup_location))
        .order_by("distance")
    )
    return available_drivers.first() if available_drivers else None
