from decimal import Decimal

from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from django.utils import timezone


class Trip(models.Model):
    class TripType(models.TextChoices):
        BUSINESS = "business", "Business"
        PERSONAL = "personal", "Personal"
        COMMUTING = "commuting", "Commuting"
        REPAIR = "repair", "Repair / Maintenance"

    class DistanceSource(models.TextChoices):
        ODOMETER = "odometer", "Odometer"
        MAP = "map", "Google Maps"

    date = models.DateField()
    start_time = models.TimeField()
    end_time = models.TimeField()
    start_location = models.CharField(max_length=255)
    end_location = models.CharField(max_length=255)
    business_purpose = models.TextField()
    trip_type = models.CharField(max_length=20, choices=TripType.choices)
    start_odometer = models.DecimalField(max_digits=10, decimal_places=1, null=True, blank=True)
    end_odometer = models.DecimalField(max_digits=10, decimal_places=1, null=True, blank=True)
    distance_miles = models.DecimalField(max_digits=8, decimal_places=1, null=True, blank=True)
    distance_source = models.CharField(max_length=20, choices=DistanceSource.choices, default=DistanceSource.MAP)
    notes = models.TextField(blank=True)
    created_at = models.DateTimeField(default=timezone.now)
    updated_at = models.DateTimeField(default=timezone.now)

    class Meta:
        ordering = ["-date", "-start_time", "-created_at"]

    def __str__(self):
        return f"{self.date:%Y-%m-%d} · {self.start_location} → {self.end_location}"

    def get_absolute_url(self):
        return reverse("trip_detail", args=[self.pk])

    @property
    def miles_display(self):
        return self.distance_miles or Decimal("0.0")

    def clean(self):
        errors = {}
        if self.end_time and self.start_time and self.end_time < self.start_time:
            errors["end_time"] = "End time must be after the start time."

        if self.start_odometer is not None and self.end_odometer is not None:
            if self.end_odometer < self.start_odometer:
                errors["end_odometer"] = "Ending odometer must be greater than or equal to starting odometer."
            else:
                self.distance_miles = self.end_odometer - self.start_odometer
                self.distance_source = self.DistanceSource.ODOMETER
        elif self.distance_miles is not None:
            if self.distance_miles < 0:
                errors["distance_miles"] = "Distance must be zero or greater."
            else:
                self.distance_source = self.DistanceSource.MAP
        else:
            errors["distance_miles"] = "Add odometer readings or calculate mileage from Google Maps."

        if errors:
            raise ValidationError(errors)

    def save(self, *args, **kwargs):
        self.full_clean()
        super().save(*args, **kwargs)
