# students/views.py
from django.shortcuts import render, redirect, get_object_or_404
from .utils import generate_student_id
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.urls import reverse_lazy
from django.db.models import Q, Count
from django.http import JsonResponse, HttpResponse
from django.db import IntegrityError
import csv
import io
import pandas as pd
from datetime import datetime

from .models import Student, ParentGuardian
from academics.models import SchoolClass

# ========== MAIN VIEWS ==========

class StudentListView(LoginRequiredMixin, ListView):
    """List all students with search and filter"""
    model = Student
    template_name = 'students/student_list.html'
    context_object_name = 'students'
    paginate_by = 20
    
    SORT_FIELDS = {
        'name':       ('last_name', 'first_name'),
        '-name':      ('-last_name', '-first_name'),
        'id':         ('student_id',),
        '-id':        ('-student_id',),
        'class':      ('current_class__name', 'last_name'),
        '-class':     ('-current_class__name', 'last_name'),
        'admitted':   ('admission_date',),
        '-admitted':  ('-admission_date',),
        'age':        ('date_of_birth',),
        '-age':       ('-date_of_birth',),
    }

    def get_queryset(self):
        queryset = super().get_queryset().select_related('current_class')

        # Search
        search_query = self.request.GET.get('q')
        if search_query:
            queryset = queryset.filter(
                Q(first_name__icontains=search_query) |
                Q(last_name__icontains=search_query) |
                Q(student_id__icontains=search_query) |
                Q(home_address__icontains=search_query)
            )

        # Filter by class — 'none' shows students with no class assigned
        class_filter = self.request.GET.get('class')
        if class_filter == 'none':
            queryset = queryset.filter(current_class__isnull=True)
        elif class_filter:
            queryset = queryset.filter(current_class_id=class_filter)

        # Filter by status
        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)

        # Filter by gender
        gender_filter = self.request.GET.get('gender')
        if gender_filter:
            queryset = queryset.filter(gender=gender_filter)

        # Sorting
        sort = self.request.GET.get('sort', '-admitted')
        order_fields = self.SORT_FIELDS.get(sort, ('-admission_date',))
        queryset = queryset.order_by(*order_fields)

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        from datetime import date
        today = date.today()

        # Global stats (always full counts)
        context['total_students']  = Student.objects.count()
        context['active_students'] = Student.objects.filter(status='active').count()
        context['unassigned_count'] = Student.objects.filter(current_class__isnull=True).count()
        context['total_classes']   = SchoolClass.objects.filter(
            students__status='active'
        ).distinct().count()
        context['new_this_month']  = Student.objects.filter(
            admission_date__year=today.year,
            admission_date__month=today.month
        ).count()

        # Filtered result count (total across all pages)
        context['filtered_count'] = self.get_queryset().count()

        context['all_classes'] = SchoolClass.objects.all().order_by('name')
        context['current_sort'] = self.request.GET.get('sort', '-admitted')

        # Preserve all current GET params as a string for pagination links
        params = self.request.GET.copy()
        params.pop('page', None)
        context['query_string'] = params.urlencode()
        return context

class StudentDetailView(LoginRequiredMixin, DetailView):
    """View student details"""
    model = Student
    template_name = 'students/student_detail.html'
    context_object_name = 'student'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get attendance records
        from academics.models import Attendance
        context['attendance_records'] = Attendance.objects.filter(
            student=self.object
        ).order_by('-date')[:30]
        
        # Get invoice records
        from finance.models import Invoice
        context['invoice_records'] = Invoice.objects.filter(
            student=self.object
        ).order_by('-issue_date')[:10]
        
        # Get parents/guardians
        context['parents'] = ParentGuardian.objects.filter(student=self.object)
        
        return context

