from django.core.exceptions import ValidationError
from django.db import models
from django.core.validators import FileExtensionValidator

from codesofy.master_details import ResultMode, ResultType
from cropmanagement.models import Crop
from mydevicemanagement.models import CustomerDevice
from fieldmanagement.models import CustomerField
from buyers.models import CustomerBuyer
from .validators import validate_image_file_size_5mb 


class Result(models.Model):
    device = models.ForeignKey(
        CustomerDevice,
        on_delete=models.CASCADE,
        related_name="results",
        help_text="Device that recorded this result (must belong to the customer).",
    )
    field = models.ForeignKey(
        CustomerField,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="results",
        help_text="Field where the sample was taken (optional).",
    )
    buyer = models.ForeignKey(
        CustomerBuyer,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="results",
        help_text="Buyer linked to this result (optional).",
    )
    result_mode = models.CharField(max_length=50, blank=True, choices=ResultMode.choices())
    batch_number = models.CharField(max_length=100,blank=True)
    description = models.TextField(blank=True)

    crop_type = models.CharField(max_length=100,null=True, blank=True)
    crop_temperature = models.FloatField(null=True, blank=True)
    crop_weight = models.FloatField(null=True, blank=True)

    moisture_level = models.FloatField(null=True, blank=True)
    density_unit = models.CharField(max_length=50, blank=True)
    temperature_unit = models.CharField(max_length=50, blank=True)

    # ↓↓↓ added max_digits/decimal_places
    average_moisture_level = models.FloatField(
        null=True, blank=True,
        help_text="Average moisture as a percentage, e.g. 12.34"
    )
    moisture_threshold = models.FloatField(null=True, blank=True)

    moisture_temperature = models.FloatField(null=True, blank=True,
        help_text="Temperature in °C, e.g. 25.50"
    )
    bulk_density = models.FloatField( null=True, blank=True,
        help_text="Bulk density (e.g. 0.789 g/cm³)"
    )
    result_type = models.CharField(
        max_length=50, blank=True,
        choices=ResultType.choices()
    )
    high_moisture_estimate = models.FloatField(
        null=True,
        blank=True
    )
    humidity = models.FloatField(null=True, blank=True)
    weather_temperature = models.FloatField(null=True, blank=True)
    pressure = models.FloatField(null=True, blank=True)
    weather_description = models.CharField(max_length=255, blank=True)

    visibility = models.FloatField(null=True, blank=True)
    wind_speed = models.FloatField(null=True, blank=True)
    wind_direction = models.CharField(max_length=50, blank=True)
    wind_gusts = models.FloatField(null=True, blank=True)
    cloud_coverage = models.FloatField(null=True, blank=True)
    uv_index = models.FloatField(null=True, blank=True)

    # RECOMMENDED: make this an integer or string, not Decimal
    # If it's a numeric id:
    scale_number_id = models.CharField(
            max_length=255,
            null=True,
            blank=True
        )
    # If it's an alphanumeric code instead, use:
    # scale_number_id = models.CharField(max_length=50, null=True, blank=True)

    gps_lat = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
    gps_lon = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)

    sample_image = models.ImageField(
        upload_to="result_samples/",
        null=True,
        blank=True,
        validators=[
            FileExtensionValidator(['jpg', 'jpeg']),
            validate_image_file_size_5mb,   # <-- add this
        ]
    )

    reading_datetime = models.DateTimeField(null=True,blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    measure_number = models.IntegerField(null=True, blank=True)
    crop = models.ForeignKey(
        Crop,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="results"
    )
    enforce_unique = models.BooleanField(
    null=True,            # allow NULL in DB (needed for MANUAL duplicates)
    default=None,
    db_index=True,
    blank=True,           # <-- add this to silence “cannot be blank” from full_clean()
)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["device", "measure_number", "enforce_unique"],
                name="uniq_measure_per_device_when_enforced",
            ),
        ]
        indexes = [
            models.Index(fields=["device"]),
            models.Index(fields=["reading_datetime"]),
            models.Index(fields=["device", "measure_number"]),
        ]

    def _compute_enforce_unique(self):
        mode = (self.result_mode or "").upper()
        return None if mode == ResultMode.MANUAL.value else True

    def save(self, *args, **kwargs):
        # set the flag first so full_clean() does not see "" / blank
        self.enforce_unique = self._compute_enforce_unique()

        self.full_clean()  # runs field + unique checks with the correct flag

        # your existing normalizations...
        if self.batch_number: self.batch_number = self.batch_number.strip()
        if self.crop_type: self.crop_type = self.crop_type.strip()
        if self.weather_description: self.weather_description = self.weather_description.strip()

        return super().save(*args, **kwargs)
