from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.views.generic import ListView, FormView, CreateView, UpdateView, DetailView
from django.http import HttpResponseRedirect, JsonResponse
from django.urls import reverse, reverse_lazy
from django.conf import settings
from datetime import date, datetime, time
from django.contrib.auth import login
import json

from bazi.models import Person
from .forms import NumberPowerForm, NumberPowerCalculateForm
from iching.utils.numberpower import NumberPower
from iching.utils.serializers import make_json_serializable
from accounts.utils import create_temporary_user, extract_first_last_name

@login_required
def delete_person(request, pk):
    """删除一个人及其相关的数字能量数据"""
    person = get_object_or_404(Person, pk=pk, created_by=request.user)
    
    if request.method == 'POST':
        person.delete()
        messages.success(request, f'已删除 {person.name} 及其相关数据。')
        return redirect('number:charts')
    
    return render(request, 'number/confirm_delete.html', {'person': person})

class NumberPowerCalculatorView(FormView):
    """
    View for calculating NumberPower.
    """
    form_class = NumberPowerForm
    template_name = 'number/calculate.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if 'number_result' in self.request.session:
            context['number_result'] = self.request.session['number_result']
            context['person'] = self.request.session.get('person_data')
            # Clear from session after retrieving
            del self.request.session['number_result']
            if 'person_data' in self.request.session:
                del self.request.session['person_data']
        return context
        
    def form_valid(self, form):
        # Prepare data for calculation
        data = {
            'dob': form.cleaned_data['birth_date'].strftime('%Y-%m-%d'),
            'dobtime': form.cleaned_data['birth_time'].strftime('%H:%M') if form.cleaned_data['birth_time'] else '00:00',
            'twin': form.cleaned_data['twin_type'],
            'fdob': form.cleaned_data['father_dob'].strftime('%Y-%m-%d') if form.cleaned_data['father_dob'] else None,
            'mdob': form.cleaned_data['mother_dob'].strftime('%Y-%m-%d') if form.cleaned_data['mother_dob'] else None,
        }
        
        # Calculate NumberPower
        result = NumberPower.calculate(data)
        
        # Store person data for display
        person_data = {
            'name': form.cleaned_data['name'],
            'gender': form.cleaned_data['gender'],
            'birth_date': form.cleaned_data['birth_date'].strftime('%Y年%m月%d日'),
            'birth_time': form.cleaned_data['birth_time'].strftime('%H:%M') if form.cleaned_data['birth_time'] else '',
            'twin_type': form.cleaned_data['twin_type'],
            'father_dob': form.cleaned_data['father_dob'].strftime('%Y年%m月%d日') if form.cleaned_data['father_dob'] else '',
            'mother_dob': form.cleaned_data['mother_dob'].strftime('%Y年%m月%d日') if form.cleaned_data['mother_dob'] else '',
        }
        
        # Handle authentication - create temporary user if needed
        if not self.request.user.is_authenticated:
            # Extract user data from form for temporary user creation
            full_name = form.cleaned_data['name'] or ''
            first_name, last_name = extract_first_last_name(full_name)
            
            # Prepare user data for temporary user creation (full Number form fields)
            # Convert date/time objects to strings for processing in create_temporary_user
            user_data = {
                'name': form.cleaned_data['name'],
                'first_name': first_name,
                'last_name': last_name,
                'gender': form.cleaned_data['gender'],
                'birth_date': form.cleaned_data['birth_date'].strftime('%Y-%m-%d') if form.cleaned_data['birth_date'] else None,
                'birth_time': form.cleaned_data['birth_time'].strftime('%H:%M') if form.cleaned_data['birth_time'] else None,
                'twin_type': form.cleaned_data['twin_type'],
                'father_dob': form.cleaned_data['father_dob'].strftime('%Y-%m-%d') if form.cleaned_data['father_dob'] else None,
                'mother_dob': form.cleaned_data['mother_dob'].strftime('%Y-%m-%d') if form.cleaned_data['mother_dob'] else None,
            }
            
            # Create temporary user with extracted data and log them in
            temp_user = create_temporary_user(user_data)
            login(self.request, temp_user)
            
            # Check if signal already created an owner record
            try:
                existing_owner = Person.objects.get(created_by=temp_user, owner=True)
                # Use the existing owner record for Number calculation
                existing_owner.number_result = result
                existing_owner.save()
                person = existing_owner
            except Person.DoesNotExist:
                # No owner record exists, check if this should be the first owner record
                existing_records = Person.objects.filter(created_by=temp_user).count()
                is_first_record = existing_records == 0
                
                person = Person.objects.create(
                    name=form.cleaned_data['name'],
                    gender=form.cleaned_data['gender'],
                    birth_date=form.cleaned_data['birth_date'],
                    birth_time=form.cleaned_data['birth_time'],
                    twin_type=form.cleaned_data['twin_type'],
                    father_dob=form.cleaned_data['father_dob'],
                    mother_dob=form.cleaned_data['mother_dob'],
                    created_by=temp_user,
                    created_by_temp_user=True,
                    owner=is_first_record,  # First record becomes owner, others are calculations
                    number_result=result
                )
                
            messages.success(self.request, f"数字能量计算成功: {person.name}")
            return redirect('number:chart', pk=person.pk)
        else:
            # For authenticated users, check if this should be their first owner record
            existing_records = Person.objects.filter(created_by=self.request.user).count()
            is_first_record = existing_records == 0
            
            person = Person.objects.create(
                name=form.cleaned_data['name'],
                gender=form.cleaned_data['gender'],
                birth_date=form.cleaned_data['birth_date'],
                birth_time=form.cleaned_data['birth_time'],
                twin_type=form.cleaned_data['twin_type'],
                father_dob=form.cleaned_data['father_dob'],
                mother_dob=form.cleaned_data['mother_dob'],
                created_by=self.request.user,
                owner=is_first_record,  # First record becomes owner, others are calculations
                number_result=result
            )
            # Set flag if user is temporary
            if hasattr(self.request.user, 'is_temporary_user') and self.request.user.is_temporary_user:
                person.created_by_temp_user = True
                person.save()
                    
            messages.success(self.request, f"数字能量计算成功: {person.name}")
            return redirect('number:chart', pk=person.pk)

