# DENTALCLINICSYSTEM/appointments/models.py

from django.db import models
from patients.models import Patient 
from doctors.models import Doctor   
from django.utils import timezone   

class Appointment(models.Model):
    # CHANGED: on_delete policy to PROTECT to prevent accidental data loss
    patient = models.ForeignKey(Patient, on_delete=models.PROTECT, related_name='appointments')
    doctor = models.ForeignKey(Doctor, on_delete=models.PROTECT, related_name='appointments')

    appointment_datetime = models.DateTimeField(default=timezone.now) 
    reason = models.TextField(blank=True, null=True, help_text="Reason for the visit")

    STATUS_CHOICES = [
        ('SCH', 'Scheduled'),
        ('CNF', 'Confirmed'),
        ('CMP', 'Completed'),
        ('CAN', 'Cancelled'),
        ('NOS', 'No Show'),
    ]
    status = models.CharField(
        max_length=3,
        choices=STATUS_CHOICES,
        default='SCH' 
    )

    notes = models.TextField(blank=True, null=True, help_text="Internal notes about the appointment")

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        formatted_datetime = self.appointment_datetime.strftime("%Y-%m-%d %I:%M %p")
        return f"Appointment for {self.patient.name} with Dr. {self.doctor.name} on {formatted_datetime}"

    class Meta:
        ordering = ['appointment_datetime']


from django import forms
from .models import Appointment
from patients.models import Patient 
from doctors.models import Doctor   

class AppointmentForm(forms.ModelForm):
    patient = forms.ModelChoiceField(
        queryset=Patient.objects.all().order_by('name'),
        # Add 'select2-enable' class to the widget
        widget=forms.Select(attrs={'class': 'form-control select2-enable'})
    )
    doctor = forms.ModelChoiceField(
        queryset=Doctor.objects.all().order_by('name'),
        # Add 'select2-enable' class to the widget
        widget=forms.Select(attrs={'class': 'form-control select2-enable'})
    )
    appointment_datetime = forms.DateTimeField(
        widget=forms.DateTimeInput(attrs={'type': 'datetime-local', 'class': 'form-control'}),
        input_formats=['%Y-%m-%dT%H:%M']
    )

    class Meta:
        model = Appointment
        fields = [
            'patient', 'doctor', 'appointment_datetime', 
            'reason', 'status', 'notes'
        ]
        widgets = {
            'reason': forms.Textarea(attrs={'rows': 3, 'class': 'form-control', 'placeholder': 'Reason for visit'}),
            'status': forms.Select(attrs={'class': 'form-control'}),
            'notes': forms.Textarea(attrs={'rows': 3, 'class': 'form-control', 'placeholder': 'Internal notes'}),
        }
        labels = {
            'appointment_datetime': 'Appointment Date and Time',
            'reason': 'Reason for Visit',
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field_name, field in self.fields.items():
            if 'class' not in field.widget.attrs:
                 field.widget.attrs.update({'class': 'form-control'})

# appointments/views.py

from django.http import JsonResponse
from django.urls import reverse
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.utils import timezone
from datetime import timedelta

from .models import Appointment
from .forms import AppointmentForm
from dental_records.models import DentalRecord, Prescription
from patients.models import Patient
from billing.models import Invoice
from staff.decorators import role_required # Make sure this is imported

# --- API VIEW (For the main calendar) ---
@login_required
def appointment_api_view(request):
    user = request.user
    
    # FIX: Reordered logic to check for superuser first
    # 1. Superuser sees all appointments.
    if user.is_superuser:
        all_appointments = Appointment.objects.all().select_related('patient', 'doctor')
    # 2. If not superuser, check for a doctor profile.
    elif hasattr(user, 'doctor_profile'):
        all_appointments = Appointment.objects.filter(doctor=user.doctor_profile).select_related('patient', 'doctor')
    # 3. If not a doctor, check for a staff profile with manager/receptionist role.
    elif hasattr(user, 'staff_profile') and user.staff_profile.role in ['MANAGER', 'RECEP']:
        all_appointments = Appointment.objects.all().select_related('patient', 'doctor')
    # 4. Otherwise, they see no appointments.
    else:
        all_appointments = Appointment.objects.none()

    events = []
    for appointment in all_appointments:
        events.append({
            'title': appointment.patient.name,
            'start': appointment.appointment_datetime.isoformat(),
            'end': (appointment.appointment_datetime + timedelta(minutes=45)).isoformat(),
            'url': reverse('appointments:appointment_detail', args=[appointment.id]),
            'color': '#28a745' if appointment.status == 'CMP' else '#17a2b8',
            'extendedProps': {
                'patient': appointment.patient.name,
                'doctor': f"Dr. {appointment.doctor.name}",
                'time': appointment.appointment_datetime.strftime('%I:%M %p'),
                'reason': appointment.reason or 'No reason provided'
            }
        })
    return JsonResponse(events, safe=False)

# --- Regular Views ---
@login_required
def appointment_list_view(request):
    user = request.user
    
    # FIX: Reordered logic to check for superuser first
    # 1. Superuser and relevant staff see all appointments.
    if user.is_superuser or (hasattr(user, 'staff_profile') and user.staff_profile.role in ['MANAGER', 'RECEP']):
         all_appointments = Appointment.objects.order_by('-appointment_datetime')
    # 2. If not staff, check for a doctor profile.
    elif hasattr(user, 'doctor_profile'):
        all_appointments = Appointment.objects.filter(doctor=user.doctor_profile).order_by('-appointment_datetime')
    # 3. Otherwise, they see no appointments.
    else:
        all_appointments = Appointment.objects.none()

    context = {'appointments_list': all_appointments, 'page_title': 'List of Appointments'}
    return render(request, 'appointments/appointment_list.html', context)

@login_required
@role_required(['MANAGER', 'RECEP', 'DOCTOR']) # FIX: Added security decorator
def schedule_appointment_view(request):
    initial_data = {}
    patient_id = request.GET.get('patient_id')
    if patient_id:
        try:
            patient = Patient.objects.get(id=patient_id)
            initial_data['patient'] = patient
        except Patient.DoesNotExist:
            pass

    if request.method == 'POST':
        form = AppointmentForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, 'Appointment scheduled successfully!')
            return redirect('appointments:appointment_list')
    else:
        form = AppointmentForm(initial=initial_data)

    context = {
        'form': form,
        'page_title': 'Schedule New Appointment'
    }
    return render(request, 'appointments/schedule_appointment.html', context)