class StudentCreateView(LoginRequiredMixin, CreateView):
    """Create a new student"""
    model = Student
    fields = [
        'first_name', 'last_name', 'date_of_birth', 'gender',
        'home_address', 'quarter', 'city', 'phone_number', 'email',
        'emergency_contact_name', 'emergency_contact_phone', 'emergency_contact_relationship',
        'blood_group', 'allergies', 'chronic_conditions', 'medications',
        'admission_date', 'admission_class', 'current_class', 'status',
        'photo', 'birth_certificate', 'notes'
    ]
    template_name = 'students/student_form.html'
    success_url = reverse_lazy('student_list')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Add New Student'
        context['next_student_id'] = generate_student_id()  # preview for the form
        context['classes'] = SchoolClass.objects.all().order_by('name')
        return context
    
    def form_valid(self, form):
        student = form.save(commit=False)
        if not student.student_id:
            student.student_id = generate_student_id()
        student.save()
        messages.success(
            self.request,
            f'Student {student.first_name} {student.last_name} added. '
            f'ID: {student.student_id}'
        )
        return redirect('students:student_detail', pk=student.pk)

class StudentUpdateView(LoginRequiredMixin, UpdateView):
    """Update student information"""
    model = Student
    fields = [
        'first_name', 'last_name', 'date_of_birth', 'gender',
        'home_address', 'quarter', 'city', 'phone_number', 'email',
        'emergency_contact_name', 'emergency_contact_phone', 'emergency_contact_relationship',
        'blood_group', 'allergies', 'chronic_conditions', 'medications',
        'current_class', 'status', 'photo', 'notes'
    ]
    template_name = 'students/student_form.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'Edit {self.object.get_full_name()}'
        context['next_student_id'] = self.object.student_id  # show existing ID when editing
        context['classes'] = SchoolClass.objects.all().order_by('name')
        return context

    def form_valid(self, form):
        messages.success(self.request, 'Student updated successfully!')
        return super().form_valid(form)

    def get_success_url(self):
        return reverse_lazy('students:student_detail', kwargs={'pk': self.object.pk})

class StudentDeleteView(LoginRequiredMixin, DeleteView):
    """Delete a student"""
    model = Student
    success_url = reverse_lazy('student_list')
    template_name = 'students/student_confirm_delete.html'
    
    def delete(self, request, *args, **kwargs):
        student = self.get_object()
        messages.success(request, f'Student {student.get_full_name()} deleted successfully')
        return super().delete(request, *args, **kwargs)

# ========== PARENT/GUARDIAN VIEWS ==========

class ParentListView(LoginRequiredMixin, ListView):
    """List all parents/guardians"""
    model = ParentGuardian
    template_name = 'students/parent_list.html'
    context_object_name = 'parents'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = super().get_queryset().select_related('student')
        
        search_query = self.request.GET.get('q')
        if search_query:
            queryset = queryset.filter(
                Q(first_name__icontains=search_query) |
                Q(last_name__icontains=search_query) |
                Q(phone__icontains=search_query) |
                Q(student__first_name__icontains=search_query)
            )
        
        return queryset.order_by('last_name', 'first_name')

class ParentDetailView(LoginRequiredMixin, DetailView):
    """View parent/guardian details"""
    model = ParentGuardian
    template_name = 'students/parent_detail.html'
    context_object_name = 'parent'

class ParentCreateView(LoginRequiredMixin, CreateView):
    """Add a new parent/guardian"""
    model = ParentGuardian
    fields = '__all__'
    template_name = 'students/parent_form.html'
    success_url = reverse_lazy('parent_list')

class ParentUpdateView(LoginRequiredMixin, UpdateView):
    """Update parent/guardian information"""
    model = ParentGuardian
    fields = '__all__'
    template_name = 'students/parent_form.html'
    success_url = reverse_lazy('parent_list')

# ========== IMPORT/EXPORT FUNCTIONS ==========