class NumberPowerResultsView(LoginRequiredMixin, ListView):
    """
    View for displaying a list of people with NumberPower results.
    """
    model = Person
    template_name = 'number/charts_list.html'
    context_object_name = 'persons'
    paginate_by = 10  # Default number of items per page
    
    def get_queryset(self):
        """Return all people except the owner record, calculating NumberPower results for any without them."""
        queryset = super().get_queryset().filter(
            created_by=self.request.user,
            owner=False  # Exclude the owner record
        ).order_by('-created_at')
        
        # Get all people regardless of whether they have number_result
        for person in queryset:
            if not person.number_result:
                # Calculate and save number_result for this person
                self.calculate_number_result(person)
                
        return queryset
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get the user's own record
        try:
            user_record = Person.objects.get(
                created_by=self.request.user,
                owner=True
            )
            # Calculate number result if not exists
            if not user_record.number_result:
                self.calculate_number_result(user_record)
            context['user_record'] = user_record
        except Person.DoesNotExist:
            context['user_record'] = None
        
        # Get pagination preference
        items_per_page = self.request.session.get('pagination_preference', 10)
        
        # Update pagination context
        context['items_per_page'] = items_per_page
        context['pagination_options'] = [10, 20, 50, 100]
        
        # Add pagination context (similar to liuyao list)
        paginator = context['paginator']
        page_obj = context['page_obj']
        
        # Calculate page range (show 5 pages around current page)
        page_range = []
        current_page = page_obj.number
        total_pages = paginator.num_pages
        
        # Logic to display a limited range of page numbers
        if total_pages <= 5:
            page_range = range(1, total_pages + 1)
        else:
            # Always show 5 pages if possible
            start_page = max(current_page - 2, 1)
            end_page = min(start_page + 4, total_pages)
            
            # Adjust start_page if we're at the end
            if end_page == total_pages:
                start_page = max(end_page - 4, 1)
                
            page_range = range(start_page, end_page + 1)
        
        context['page_range'] = page_range

        return context
    
    def get_paginate_by(self, queryset):
        """
        Get the number of items to paginate by, or use settings default
        """
        # Check if user has set a preference in their session
        session_value = self.request.session.get('number_items_per_page')
        if session_value:
            return session_value
        
        # Check URL parameter (allow temporary override)
        url_value = self.request.GET.get('per_page')
        if url_value and url_value.isdigit() and 5 <= int(url_value) <= 100:
            return int(url_value)
            
        # Fall back to settings with app-specific default
        return settings.PAGINATE_BY.get('number', settings.PAGINATE_BY['default'])

    def calculate_number_result(self, person):
        """Calculate and save NumberPower result for a person."""
        if not person.birth_date:
            return
            
        # Prepare data for calculation
        data = {
            'name': person.name,
            'gender': person.gender.lower(),
            'birth_date': person.birth_date,
            'birth_time': person.birth_time,
            'twin_type': person.twin_type,
            'zi_hour_type': 'before_midnight' if person.birth_time and person.birth_time.hour == 23 else 'after_midnight',
            'is_adopted': False,  # Default value
            'father_birth_date': person.father_dob,
            'mother_birth_date': person.mother_dob,
        }
        
        # Format data for calculate method
        dob = data['birth_date'].strftime('%Y-%m-%d')
        
        # Format birth time if available
        dobtime = None
        if data['birth_time']:
            dobtime = data['birth_time'].strftime('%H:%M')
        
        # Format data for NumberPower.calculate
        np_data = {
            'dob': dob,
            'dobtime': dobtime,
            'twin': data['twin_type'],
            'fdob': data['father_birth_date'].strftime('%Y-%m-%d') if data['father_birth_date'] else None,
            'mdob': data['mother_birth_date'].strftime('%Y-%m-%d') if data['mother_birth_date'] else None,
        }
        
        # Calculate number result
        calculator = NumberPower()
        result = calculator.calculate(np_data)
        
        # Make result JSON serializable
        result = make_json_serializable(result)
        
        # Save the result to the person
        person.number_result = result
        person.save(update_fields=['number_result'])

