from django.db import models
from usercontrol.models import *

import uuid
from django.core.validators import MinValueValidator, MaxValueValidator
import datetime


# For reference
# https://docs.djangoproject.com/en/4.0/ref/models/fields/

# /////////////////
# Meteostations ///
# /////////////////

class Meteoservice(models.Model):
    title = models.CharField(max_length=30)
    def __str__(self):
        return self.title

class Meteostations(models.Model):
    name = models.CharField(max_length=30)
    location = models.CharField(max_length=30)
    service_uri = models.CharField(max_length=255)
    last_forecast = models.JSONField(null = True)
    
    # foreign keys
    enterprise = models.ForeignKey(Enterprises, on_delete=models.CASCADE)
    meteoservice = models.ForeignKey(Meteoservice, on_delete=models.CASCADE)


# /////////////////
# GardensInfo /////
# /////////////////

class Gardens(models.Model):
    name = models.CharField(max_length=20)
    address = models.CharField(max_length=100)
    polygon = models.JSONField(blank=True, null=True, default = None)

    # foreign keys
    enterprise = models.ForeignKey(Enterprises, on_delete=models.CASCADE, default = 1)

    def __str__(self):
        return self.name
    
    def get_absolute_url(self):
        return f"/gardens/{self.id}"

class Cultivares(models.Model):
    title = models.CharField(max_length=20)

    def __str__(self):
        return self.title
    
class Blocks(models.Model):
    name = models.CharField(max_length=50)
    polygon = models.JSONField(blank=True, null=True) # encoder could be added
    is_autonomous = models.BooleanField(default=False)

    # foreign keys
    private_meteostation = models.ForeignKey(Meteostations, on_delete=models.SET_NULL, null = True)
    garden = models.ForeignKey(Gardens, on_delete=models.CASCADE)
    cultivar = models.ForeignKey(Cultivares, on_delete=models.SET_NULL, default=1, null = True )

    def __str__(self):
        return self.name
    
    def get_absolute_url(self):
        return f"/blocks/{self.garden.id}/{self.id}"

class YieldStages(models.Model):
    title = models.CharField(max_length=30)

    def __str__(self):
        return self.title