def export_students_csv(request):
    """Export students to CSV"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="students_export.csv"'
    
    writer = csv.writer(response)
    writer.writerow([
        'Student ID', 'First Name', 'Last Name', 'Date of Birth', 'Gender',
        'Class', 'Admission Date', 'Status', 'Parent Name', 'Parent Phone'
    ])
    
    students = Student.objects.select_related('current_class').prefetch_related('parents').all()
    
    for student in students:
        parent = student.parents.filter(is_primary_contact=True).first()
        parent_name = f"{parent.first_name} {parent.last_name}" if parent else ''
        parent_phone = parent.phone if parent else ''
        
        writer.writerow([
            student.student_id,
            student.first_name,
            student.last_name,
            student.date_of_birth,
            student.get_gender_display(),
            student.current_class.name if student.current_class else '',
            student.admission_date,
            student.status,
            parent_name,
            parent_phone
        ])
    
    return response

def import_students_csv(request):
    """Import students from CSV"""
    if request.method == 'POST' and request.FILES.get('file'):
        csv_file = request.FILES['file']
        
        if not csv_file.name.endswith('.csv'):
            messages.error(request, 'Please upload a CSV file')
            return redirect('students:import_students_csv')
        
        try:
            decoded_file = csv_file.read().decode('utf-8-sig')
            io_string = io.StringIO(decoded_file)
            reader = csv.DictReader(io_string)
            
            imported = 0
            errors = []
            
            for row_num, row in enumerate(reader, start=2):
                try:
                    # Normalise headers: strip whitespace, lowercase — handles any capitalisation
                    row_norm = {k.strip().lower(): (v or '').strip() for k, v in row.items()}

                    first_name = (
                        row_norm.get('first name') or row_norm.get('firstname') or
                        row_norm.get('first_name') or row_norm.get('nom') or ''
                    )
                    last_name = (
                        row_norm.get('last name') or row_norm.get('lastname') or
                        row_norm.get('last_name') or row_norm.get('prenom') or
                        row_norm.get('prénom') or ''
                    )

                    if not first_name or not last_name:
                        errors.append(f"Row {row_num}: Missing first or last name")
                        continue
                    
                    # Resolve class — normalised key lookup
                    class_name = (
                        row_norm.get('class') or row_norm.get('classe') or
                        row_norm.get('current class') or ''
                    )
                    override_class_id = request.POST.get('class_id', '').strip()
                    current_class = None

                    if override_class_id:
                        # Staff selected a class in the form — use it for all rows
                        current_class = SchoolClass.objects.filter(pk=override_class_id).first()
                    elif class_name:
                        current_class = SchoolClass.objects.filter(
                            Q(name__icontains=class_name) | Q(code__icontains=class_name)
                        ).first()
                        if not current_class:
                            errors.append(
                                f"Row {row_num}: Class '{class_name}' not found — "
                                f"check the class code matches exactly (e.g. CL6-A, CM2-A)"
                            )
                            continue
                    else:
                        # No class in CSV and no override — block the row
                        errors.append(
                            f"Row {row_num}: {first_name} {last_name} — "
                            f"no Class specified. Add a Class column to the CSV "
                            f"or select a target class in the import form."
                        )
                        continue
                    
                    # Parse date
                    dob_str = row.get('Date of Birth', '')
                    date_of_birth = None
                    if dob_str:
                        try:
                            date_of_birth = datetime.strptime(dob_str, '%Y-%m-%d').date()
                        except ValueError:
                            try:
                                date_of_birth = datetime.strptime(dob_str, '%d/%m/%Y').date()
                            except ValueError:
                                pass
                    
                    # Auto-generate unique student ID — staff never supply this
                    student_id = generate_student_id()

                    # Create student (never use get_or_create — always insert fresh)
                    student = Student.objects.create(
                        student_id=student_id,
                        first_name=first_name,
                        last_name=last_name,
                        date_of_birth=date_of_birth,
                        gender=row.get('Gender', 'U')[:1].upper(),
                        current_class=current_class,
                        admission_date=datetime.now().date(),
                        status='active',
                        imported_from=csv_file.name,
                    )
                    imported += 1

                    # Create parent/guardian if provided — normalised key lookup
                    parent_name = (
                        row_norm.get('parent name') or row_norm.get('parent') or
                        row_norm.get('guardian name') or row_norm.get('guardian') or ''
                    )
                    parent_phone = (
                        row_norm.get('parent phone') or row_norm.get('phone') or
                        row_norm.get('telephone') or row_norm.get('contact') or ''
                    ).replace(' ', '').replace('-', '')

                    if parent_name:
                        # Split "DITCHEWI CHRISTIAN" → first=DITCHEWI last=CHRISTIAN
                        # If only one word, use it as last name
                        parts = parent_name.split(None, 1)  # split on first space only
                        p_first = parts[0] if len(parts) > 1 else ''
                        p_last  = parts[1] if len(parts) > 1 else parts[0]

                        ParentGuardian.objects.create(
                            student=student,
                            first_name=p_first,
                            last_name=p_last,
                            phone=parent_phone or '0000000000',  # phone is required
                            relationship='parent',
                            is_primary_contact=True,
                            receive_sms=True,
                        )
                    
                except Exception as e:
                    errors.append(f"Row {row_num}: {str(e)}")
            
            if errors:
                messages.warning(request, f"Imported {imported} students with {len(errors)} errors")
                for error in errors[:5]:
                    messages.error(request, error)
            else:
                messages.success(request, f"Successfully imported {imported} students!")
            
        except Exception as e:
            messages.error(request, f"Error processing file: {str(e)}")
        
        return redirect('students:student_list')
    
    # GET request - show import form
    classes = SchoolClass.objects.all()
    return render(request, 'students/import.html', {'classes': classes})

def download_student_sample(request):
    """Download sample CSV template"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="student_sample.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['First Name', 'Last Name', 'Date of Birth', 'Gender', 'Class', 'Parent Name', 'Parent Phone'])
    writer.writerow(['John', 'Doe', '2015-05-15', 'M', 'CL5-A', 'Peter Doe', '677889900'])
    writer.writerow(['Jane', 'Smith', '2015-08-22', 'F', 'CL5-A', 'Mary Smith', '699123456'])
    
    return response

