from . import models
from utils.services import diff_day, current_date, get_month_days, next_month_due
from room.models import Room
from address.models import Address
from paymentlog.models import PaymentLog, CalculationDates
from paymentlog.services import generate_electricity_log_instances
from room.services import get_active_tenants
from tenant.models import TenantRoom

def create_tenant_rent(instance, tenant):
    rent_due = current_date(next_month_due(instance.cleaned_data['check_in']))
    food_due = current_date(next_month_due(instance.cleaned_data['food_start'] or instance.cleaned_data['check_in']))

    models.TenantRent.objects.create( # type: ignore
        tenant=tenant,
        security_amount=instance.cleaned_data['security_amount'],
        rent_due=rent_due,
        food_due=food_due,
        meal=instance.cleaned_data['meal']
    )

def create_occupation(instance, tenant):
    models.Occupation.objects.create( # type: ignore
        tenant=tenant,
        type=instance.cleaned_data['occupation_type'],
        address=instance.cleaned_data['occupation_address'],
        contact=instance.cleaned_data['occupation_contact'],
        institute_name=instance.cleaned_data['institute_name'],
    )

def create_guardian(instance, tenant):
    models.Guardian.objects.create( # type: ignore
        tenant=tenant,
        name=instance.cleaned_data['guardian_name'],
        phone_number=instance.cleaned_data['guardian_phone_number'],
        relation=instance.cleaned_data['guardian_relation']
    )

def create_address(instance, tenant):
    Address.objects.create( # type: ignore
        tenant=tenant,
        address_line=instance.cleaned_data['address_line'],
        postal_code=instance.cleaned_data['postal_code'],
        city=instance.cleaned_data['city'],
        state=instance.cleaned_data['state'],
        country="India",
    )

def join_room(instance, unsaved_tenant):
    room = instance.cleaned_data['room']
    tenants = get_active_tenants(room.id)

    # Lock the room object to prevent race conditions
    room = Room.objects.select_for_update().get(pk=room.pk) # type: ignore

    if len(tenants) != 0: # means we need to perform the calculation someone is already living in the room.
        electricity_payment_logs = generate_electricity_log_instances(room.id, instance.cleaned_data['current_electricity_reading'],  instance.cleaned_data['check_in'])
        PaymentLog.objects.bulk_create(electricity_payment_logs) # type: ignore

    TenantRoom.objects.create( # type: ignore
        tenant= unsaved_tenant,
        room= room,
        joined_on= current_date(instance.cleaned_data['check_in']),
        is_single_sharing = instance.cleaned_data['single_sharing'] or False
    )


    room.last_electricity_reading = instance.cleaned_data['current_electricity_reading']
    # update the room if it was meant for single sharing
    if(instance.cleaned_data['single_sharing']):
        room.is_available = False

    room.save()


def update_meal(self):
    tenant_rent = models.TenantRent.objects.select_for_update().get(tenant_id=self.instance.pk) # type: ignore
    if tenant_rent.meal and tenant_rent.meal.id != self.cleaned_data['meal'].id:
        dates = CalculationDates.objects.select_for_update().get(tenant_id=self.instance.pk) # type: ignore
        days_difference = diff_day(dates.last_food_calculation)

        if days_difference != 0 and tenant_rent.meal:
            per_day_food_cost = tenant_rent.meal.price_per_month / get_month_days(current_date())
            total_payble = round(days_difference * per_day_food_cost, 2)

            if total_payble > 0:
                PaymentLog.objects.create( # type: ignore
                    amount= total_payble,
                    tenant_id= self.instance.pk,
                    log_type= "food",
                    room_id= self.instance.current_room.id,
                    remark= f"""The log was created based on details:
                        Meal Type: {tenant_rent.meal.name},
                        Total Days: {days_difference},
                        Meal Price (per day): {round(per_day_food_cost, 2)},
                        Total Amount: {total_payble}
                    """,
                    created_at = current_date(),
                    updated_at = current_date(),
                )

        dates.last_food_calculation = current_date()
        dates.save()
    tenant_rent.meal = self.cleaned_data['meal']
    tenant_rent.save()


def create_calculation_dates(self, tenant):
    last_rent_calculation = current_date(self.cleaned_data['check_in'])
    last_food_calculation = current_date(self.cleaned_data['food_start'] or self.cleaned_data['check_in'])
    last_electricity_calculation = current_date(self.cleaned_data['check_in'])

    CalculationDates.objects.create(# type: ignore
        tenant=tenant,
        last_rent_calculation = last_rent_calculation,
        last_food_calculation = last_food_calculation,
        last_electricity_calculation = last_electricity_calculation,
    )

def is_checkout_action(log_entry):
    """
    Determine if a log entry represents a tenant checkout
    """
    if log_entry.action_flag != 2:
        return False

    try:
        tenant = log_entry.get_edited_object()
        if not tenant:
            return False

        # Check the change message
        changes = eval(log_entry.change_message)
        if isinstance(changes, list) and changes:
            for change in changes:
                if 'fields' in change and 'check_out' in change['fields']:
                    # Verify this is the actual checkout (check_out field was set from None)
                    return True

        return False

    except Exception:
        return False
