from decimal import Decimal

from django import forms
from django.utils import timezone

from .models import Trip


DATETIME_LOCAL_FORMAT = "%Y-%m-%dT%H:%M"


class TripForm(forms.ModelForm):
    created_at_override = forms.DateTimeField(
        required=False,
        label="Custom created timestamp",
        input_formats=[DATETIME_LOCAL_FORMAT],
        widget=forms.DateTimeInput(attrs={"type": "datetime-local", "class": "form-control", "placeholder": "Leave blank to use now"}, format=DATETIME_LOCAL_FORMAT),
        help_text="Optional for retroactive entries. Leave blank to use the current timestamp.",
    )
    updated_at_override = forms.DateTimeField(
        required=False,
        label="Custom updated timestamp",
        input_formats=[DATETIME_LOCAL_FORMAT],
        widget=forms.DateTimeInput(attrs={"type": "datetime-local", "class": "form-control", "placeholder": "Leave blank to auto-update"}, format=DATETIME_LOCAL_FORMAT),
        help_text="Optional. If empty while editing, the app will stamp the current time.",
    )
    update_end_odometer_from_map = forms.BooleanField(
        required=False,
        label="Use Google Maps miles to prefill ending odometer",
        help_text="If a starting odometer and route miles are available, this suggests an ending odometer.",
    )

    class Meta:
        model = Trip
        fields = ["date", "start_time", "end_time", "start_location", "end_location", "business_purpose", "trip_type", "start_odometer", "end_odometer", "distance_miles", "notes"]
        widgets = {
            "date": forms.DateInput(attrs={"type": "date", "class": "form-control"}),
            "start_time": forms.TimeInput(attrs={"type": "time", "class": "form-control"}),
            "end_time": forms.TimeInput(attrs={"type": "time", "class": "form-control"}),
            "start_location": forms.TextInput(attrs={"class": "form-control", "placeholder": "123 Market St, San Francisco"}),
            "end_location": forms.TextInput(attrs={"class": "form-control", "placeholder": "Client office, warehouse, property, etc."}),
            "business_purpose": forms.Textarea(attrs={"class": "form-control", "rows": 3, "placeholder": "Meeting with Client A at Property X"}),
            "trip_type": forms.Select(attrs={"class": "form-select"}),
            "start_odometer": forms.NumberInput(attrs={"class": "form-control", "step": "0.1", "min": "0", "placeholder": "Optional"}),
            "end_odometer": forms.NumberInput(attrs={"class": "form-control", "step": "0.1", "min": "0", "placeholder": "Optional"}),
            "distance_miles": forms.NumberInput(attrs={"class": "form-control", "step": "0.1", "min": "0", "placeholder": "Auto-filled from Google Maps or manual"}),
            "notes": forms.Textarea(attrs={"class": "form-control", "rows": 3, "placeholder": "Client, project, repair details, or extra notes"}),
        }
        help_texts = {
            "business_purpose": "Be specific so the trip is audit-friendly.",
            "distance_miles": "Preferred source is odometer when both readings are present; otherwise Google Maps mileage is used.",
        }

    def __init__(self, *args, latest_end_odometer=None, **kwargs):
        super().__init__(*args, **kwargs)
        if not self.instance.pk and latest_end_odometer is not None and self.initial.get("start_odometer") in (None, ""):
            self.initial["start_odometer"] = latest_end_odometer


    def clean_business_purpose(self):
        purpose = (self.cleaned_data.get("business_purpose") or "").strip()
        if len(purpose) < 8:
            raise forms.ValidationError("Please add a more specific business purpose for this trip.")
        return purpose

    def clean(self):
        cleaned_data = super().clean()
        start_odometer = cleaned_data.get("start_odometer")
        end_odometer = cleaned_data.get("end_odometer")
        distance_miles = cleaned_data.get("distance_miles")
        should_prefill_end = cleaned_data.get("update_end_odometer_from_map")

        if start_odometer is not None and end_odometer is not None and end_odometer < start_odometer:
            self.add_error("end_odometer", "Ending odometer must be greater than or equal to starting odometer.")

        if should_prefill_end and start_odometer is not None and distance_miles is not None and not end_odometer:
            cleaned_data["end_odometer"] = Decimal(start_odometer) + Decimal(distance_miles)
            self.cleaned_data["end_odometer"] = cleaned_data["end_odometer"]

        if start_odometer is None and end_odometer is not None:
            self.add_error("start_odometer", "Add a starting odometer before storing an ending odometer.")

        if start_odometer is None and end_odometer is None and distance_miles is None:
            self.add_error("distance_miles", "Calculate Google Maps mileage or enter odometer readings.")

        return cleaned_data

    def save(self, commit=True):
        trip = super().save(commit=False)
        now = timezone.now()
        created_override = self.cleaned_data.get("created_at_override")
        updated_override = self.cleaned_data.get("updated_at_override")

        if trip.pk:
            trip.created_at = created_override or trip.created_at
            trip.updated_at = updated_override or now
        else:
            trip.created_at = created_override or now
            trip.updated_at = updated_override or trip.created_at

        if commit:
            trip.save()
        return trip


class TripFilterForm(forms.Form):
    start_date = forms.DateField(required=False, widget=forms.DateInput(attrs={"type": "date", "class": "form-control"}))
    end_date = forms.DateField(required=False, widget=forms.DateInput(attrs={"type": "date", "class": "form-control"}))
    month = forms.IntegerField(required=False, min_value=1, max_value=12, widget=forms.NumberInput(attrs={"class": "form-control", "placeholder": "Month"}))
    year = forms.IntegerField(required=False, min_value=2000, max_value=2100, widget=forms.NumberInput(attrs={"class": "form-control", "placeholder": "Year"}))
    trip_type = forms.ChoiceField(required=False, choices=[("", "All trip types"), *Trip.TripType.choices], widget=forms.Select(attrs={"class": "form-select"}))


class ReportFilterForm(forms.Form):
    REPORT_CHOICES = [("month", "Monthly report"), ("range", "Custom date range"), ("year", "Annual summary")]

    report_type = forms.ChoiceField(choices=REPORT_CHOICES, required=False, initial="month", widget=forms.Select(attrs={"class": "form-select"}))
    month = forms.IntegerField(required=False, min_value=1, max_value=12, widget=forms.NumberInput(attrs={"class": "form-control"}))
    year = forms.IntegerField(required=False, min_value=2000, max_value=2100, widget=forms.NumberInput(attrs={"class": "form-control"}))
    start_date = forms.DateField(required=False, widget=forms.DateInput(attrs={"type": "date", "class": "form-control"}))
    end_date = forms.DateField(required=False, widget=forms.DateInput(attrs={"type": "date", "class": "form-control"}))

    def clean(self):
        cleaned = super().clean()
        report_type = cleaned.get("report_type") or "month"
        year = cleaned.get("year")
        month = cleaned.get("month")
        start_date = cleaned.get("start_date")
        end_date = cleaned.get("end_date")

        if report_type == "month":
            if not month or not year:
                raise forms.ValidationError("Choose both month and year for the monthly report.")
        elif report_type == "range":
            if not start_date or not end_date:
                raise forms.ValidationError("Choose both start and end dates for a custom range.")
            if end_date < start_date:
                raise forms.ValidationError("End date must be on or after the start date.")
        elif report_type == "year":
            if not year:
                raise forms.ValidationError("Choose a year for the annual summary.")
        return cleaned
