from django.core.exceptions import ValidationError
from django import forms
from django.db import transaction
from django.utils.html import format_html
from .models import Tenant, TenantRent
from django.core.validators import RegexValidator
from room.models import Room
from address.models import Address
from hostel.models import Hostel
from meal.models import Meal
import json
from . import services


# 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 TenantForm(forms.ModelForm):
    # Tenant Fields
    avatar = forms.ImageField(required=False)
    name = forms.CharField(max_length=255)
    email = forms.EmailField()
    phone_number = forms.CharField(max_length=10)
    adhar_number = forms.CharField(max_length=12)
    id_proof = forms.FileField(required=False)
    terms_and_conditions = forms.BooleanField(required=False, label=format_html('I confirm that I have downloaded, completed, and submitted this <a target="_blank" href="https://admin.sweetvilla.in/media/sweetvilla_terms_and_conditions.pdf">terms and conditions</a> form.'), widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}))

    # room fields.
    hostel = forms.ModelChoiceField(
        queryset=Hostel.objects.all(), # type: ignore
    )
    room = forms.ModelChoiceField(
        queryset=Room.objects.none(),  # type: ignore
    )
    current_electricity_reading = forms.IntegerField(min_value=1, initial=1)
    check_in = forms.DateField(widget=forms.DateInput(attrs={'type': 'date'}))


    # Guardian Fields
    guardian_name = forms.CharField(max_length=255)
    guardian_phone_number = forms.CharField(max_length=10)
    guardian_relation = forms.CharField(max_length=50)

    # Occupation Fields
    occupation_type = forms.ChoiceField(choices=[('job', 'Job'), ('student', 'Student'), ('other', 'Other')])
    occupation_address = forms.CharField(max_length=255)
    occupation_contact = forms.CharField(max_length=10)
    institute_name = forms.CharField(max_length=255, label='College/Company Name', widget=forms.TextInput(attrs={'placeholder': 'Where you work or study'}))

    # Rent Fields
    security_amount = forms.DecimalField(max_digits=10, decimal_places=2)
    meal = forms.ModelChoiceField(
        queryset=Meal.objects.all(),  # type: ignore
    )
    food_start = forms.DateField(required=False, widget=forms.DateInput(attrs={'type': 'date'}))

    # address
    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)

    single_sharing = forms.BooleanField(required=False, initial=False)


    class Meta:
        model = Tenant
        fields = [
            'avatar','name', 'email', 'phone_number', 'adhar_number', 'id_proof', 'address_line', 'state', 'city', 'postal_code', 'single_sharing',
            'hostel', 'room', 'current_electricity_reading', 'check_in', 'guardian_name', 'guardian_phone_number',
            'guardian_relation', 'occupation_type', 'institute_name', 'occupation_address',
            'occupation_contact', 'security_amount', 'meal', 'food_start', 'terms_and_conditions',
        ]



    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")]


        if "hostel" in self.data:  # If the form is submitted with hostel data
            try:
                hostel_id = int(self.data.get("hostel")) # type: ignore
                self.fields["room"].queryset = Room.objects.filter(hostel_id=hostel_id) # type: ignore
            except (ValueError, TypeError):
                pass  # If conversion fails, leave queryset empty
        elif self.instance.pk:  # If instance exists (editing)
            self.fields["room"].queryset = Room.objects.filter(hostel=self.instance.hostel) # type: ignore


    def save(self, commit=True):
        is_new = self.instance.pk is None
        # Create the Tenant instance
        tenant = super().save(commit=False)


        with transaction.atomic(): # type: ignore
            if is_new:
                tenant.save()
                services.join_room(self, tenant)
                services.create_address(self, tenant)
                services.create_guardian(self, tenant)
                services.create_occupation(self, tenant)
                services.create_tenant_rent(self, tenant)
                services.create_calculation_dates(self, tenant)
            else:
                tenant.save()

        return tenant


class UpdateTenantForm(forms.ModelForm):
    avatar = forms.ImageField(required=False)
    name = forms.CharField(max_length=255)
    email = forms.EmailField()
    phone_number = forms.CharField(max_length=10)
    adhar_number = forms.CharField(max_length=12)
    meal = forms.ModelChoiceField(
        queryset=Meal.objects.all(),  # type: ignore
    )

    class Meta:
        model = Tenant
        fields = [
            'avatar','name', 'email', 'phone_number', 'adhar_number', 'meal'
        ]

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

        if self.instance: # Check if we are editing an existing instance
            rent_info = TenantRent.objects.get(tenant_id=self.instance.pk) # type: ignore
            self.fields['meal'].initial = rent_info.meal  # Set initial value from existing instance


    def save(self, commit=True):
        tenant = super().save(commit=False)

        if tenant.check_out and self.cleaned_data['meal'].id:
            tenant_rent = TenantRent.objects.get(tenant_id=tenant.pk) # type: ignore
            if(tenant_rent.meal.id != self.cleaned_data['meal'].id):
                raise ValidationError({"meal": "Cannot change meal plan for checked-out tenant."})

        with transaction.atomic(): # type: ignore
            services.update_meal(self)
            tenant.save()

        return tenant
