from django import forms
from django.db import transaction
from .models import Hostel
from room.models import Room
from address.models import Address
from django.core.validators import RegexValidator
import json

# Load the state-city data from the JSON file
with open('utils/state-city.json', 'r') as f:  # Replace 'state-city.json' with your file path
    state_city_data = json.load(f)

STATE_CHOICES = [(state, state) for state in state_city_data.keys()] # Choices for state field

class HostelForm(forms.ModelForm):
    name = forms.CharField(max_length=255)
    email = forms.EmailField()
    contact_number = forms.CharField(max_length=10)
    total_floors = forms.IntegerField(min_value=1, initial=1)
    electricity_charge_per_unit = forms.FloatField(min_value=1.00, initial=1.00)
    description = forms.CharField(widget=forms.Textarea())

    address_line = forms.CharField(max_length=255)
    postal_code = forms.CharField(
        max_length=6, min_length=6,
        validators=[RegexValidator(r'^\d{6}$', message="Postal code must be exactly 6 digits and numeric.")]
    )
    state = forms.ChoiceField(choices=[("", "Select State")] + STATE_CHOICES, required=True)
    city = forms.ChoiceField(choices=[("", "Select City")], required=True)

    class Meta:
        model = Hostel
        fields = [
            'name', 'email', 'contact_number', 'total_floors', 'electricity_charge_per_unit', 'description',
            'address_line', 'state', 'city'
        ]

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

        self.fetched_address = None
        if self.instance.pk:
            self.fetched_address = Address.objects.filter(hostel_id=self.instance.pk).first()  # type: ignore

        if self.fetched_address:
            address = self.fetched_address
            self.fields['address_line'].initial = address.address_line
            self.fields['postal_code'].initial = address.postal_code
            self.fields['state'].initial = address.state
            self.fields['city'].initial = address.city

        selected_state = self.data.get('state') or self.fields['state'].initial
        selected_city = self.data.get('city') or self.fields['city'].initial

        if selected_state:
            city_choices = [(city, city) for city in state_city_data.get(selected_state, [])]
            self.fields['city'].choices = [("", "Select City")] + city_choices

            # Ensure the selected city is among the choices
            if selected_city and selected_city not in [c[0] for c in city_choices]:
                selected_city = ""

            self.fields['city'].initial = selected_city
        else:
            self.fields['city'].choices = [("", "Select City")]

    def clean(self):
        cleaned_data = super().clean()

        selected_state = cleaned_data.get('state')
        selected_city = cleaned_data.get('city')

        if selected_state and selected_city:
            valid_cities = state_city_data.get(selected_state, [])
            if selected_city not in valid_cities:
                self.add_error('city', "Invalid city for the selected state.")

        return cleaned_data

    def save(self, commit=True):
        is_new = self.instance.pk is None
        hostel = super().save(commit=False)

        with transaction.atomic(): # type: ignore
            hostel.save()
            if is_new:
                Address.objects.create( # type: ignore
                    hostel=hostel,
                    address_line=self.cleaned_data['address_line'],
                    postal_code=self.cleaned_data['postal_code'],
                    city=self.cleaned_data['city'],
                    state=self.cleaned_data['state'],
                    country="India",
                )

                # generates the room instances
                rooms = [
                    Room(
                        hostel=hostel,
                        room_number=f"{floor_index}0{room_index}",
                        is_available=True,
                        room_type='triple' if room_index == 3 else 'double',
                        total_beds=3 if room_index == 3 else 2,
                        price_per_month=18000 if room_index == 3 else 15000,
                    )
                    for floor_index in range(1, (self.cleaned_data['total_floors'] + 1))
                    for room_index in range(1, 7)
                ]
                Room.objects.bulk_create(rooms) # type: ignore
            else:
                if self.fetched_address:
                    self.fetched_address.address_line = self.cleaned_data['address_line']
                    self.fetched_address.postal_code = self.cleaned_data['postal_code']
                    self.fetched_address.city = self.cleaned_data['city']
                    self.fetched_address.state = self.cleaned_data['state']
                    self.fetched_address.save()

        return hostel