class NumberPowerDetailView(LoginRequiredMixin, DetailView):
    """
    View for displaying a person's NumberPower result details.
    """
    model = Person
    template_name = 'number/result_detail.html'
    context_object_name = 'person'
    
    def get_queryset(self):
        # Restrict queryset to only the current user's records
        return Person.objects.filter(created_by=self.request.user)
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        person = self.get_object()
        
        # If number_result is missing, calculate and save it
        if not person.number_result:
            self.calculate_number_result(person)
            
        return context
        
    def calculate_number_result(self, person):
        """Calculate and save NumberPower result for a person."""
        if not person.birth_date:
            return
            
        # Prepare data for calculation
        data = {
            'name': person.name,
            'gender': person.gender.lower(),
            'birth_date': person.birth_date,
            'birth_time': person.birth_time,
            'twin_type': person.twin_type,
            'zi_hour_type': 'before_midnight' if person.birth_time and person.birth_time.hour == 23 else 'after_midnight',
            'is_adopted': False,  # Default value
            'father_birth_date': person.father_dob,
            'mother_birth_date': person.mother_dob,
        }
        
        # Format data for calculate method
        dob = data['birth_date'].strftime('%Y-%m-%d')
        
        # Format birth time if available
        dobtime = None
        if data['birth_time']:
            dobtime = data['birth_time'].strftime('%H:%M')
        
        # Format data for NumberPower.calculate
        np_data = {
            'dob': dob,
            'dobtime': dobtime,
            'twin': data['twin_type'],
            'fdob': data['father_birth_date'].strftime('%Y-%m-%d') if data['father_birth_date'] else None,
            'mdob': data['mother_birth_date'].strftime('%Y-%m-%d') if data['mother_birth_date'] else None,
        }
        
        # Calculate number result
        calculator = NumberPower()
        result = calculator.calculate(np_data)
        
        # Make result JSON serializable
        result = make_json_serializable(result)
        
        # Save the result to the person
        person.number_result = result
        person.save(update_fields=['number_result'])