@login_required
# FIX: Added security decorator. Detail view logic should be handled within the view.
def appointment_detail_view(request, appointment_id):
    appointment = get_object_or_404(Appointment, id=appointment_id)
    user = request.user

    # Security Check
    is_staff_or_superuser = user.is_superuser or (hasattr(user, 'staff_profile') and user.staff_profile.role in ['MANAGER', 'RECEP'])
    is_the_doctor = hasattr(user, 'doctor_profile') and user.doctor_profile == appointment.doctor

    if not (is_staff_or_superuser or is_the_doctor):
        messages.error(request, "You do not have permission to view this appointment.")
        return redirect('dashboard')

    dental_record = None
    try:
        dental_record = appointment.dental_record 
    except (DentalRecord.DoesNotExist, AttributeError):
        pass

    context = {
        'appointment': appointment,
        'dental_record': dental_record,
        'page_title': f"Appointment Details for {appointment.patient.name}"
    }
    return render(request, 'appointments/appointment_detail.html', context)

@login_required
@role_required(['MANAGER', 'RECEP', 'DOCTOR']) # FIX: Added security decorator
def edit_appointment_view(request, appointment_id):
    appointment_to_edit = get_object_or_404(Appointment, id=appointment_id)
    if request.method == 'POST':
        form = AppointmentForm(request.POST, instance=appointment_to_edit)
        if form.is_valid():
            form.save()
            messages.success(request, 'Appointment details updated successfully!')
            return redirect('appointments:appointment_detail', appointment_id=appointment_to_edit.id)
    else:
        form = AppointmentForm(instance=appointment_to_edit)
    context = {'form': form, 'appointment': appointment_to_edit, 'page_title': f"Edit Appointment"}
    return render(request, 'appointments/edit_appointment.html', context)