class TreeBreeds(models.Model):
    title = models.CharField(max_length=50)
    width = models.FloatField()
    height = models.FloatField()

    #foreign keys
    cultivate = models.ForeignKey(Cultivares, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

class EnterpriseSpecificBreeds(models.Model):
    title = models.CharField(max_length=50)
    width = models.FloatField()
    height = models.FloatField()
    yields = models.FloatField(null = True)
    injection = models.CharField(max_length=50, null = True)
    planting_distance = models.FloatField()

    enterprise = models.ForeignKey(Enterprises, on_delete=models.CASCADE)
    cultivar = models.ForeignKey(Cultivares, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

class TreeRow(models.Model):
    coordinates = models.JSONField()

    # foreign keys
    block = models.ForeignKey(Blocks, on_delete=models.CASCADE)
    tree_breed = models.ForeignKey(EnterpriseSpecificBreeds, on_delete=models.CASCADE)

class Trees(models.Model):
    latitude = models.FloatField()
    longitude = models.FloatField()
    width = models.FloatField()
    height = models.FloatField()
    breed = models.CharField(max_length=50)

    #foreign keys
    cultivares = models.ForeignKey(Cultivares, on_delete=models.CASCADE, null=True)
    block = models.ForeignKey(Blocks, on_delete=models.CASCADE, null=True)
    row = models.ForeignKey(TreeRow, on_delete=models.CASCADE, default = None, null = True)

class ProtectedRegions(models.Model):
    polygon = models.JSONField(blank=True, null=True)

    #foreign keys
    garden = models.ForeignKey(Gardens, on_delete=models.CASCADE)

# /////////////////
# Drones //////////
# /////////////////

class DroneModels(models.Model):
    maker = models.CharField(max_length=20) # DJI, Parrot, etc.
    model = models.CharField(max_length=50) 
    fly_time_min = models.FloatField()
    working_range = models.FloatField()
    min_temperature = models.FloatField()
    max_temperature = models.FloatField()
    camera_mp = models.FloatField()
    camera_direction = models.FloatField(default=0, validators=[MinValueValidator(0), MaxValueValidator(360)])

    def __str__(self):
        return self.model

class Drones(models.Model):
    name = models.CharField(max_length=40)



    # foreign keys
    model = models.ForeignKey(DroneModels, on_delete=models.CASCADE)
    block = models.ForeignKey(Blocks, on_delete=models.SET_NULL, null = True, unique=True) 
    enterprise = models.ForeignKey(Enterprises, on_delete=models.CASCADE)

    def __str__(self):
        return self.name

class DroneStations(models.Model):
    latitude = models.FloatField()
    longitude = models.FloatField()
    
    # foreign keys
    block = models.ForeignKey(Blocks, on_delete=models.CASCADE)


class Devices(models.Model):
    name = models.CharField(max_length=40)
    key = models.UUIDField(default=uuid.uuid4, editable=False)
    
    #foreign keys
    block = models.ForeignKey(Blocks, on_delete=models.SET_NULL, null = True)
    enterprise = models.ForeignKey(Enterprises, on_delete=models.CASCADE)

    def __str__(self):
        return self.name


class Missions(models.Model):
    name = models.CharField(max_length=40)
    status = models.BooleanField(default = 0)
    generated_date = models.DateTimeField(auto_now_add = True)
    closed_date = models.DateTimeField(null = True)
    #foreign keys
    block = models.ForeignKey(Blocks,on_delete=models.SET_NULL, null = True)
    stage = models.ForeignKey(YieldStages,on_delete=models.CASCADE)

    def __str__(self):
        return self.name
    
    def completionPercentage(self):
        flights = Flights.objects.filter(mission=self)
        if len(flights) == 0:
            return 0
        completed = 0
        for flight in flights:
            if flight.status == 3:
                completed += 1
        return int(completed / len(flights) * 100)
    
    def nextFlight(self):
        flights = Flights.objects.filter(mission=self, status=0 or 1)
        if len(flights) > 0:
            return min(flights, key=lambda x: x.start_date)
        return None
    
    def lastFlight(self):
        flights = Flights.objects.filter(mission=self, status=3)
        if len(flights) > 0:
            return max(flights, key=lambda x: x.end_date)
        return None
    
    def scabPercentage(self):
        TreeStateOneTreeOnly = TreeState.objects.filter(mission=self).values('tree').distinct()
        if TreeStateOneTreeOnly.count() == 0:
            return 0
        return int(TreeStateOneTreeOnly.filter(has_scab=True).count() / TreeStateOneTreeOnly.count() * 100)
    
    def get_absolute_url(self):
        return f"/blocks/{self.block.garden.id}/{self.block.id}/mission/{self.id}"



class FlightPlans(models.Model):
    flight_plan=models.JSONField(blank = True, null = True)
    sequence_num=models.IntegerField(null=False)

    #foreign keys
    mission = models.ForeignKey(Missions, on_delete=models.CASCADE, null=True)
    block = models.ForeignKey(Blocks, on_delete=models.SET_NULL, null=True)


class Flights(models.Model):
    status = models.IntegerField()
    start_date = models.DateTimeField(null = True)
    end_date = models.DateTimeField(null = True)

    diagnostics = models.JSONField(null = True)

    #foreign keys
    mission = models.ForeignKey(Missions,on_delete=models.CASCADE)
    plan = models.ForeignKey(FlightPlans,on_delete=models.CASCADE,null=True)

    def get_absolute_url(self):
        return f"/blocks/{self.plan.block.garden.id}/{self.plan.block.id}/mission/{self.mission.id}"



class Photos(models.Model):
    image_uri = models.ImageField(upload_to='uploads/')
    GPS = models.JSONField()
    altitude = models.FloatField()
    date_time = models.DateTimeField(auto_now_add = True)
    photo_location_num = models.IntegerField()
    
    # foreign keys
    tree = models.ForeignKey(Trees, on_delete=models.CASCADE)
    mission = models.ForeignKey(Missions, on_delete=models.CASCADE, null = True)

class TreeState(models.Model):
    yields = models.FloatField(null = True)
    probability_scab = models.FloatField(null = True)
    has_scab = models.BooleanField(null = True)

    last_updated = models.DateTimeField(null=True, default=datetime.datetime(2000, 1, 1, tzinfo=datetime.timezone.utc))
    yield_stage = models.ForeignKey(YieldStages, null = True, on_delete=models.CASCADE)
    
    # foreign keys
    tree = models.ForeignKey(Trees, on_delete=models.CASCADE)
    mission = models.ForeignKey(Missions, on_delete=models.CASCADE)

    class Meta:
        # Define uniqueness constraint
        unique_together = ('yield_stage', 'tree', 'mission',)

class MLModels(models.Model):
    title = models.CharField(max_length=50)
    file_uri = models.FileField(upload_to='ML_models/')
    classes = models.JSONField()
    active_classes = models.JSONField(blank=True, null=True)
    model_type = models.TextField(choices=[('yolo', 'YOLO'), ('mobilenet', 'MobileNet')])
    
    def __str__(self):
        return self.title
    

    
