from django import forms
from django.core.exceptions import ValidationError
from django.utils import timezone

from .models import ContactEnquiry, CustomerReview


DESTINATION_CHOICES = (
    (
        "Karnataka Tours",
        (
            ("Chikmagalur", "Chikmagalur"),
            ("Coorg", "Coorg"),
            ("Mysore", "Mysore"),
            ("Ooty", "Ooty"),
            ("Hampi", "Hampi"),
            ("Dandeli", "Dandeli"),
        ),
    ),
    (
        "Domestic Tours",
        (
            ("Kerala", "Kerala"),
            ("Goa", "Goa"),
            ("Himachal", "Himachal"),
            ("Kashmir", "Kashmir"),
            ("Golden Triangle", "Golden Triangle"),
            ("Darjeeling & Gangtok", "Darjeeling & Gangtok"),
        ),
    ),
    (
        "International Tours",
        (
            ("Bhutan", "Bhutan"),
            ("Thailand", "Thailand"),
            ("Singapore", "Singapore"),
            ("Malaysia", "Malaysia"),
            ("Dubai", "Dubai"),
            ("Bali", "Bali"),
        ),
    ),
)

DESTINATION_FLAT_CHOICES = tuple(
    value
    for _, grouped in DESTINATION_CHOICES
    for value, _ in grouped
)


class ContactEnquiryForm(forms.ModelForm):
    destination = forms.CharField(
        widget=forms.TextInput(
            attrs={
                "placeholder": "Type and select destination",
                "autocomplete": "off",
                "list": "destination-options",
            }
        )
    )

    class Meta:
        model = ContactEnquiry
        fields = [
            "name",
            "phone",
            "email",
            "city",
            "destination",
            "date_of_travel",
            "adults",
            "children",
            "children_ages",
            "number_of_nights",
            "hotel_category",
            "special_request",
        ]
        widgets = {
            "name": forms.TextInput(attrs={"placeholder": "Full Name"}),
            "phone": forms.TextInput(attrs={"placeholder": "Mobile Number", "inputmode": "numeric", "maxlength": "10"}),
            "email": forms.EmailInput(attrs={"placeholder": "Email Address"}),
            "city": forms.TextInput(attrs={"placeholder": "City"}),
            "date_of_travel": forms.DateInput(attrs={"type": "date"}),
            "adults": forms.NumberInput(attrs={"min": "1", "step": "1", "placeholder": "Adults"}),
            "children": forms.NumberInput(attrs={"min": "0", "step": "1", "placeholder": "Children"}),
            "children_ages": forms.TextInput(attrs={"placeholder": "e.g., 5, 9"}),
            "number_of_nights": forms.NumberInput(attrs={"min": "1", "step": "1", "placeholder": "Number of Nights"}),
            "hotel_category": forms.Select(),
            "special_request": forms.Textarea(
                attrs={
                    "placeholder": "Tell us about your travel preferences, honeymoon, family trip, sightseeing, adventure activities, vehicle preference, etc.",
                    "rows": 5,
                }
            ),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields["name"].required = True
        self.fields["phone"].required = True
        self.fields["email"].required = True
        self.fields["destination"].required = True
        self.fields["date_of_travel"].required = True
        self.fields["adults"].required = True
        self.fields["number_of_nights"].required = True
        self.fields["hotel_category"].required = True
        self.fields["children"].required = False
        self.fields["children_ages"].required = False
        self.fields["city"].required = False
        self.fields["special_request"].required = False

        self.fields["children"].initial = 0
        self.destination_suggestions = DESTINATION_FLAT_CHOICES

        for field in self.fields.values():
            existing_classes = field.widget.attrs.get("class", "")
            css_class = "form-select" if isinstance(field.widget, forms.Select) else "form-control"
            field.widget.attrs["class"] = f"{existing_classes} {css_class}".strip()

        self.fields["hotel_category"].choices = [("", "Select hotel category")] + list(ContactEnquiry.HotelCategory.choices)

    def clean_phone(self):
        phone = self.cleaned_data.get("phone", "")
        digits = "".join(ch for ch in phone if ch.isdigit())
        if len(digits) != 10:
            raise ValidationError("Mobile number must be exactly 10 digits.")
        return digits

    def clean_date_of_travel(self):
        travel_date = self.cleaned_data.get("date_of_travel")
        if travel_date and travel_date < timezone.localdate():
            raise ValidationError("Date of travel cannot be in the past.")
        return travel_date

    def clean_destination(self):
        destination = (self.cleaned_data.get("destination") or "").strip()
        if not destination:
            raise ValidationError("Please select a destination.")

        valid_lookup = {item.lower(): item for item in DESTINATION_FLAT_CHOICES}
        resolved = valid_lookup.get(destination.lower())
        if not resolved:
            raise ValidationError("Please choose a valid destination from the list.")
        return resolved

    def clean(self):
        cleaned_data = super().clean()
        children = cleaned_data.get("children") or 0
        children_ages = (cleaned_data.get("children_ages") or "").strip()

        if children < 0:
            self.add_error("children", "Number of children cannot be negative.")

        if children > 0 and not children_ages:
            self.add_error("children_ages", "Please enter age of children.")

        return cleaned_data

    def save(self, commit=True):
        enquiry = super().save(commit=False)
        enquiry.travel_requirement = ContactEnquiry.Requirement.HOLIDAY_PACKAGE
        enquiry.message = enquiry.special_request or (
            f"Destination: {enquiry.destination}; "
            f"Travel Date: {enquiry.date_of_travel}; Adults: {enquiry.adults}; Children: {enquiry.children}; "
            f"Nights: {enquiry.number_of_nights}; Hotel Category: {enquiry.get_hotel_category_display() if enquiry.hotel_category else 'Not specified'}"
        )
        if commit:
            enquiry.save()
        return enquiry


class CustomerReviewForm(forms.ModelForm):
    class Meta:
        model = CustomerReview
        fields = ["name", "city", "email", "rating", "review"]
        widgets = {
            "name": forms.TextInput(attrs={"placeholder": "Full Name"}),
            "city": forms.TextInput(attrs={"placeholder": "City (Optional)"}),
            "email": forms.EmailInput(attrs={"placeholder": "Email (Optional)"}),
            "rating": forms.HiddenInput(),
            "review": forms.Textarea(
                attrs={
                    "placeholder": "Share your travel experience...",
                    "rows": 4,
                    "maxlength": "1200",
                }
            ),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["name"].required = True
        self.fields["review"].required = True
        self.fields["city"].required = False
        self.fields["email"].required = False

    def clean_rating(self):
        rating = self.cleaned_data.get("rating")
        if rating is None:
            raise ValidationError("Please select a star rating.")
        if rating < 1 or rating > 5:
            raise ValidationError("Rating must be between 1 and 5 stars.")
        return rating

    def clean_name(self):
        name = (self.cleaned_data.get("name") or "").strip()
        if len(name) < 2:
            raise ValidationError("Please enter a valid name.")
        return name

    def clean_review(self):
        review = (self.cleaned_data.get("review") or "").strip()
        if len(review) < 10:
            raise ValidationError("Please share at least 10 characters in your review.")
        return review

    def save(self, commit=True):
        instance = super().save(commit=False)
        instance.status = CustomerReview.Status.PENDING
        if commit:
            instance.save()
        return instance