@login_required
@role_required(['MANAGER', 'RECEP']) # Only Managers and Receptionists should delete
def delete_appointment_view(request, appointment_id):
    appointment_to_delete = get_object_or_404(Appointment, id=appointment_id)
    if request.method == 'POST':
        appointment_to_delete.delete()
        messages.success(request, 'Appointment deleted successfully!')
        return redirect('appointments:appointment_list')
    context = {'appointment': appointment_to_delete, 'page_title': f"Confirm Delete"}
    return render(request, 'appointments/appointment_confirm_delete.html', context)


@login_required
def print_summary_view(request, appointment_id):
    appointment = get_object_or_404(Appointment, pk=appointment_id)
    # Note: Consider adding security checks to print views as well
    context = {
        'appointment': appointment,
        'page_title': f'Summary for {appointment.patient.name} on {appointment.appointment_datetime.date()}'
    }
    # ... (rest of the view is unchanged)
    try:
        invoice = appointment.invoice
        context['invoice'] = invoice
        context['invoice_items'] = invoice.invoice_items.all()
    except (Invoice.DoesNotExist, AttributeError):
        context['invoice'] = None
        context['invoice_items'] = None

    try:
        prescription = appointment.dental_record.prescription
        context['prescription'] = prescription
        context['prescription_items'] = prescription.items.all()
    except (DentalRecord.DoesNotExist, Prescription.DoesNotExist, AttributeError):
        context['prescription'] = None
        context['prescription_items'] = None
        
    return render(request, 'appointments/print_summary.html', context)

@login_required
def print_bill_summary_view(request, appointment_id):
    appointment = get_object_or_404(
        Appointment.objects.select_related('patient', 'doctor'), 
        pk=appointment_id
    )
    # Note: Consider adding security checks to print views as well
    context = {
        'appointment': appointment,
        'page_title': f'Bill for {appointment.patient.name} on {appointment.appointment_datetime.date()}'
    }
    # ... (rest of the view is unchanged)
    try:
        invoice = Invoice.objects.get(appointment=appointment)
        invoice_items = invoice.invoice_items.all()
        services = invoice_items.filter(service__isnull=False)
        products = invoice_items.filter(product__isnull=False)
        context['invoice'] = invoice
        context['services_list'] = services
        context['products_list'] = products
    except Invoice.DoesNotExist:
        context['invoice'] = None
        context['services_list'] = []
        context['products_list'] = []

    try:
        prescription = appointment.dental_record.prescription
        context['prescription'] = prescription
        context['prescription_items'] = prescription.items.all()
    except (DentalRecord.DoesNotExist, Prescription.DoesNotExist, AttributeError):
        context['prescription'] = None
        context['prescription_items'] = []
        
    return render(request, 'appointments/print_bill_summary.html', context)

# appointments/urls.py

from django.urls import path
from . import views

app_name = 'appointments'

urlpatterns = [
    # API endpoint for the calendar
    path('api/all/', views.appointment_api_view, name='appointment_api'),

    # Regular appointment views
    path('', views.appointment_list_view, name='appointment_list'),
    path('schedule/', views.schedule_appointment_view, name='schedule_appointment'),
    path('<int:appointment_id>/', views.appointment_detail_view, name='appointment_detail'),
    path('<int:appointment_id>/edit/', views.edit_appointment_view, name='edit_appointment'),
    path('<int:appointment_id>/delete/', views.delete_appointment_view, name='delete_appointment'),

    # Existing print summary
    path('<int:appointment_id>/print-summary/', views.print_summary_view, name='print_summary'),
    
    # NEW: URL for the comprehensive bill summary
    path('<int:appointment_id>/print-bill-summary/', views.print_bill_summary_view, name='print_bill_summary'),
]

from django.contrib import admin
from .models import Appointment # Import your Appointment model

class AppointmentAdmin(admin.ModelAdmin):
    list_display = ('patient', 'doctor', 'appointment_datetime', 'status', 'reason')
    list_filter = ('status', 'doctor', 'appointment_datetime')
    search_fields = ('patient__name', 'doctor__name', 'reason')
    list_per_page = 20 # Show 20 appointments per page in admin

# Register your models here.
admin.site.register(Appointment, AppointmentAdmin) # Register Appointment with its custom admin options



from django.test import TestCase

# Create your tests here.


Analyse all the individual files for appointments app and understand its purpose , fix errors and give full updated codes