from api.flight_plan_algorithm import *
from gardens.models import *
import time, datetime
import json

monthsLV = ["Janvāris", "Februāris", "Marts", "Aprīlis", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Decembris"]

def generate_mission(block_id, mission_name, mission_stage, only_sides, obstacle_avoidance, flying_altitude):

    plans = path_calculations(block_id, flying_altitude = flying_altitude, max_distance_to_tree_meters = 2, obstacle_avoidance = obstacle_avoidance, only_sides = only_sides)

    plans_list = []
    for plan in plans:
        plans_list.append(plan.tolist())
    
    plans = plans_list

    if len(plans)>=1:
        if block_id != None:
            mission = Missions.objects.create(
                    name = mission_name,
                    block_id = block_id,
                    stage_id = mission_stage,
                    )
            for x in range(0,len(plans)):
                geoJSON = {"type":"Feature",
                                    "geometry": 
                                    {"type": "Polygon",
                                    "coordinates":[plans[x]]}}
                FlightPlans.objects.create(
                            flight_plan = geoJSON,
                            sequence_num = x+1,
                            mission_id = mission.id,
                            block_id = block_id
                    )
    return mission

def calculate_flight_time_altitude(flight_plan, speed=2, ascent_speed=2, descent_speed=1):
        flight_plan_coordinates = flight_plan.flight_plan['geometry']['coordinates'][0]
        total_distance = 0
        total_time = 0
        total_altiude_distance = 0
        for i in range(len(flight_plan_coordinates) - 1):
            distance = math.sqrt((flight_plan_coordinates[i][0] - flight_plan_coordinates[i+1][0])**2 + (flight_plan_coordinates[i][1] - flight_plan_coordinates[i+1][1])**2)
            distance = distance * 111111
            distance_altitude = flight_plan_coordinates[i][2] - flight_plan_coordinates[i+1][2]
            total_distance += distance
            total_altiude_distance += abs(distance_altitude)
            if distance_altitude > 0:
                time = distance_altitude / ascent_speed
            else:
                time = abs(distance_altitude) / descent_speed
            total_time += time
        total_time += total_distance / speed
        return total_time / 60


# Autonousmly generates flights for a block, while taking into account time of the day.
def autonomous_flight_time_planning(block_id, mission_name=None, mission_stage=1, flying_altitude = 2, only_sides = False, obstacle_avoidance = True):
    # generate a mission with flight plans using generate_mission() 
    currentTime = datetime.datetime.now()
    mission_number = 1
    if mission_name == None:
        name = f"{monthsLV[currentTime.month-1]} {currentTime.year}"
        check_name = name + "(" + str(mission_number) + ")"
        while check_name in Missions.objects.values_list("name", flat=True):
            mission_number += 1
            check_name = name + "(" + str(mission_number) + ")"
        name = name + "(" + str(mission_number) + ")"
        mission = generate_mission(block_id, name, mission_stage, only_sides, obstacle_avoidance, flying_altitude)
    else:
        mission = generate_mission(block_id, mission_name, mission_stage, only_sides, obstacle_avoidance, flying_altitude)
    # create a flight for each flight plan with a start time that is 30 minutes after the previous flight and is within the time frame of 8:00 - 16:00
    flight_plans = FlightPlans.objects.filter(mission_id = mission.id)

    start_time = datetime.datetime.now().replace(tzinfo=datetime.timezone.utc) + datetime.timedelta(days=1)

    missions = Missions.objects.filter(block_id = block_id)
    for mission_block in missions:
            flightsss = Flights.objects.filter(mission_id = mission_block.id)
            for flight in flightsss:
                if flight.end_date > start_time:
                    start_time = flight.end_date
    
    for flight_plan in flight_plans:
        start_time = start_time + datetime.timedelta(minutes=120)
        
        flights = Flights.objects.filter(plan_id = flight_plan.id)


        # check if the time is within 8:00 - 16:00, move to the next day if it is not
        if start_time.hour >= 8 and start_time.hour < 16:
            pass
        else:
            start_time = start_time + datetime.timedelta(days=1)
            start_time = start_time.replace(hour=8, minute=0, second=0)
        

        # create a flight if there are no flights for the flight plan
        if flights.count() == 0:
            flight = Flights.objects.create(
                status = 1,
                mission_id = mission.id,
                plan_id = flight_plan.id,
                start_date = start_time,
                end_date = start_time + datetime.timedelta(minutes=calculate_flight_time_altitude(flight_plan))
            )
        # calculate the time the flight should end using the haversine formula and checking flight_plan.flight_plan
        flight_time = calculate_flight_time_altitude(flight_plan)
        print("time:", flight_time)
        # add the flight time to the start time
        start_time = start_time + datetime.timedelta(minutes=flight_time)

    return mission
# function that reschedules a flight if it is missed or cancelled by the user, the flight should be rescheduled to the next convient time accounting for the time of the day and flights that are already scheduled
def reschedule_flight(flight_id):
    resheduled_flight = Flights.objects.get(id = flight_id)
    mission = Missions.objects.get(id = resheduled_flight.mission_id)
    block = Blocks.objects.get(id = mission.block_id)
    missions = Missions.objects.filter(block_id = block.id, status = 0)
    next_time = datetime.datetime.now().replace(tzinfo=datetime.timezone.utc)
    for mission in missions:
        flights = Flights.objects.filter(mission_id = mission.id)
        for flight in flights:
            if flight.end_date > next_time:
                next_time = flight.end_date
    next_time = next_time + datetime.timedelta(minutes=120)
    if next_time.hour >= 8 and next_time.hour < 16:
        pass
    else:
        next_time = next_time + datetime.timedelta(days=1)
        next_time = next_time.replace(hour=8, minute=0, second=0)
    resheduled_flight.start_date = next_time
    resheduled_flight.end_date = next_time + datetime.timedelta(minutes=calculate_flight_time_altitude(FlightPlans.objects.get(id = resheduled_flight.plan_id)))
    resheduled_flight.save()
    return True

        