def download_class6_sample(request):
    """Download Class 6 style sample"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="class6_sample.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['NAME', 'DATE OF BIRTH', 'PLACE OF BIRTH', 'SEX'])
    writer.writerow(['ABUEMBAIMBI WISDOM NJI', '22/10/2015', 'DOUALA', 'M'])
    writer.writerow(['ADIGOUM ADEBIAYE NAOMI DEBORAH', '07/07/2015', 'DOUALA', 'F'])
    
    return response

def import_class_from_excel(request, sheet_name):
    """Import a specific class from Excel"""
    try:
        from .import_class_data import import_student_data
        result = import_student_data(
            excel_file="Rapha-Bethel BNPS.xlsx",
            sheet_name=sheet_name,
            class_name=sheet_name
        )
        
        if result['errors']:
            messages.warning(request, f"Imported {result['imported']} students with {len(result['errors'])} errors")
        else:
            messages.success(request, f"Successfully imported {result['imported']} students from {sheet_name}!")
        
    except Exception as e:
        messages.error(request, f"Error importing {sheet_name}: {str(e)}")
    
    return redirect('students:student_list')

def import_all_classes(request):
    """Import all classes from Excel"""
    try:
        from .import_all_classes import import_all_classes
        total = import_all_classes()
        messages.success(request, f"Successfully imported {total} students across all classes!")
    except Exception as e:
        messages.error(request, f"Error importing classes: {str(e)}")
    
    return redirect('students:student_list')

# ========== API ENDPOINTS ==========

def get_student_stats(request):
    """API endpoint for student statistics"""
    stats = {
        'total': Student.objects.count(),
        'active': Student.objects.filter(status='active').count(),
        'by_class': list(Student.objects.values('current_class__name').annotate(count=Count('id'))),
        'by_gender': list(Student.objects.values('gender').annotate(count=Count('id'))),
        'by_status': list(Student.objects.values('status').annotate(count=Count('id'))),
    }
    return JsonResponse(stats)