from django.shortcuts import render
from django.shortcuts import render, redirect
from .models import *
from .forms import *
from django.utils.timezone import localtime, now
from django.views import View
from django.contrib import messages
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.db.models import Q
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib.auth import get_user_model
from django.shortcuts import get_object_or_404
from django.http import HttpResponseForbidden
from datetime import date
from django.contrib.auth.views import LoginView
from django.contrib.auth import authenticate, login, get_user_model
from django.contrib import messages
from django.shortcuts import redirect
from medicine.models import *
import requests
from django.views.decorators.http import require_GET

BANGLA_TO_ENG_DIGIT = str.maketrans("০১২৩৪৫৬৭৮৯", "0123456789")
User = get_user_model()

def hoshomeview(request):
    query = HActiviti.objects.all().order_by('-created_at')
    now = localtime()  # Local time based on TIME_ZONE in settings.py

    availabele_doctors = Availability.objects.filter(
        Q(date__gt=now.date()) |
        Q(date=now.date(), start_time__gt=now.time())
    ).order_by('date', 'start_time')

    return render(request, 'hhome.html', {
        'query': query,
        'available_doctors': availabele_doctors
    })

def aboutview(request):
    return render(request, 'about.html')

def missionview(request):
    return render(request, 'hmission.html')

def facilitiesview(request):
    return render(request, 'facilities.html')

def hcontactview(request):
    return render(request, 'hcontact.html')

def hdoctorview(request):
    doctors = Doctor.objects.filter(status='Yes')
    return render(request, 'doctors.html', {'doctors': doctors})

def hactivitiesview(request):
    query = HActiviti.objects.all().order_by('-created_at')
    return render(request, 'hactivities.html', {'query': query})

def hactivitydetailview(request, id):
    query = HActiviti.objects.get(id=id)
    return render(request, 'hactivitydetails.html', {'query': query})

@login_required
def custom_redirect(request):
    user = request.user
    if request.user.is_superuser:
        return redirect('/superuser/dashboard/')
    if request.user.is_staff and request.user.id == 752:
        return redirect('/superuser/dashboard/')
    elif user.role == 'Patient':
        return redirect('/patient/dashboard/')
    elif user.role == 'Doctor':
        return redirect('/doctor/dashboard/')

    # Default redirect if role is not found
    return redirect('/')


def send_otp_to_mobile(mobile, otp_code):
    message = f"Your OTP is {otp_code}"
    url = "https://bulksmsbd.net/api/smsapi"

    payload = {
        'api_key': 'huLwVgUkvNwu6FUxvprX',
        'senderid': '8809604904703',
        'number': mobile,
        'message': message
    }
    response = requests.post(url, data=payload)
    print(response.status_code)
    print(response.text)

class CustomerRegistrationView(View):
    def get(self, request):
        form = CustomerRegistrationForm()
        return render(request, 'register.html', {'form':form})
    def post(self, request):
        form = CustomerRegistrationForm(request.POST)
        if form.is_valid():
            mobile = form.cleaned_data['mobile']
            name = form.cleaned_data['name']
            role = form.cleaned_data['role']
            dob = form.cleaned_data['dob']
            gender = form.cleaned_data['gender']
            if User.objects.filter(mobile=mobile, dob=dob).exists():
                messages.warning(request, "এই মোবাইল এবং জন্মতারিখ দিয়ে ইতিমধ্যে একাউন্ট খোলা হয়েছে। অন্য মোবাইল নম্বর ব্যবহার করুন।")
            else:
                otp_code = OTP.generate_otp()
                OTP.objects.create(mobile=mobile, code=otp_code)
                send_otp_to_mobile(mobile, otp_code)
                request.session['register_mobile'] = mobile
                request.session['register_name'] = name
                request.session['register_role'] = role
                request.session['register_dob'] = dob.isoformat()
                request.session['register_gender'] = gender
                return redirect('verify_registration_otp')
            form = CustomerRegistrationForm()
            return redirect('/login/')
        else:
            messages.warning(request, "ত্রুটি থাকার কারণে রেজিস্ট্রেশন সম্পন্ন হয় নি। পুনরায় চেষ্টা করুন।")
            return render(request, 'register.html', {'form': form})

def verify_registration_otp(request):
    r = True
    mobile = request.session.get('register_mobile')
    name = request.session.get('register_name')
    role = request.session.get('register_role')
    dob_str = request.session.get('register_dob')
    dob = date.fromisoformat(dob_str) if dob_str else None
    gender = request.session.get('register_gender')
    if request.method == "POST":
        code = request.POST.get('otp')
        otp_obj = OTP.objects.filter(mobile=mobile, code=code).last()
        if otp_obj and otp_obj.is_valid():
            user = User.objects.create_user(mobile=mobile, name=name, role=role, dob=dob, gender=gender)
            login(request, user)
            OTP.objects.filter(mobile=mobile).delete()
            return redirect('hoshome')
        else:
            messages.warning(request, "Invalid or expired OTP")
    return render(request, "verify_otp.html", {'r': r})

def doctor_login_view(request):
    if request.method == "POST":
        mobile = request.POST.get("mobile", "").strip().translate(BANGLA_TO_ENG_DIGIT)
        dob = request.POST.get("dob", "")

        if not re.fullmatch(r'\d{11}', mobile):
            messages.warning(request, "মোবাইল নম্বর অবশ্যই ১১ সংখ্যার হতে হবে")
            return render(request, "login.html")

        if User.objects.filter(mobile=mobile, dob=dob).exists():
            user = User.objects.get(mobile=mobile, dob=dob)
            login(request, user)
            return redirect("hoshome")
        else:
            messages.warning(request, "এই মোবাইল নম্বর এবং জন্মতারিখের সাথে কোনো ব্যবহারকারী পাওয়া যায়নি।")
    return render(request, "login.html")

def login_view(request):
    if request.method == "POST":
        mobile = request.POST.get("mobile", "").strip().translate(BANGLA_TO_ENG_DIGIT)
        dob = request.POST.get("dob", "")

        if not re.fullmatch(r'\d{11}', mobile):
            messages.warning(request, "মোবাইল নম্বর অবশ্যই ১১ সংখ্যার হতে হবে")
            return render(request, "login.html")

        if User.objects.filter(mobile=mobile, dob=dob).exists():
            otp_code = OTP.generate_otp()
            OTP.objects.create(mobile=mobile, code=otp_code)
            send_otp_to_mobile(mobile, otp_code)
            request.session['login_mobile'] = mobile
            request.session['login_dob'] = dob
            return redirect("verify_login_otp")
        else:
            messages.warning(request, "এই মোবাইল নম্বর এবং জন্মতারিখের সাথে কোনো ব্যবহারকারী পাওয়া যায়নি।")
    return render(request, "login.html")

def verify_login_otp(request):
    l = True
    mobile = request.session.get('login_mobile')
    dob = request.session.get('login_dob')
    if request.method == "POST":
        code = request.POST.get("otp")
        otp_obj = OTP.objects.filter(mobile=mobile, code=code).last()
        if otp_obj and otp_obj.is_valid():
            user = User.objects.get(mobile=mobile, dob=dob)
            login(request, user)
            OTP.objects.filter(mobile=mobile).delete()
            return redirect("hoshome")
        else:
            messages.warning(request, "Invalid or expired OTP.")
    return render(request, "verify_otp.html", {'l': l})
    
@login_required    
def seeprofile(request):
    user = request.user
    today = date.today()
    age = today.year - user.dob.year - ((today.month, today.day) < (user.dob.month, user.dob.day))
    return render(request, 'profile.html', {'age': age})


@method_decorator(login_required, name='dispatch')
class EditProfileview(View):
    def get(self, request):
        customer = request.user
        initial_data = {
            'role': customer.role,
            'gender': customer.gender,
            'name': customer.name,
            'dob': customer.dob,
            'address': customer.address,
            'mobile': customer.mobile,
            'profile_pic': customer.profile_pic,
        }
        form = CustomerProfileForm(instance=request.user, initial=initial_data)
        return render(request, 'editprofile.html', {'form': form, 'pic': customer.profile_pic})

    def post(self, request):
        form = CustomerProfileForm(request.POST, request.FILES, instance=request.user)
        if form.is_valid():
            form.save()
            messages.success(request, "Profile updated successfully.")
            return redirect('seeprofile') 
        else:
            messages.warning(request, "There was an error updating your profile.")
        return render(request, 'editprofile.html', {'form': form})
    

@login_required
def superuser_dashboard(request):
    appointments = Appointment.objects.filter(available__date=localtime().date()).order_by('-created_at')
    prescriptions = Prescription.objects.all().order_by('-prescribed_date')
    context = {
        'appointments': appointments,
        'prescriptions': prescriptions,
    }
    return render(request, 'superuser_dashboard.html', context)

@login_required
def patient_dashboard(request):
    now = localtime() 
    # Ensure the logged-in user is a patient
    if request.user.role != 'Patient':
        return HttpResponseForbidden("Access denied.")

    patient = User.objects.get(mobile=request.user.mobile, dob=request.user.dob)
    doctors = Doctor.objects.all()
    doc_availability = Availability.objects.filter(
        Q(date__gt=now.date()) |
        Q(date=now.date(), start_time__gt=now.time())
    ).order_by('date', 'start_time')
    appointments = Appointment.objects.filter(patient=patient)
    tests = Test.objects.filter(appointment__in=appointments)
    prescriptions = Prescription.objects.filter(appointment__in=appointments)
    context = {
        'doctors': doctors,
        'appointment_map': appointments,
        'doc_av': doc_availability,
        'tests': tests,
        'prescriptions': prescriptions,
    }
    return render(request, 'patient_dashboard.html', context)

@login_required
def book_appointment(request, doctor_id, availability_id):
    # Allow patients to book appointments only if they are assigned the 'Patient' role
    if request.user.role != 'Patient':
        return HttpResponseForbidden("Access denied.")

    doctor = get_object_or_404(Doctor, id=doctor_id)
    availability = get_object_or_404(Availability, id=availability_id)

    # Check if the patient has already booked an appointment
    appointment = Appointment.objects.filter(patient=request.user, doctor=doctor, available=availability).first()

    # Handle the booking logic when the form is submitted (POST request)
    if request.method == 'POST':
        notes = request.POST.get('notes')  # Get the notes from the form
        try:
        # If the patient is updating an existing appointment, update the note
            if appointment:
                appointment.notes = notes
                appointment.save()
                return redirect('patient_dashboard')  # Redirect to the dashboard after updating
            else:
                # Ensure the patient is not booking an appointment for the same doctor and date
                if Appointment.objects.filter(patient=request.user, doctor=doctor, available__date=availability.date).exists():
                    return HttpResponseForbidden("You already have an appointment with this doctor on the selected date.")

                # Create a new appointment with the provided notes
                Appointment.objects.create(
                    doctor=doctor,
                    patient=request.user,
                    available=availability,
                    notes=notes  # Save the patient's notes
                )
                return redirect('patient_dashboard')  # Redirect to the dashboard after booking
        except ValidationError as e:
            messages.error(request, e.message)
    # If the patient already has an appointment, show the existing notes
    context = {
        'doctor': doctor,
        'availability': availability,
        'appointment': appointment,  # Pass the appointment if it exists
    }

    return render(request, 'book_appointment.html', context)

@login_required
def delete_appointment(request, doctor_id, availability_id):
    # Ensure the logged-in user is a patient and the appointment belongs to them
    if request.user.role != 'Patient':
        return HttpResponseForbidden("Access denied.")
    
    # Get the doctor and availability objects
    doctor = get_object_or_404(Doctor, id=doctor_id)
    availability = get_object_or_404(Availability, id=availability_id)
    
    # Find the appointment that the patient has booked for the given doctor and availability
    appointment = Appointment.objects.filter(
        patient=request.user,
        doctor=doctor,
        available=availability
    ).first()

    if not appointment:
        return HttpResponseForbidden("You do not have an appointment with this doctor at the selected time.")
    
    # Delete the appointment
    appointment.delete()

    return redirect('patient_dashboard')  # Redirect to the patient dashboard after deletion


@login_required
def upload_test_report(request, id):
    # Allow patients to upload reports for their prescribed tests
    test = get_object_or_404(Test, id=id)

    if request.user != test.appointment.patient:
        return HttpResponseForbidden("You do not have permission to upload a report for this test.")

    if request.method == 'POST':
        report_file = request.FILES.get('report_file')
        notes = request.POST.get('notes')

        TestReport.objects.create(
            test=test,
            uploaded_by=request.user,
            report_file=report_file,
            notes=notes,
        )
        test.status = 'Uploaded'
        test.save()

        return redirect('patient_dashboard')

    return render(request, 'upload_test_report.html', {'test': test})

@login_required
def doctor_dashboard(request):
    # Ensure the logged-in user is a doctor
    if request.user.role != 'Doctor':
        return HttpResponseForbidden("Access denied.")   
    vendor = MyUser.objects.get(mobile=request.user.mobile, dob=request.user.dob)
    doctor = Doctor.objects.get(vendor=vendor)
    appointments = Appointment.objects.filter(doctor=doctor).order_by('-created_at')
    for appointment in appointments:
        appointment.prescription_exists = Prescription.objects.filter(appointment=appointment).exists()
    tests = Test.objects.filter(appointment__in=appointments)
    reports = TestReport.objects.filter(test__in=tests)
    context = {
        'appointments': appointments,
        'reports': reports,
    }
    return render(request, 'doctor_dashboard.html', context)


@login_required
def prescription_detail(request, prescription_id):
    # Allow only doctors to view prescriptions or the patients who are related to the prescription
    prescription = get_object_or_404(Prescription, id=prescription_id)
    
    # Check if the logged-in user is allowed to view the prescription (doctor or patient)
    if request.user.role != 'Doctor' and prescription.appointment.patient.role != request.user.role:
        return HttpResponseForbidden("Access denied.")

    # Fetch all the tests related to the prescription
    tests = Test.objects.filter(appointment=prescription.appointment)

    context = {
        'prescription': prescription,
        'tests': tests,
    }
    
    return render(request, 'prescription_detail.html', context)


@login_required
def create_or_edit_prescription(request, appointment_id=None, prescription_id=None):
    prescription = None
    tests = []

    if prescription_id:
        prescription = get_object_or_404(Prescription, id=prescription_id)
        tests = Test.objects.filter(appointment=prescription.appointment)

        # অনুমোদন যাচাই
        if request.user.role != 'Doctor' and prescription.appointment.patient != request.user.role:
            return HttpResponseForbidden("অনুমতি নেই।")

        appointment = prescription.appointment
    else:
        appointment = get_object_or_404(Appointment, id=appointment_id)
    if request.method == "POST":
        # সাধারণ তথ্য সংগ্রহ
        symptoms = request.POST.get('symptoms')
        on_examination = request.POST.get('on_examination')
        instructions = request.POST.get('instructions')
        weight = request.POST.get('weight')
        temperature = request.POST.get('temperature')
        blood_pressure = request.POST.get('blood_pressure')
        if request.user.vendor_doctor.eye_specialist:
            right_sph_distance = request.POST.get('right_sph_distance')
            right_cyl_distance = request.POST.get('right_cyl_distance')
            right_axis_distance = request.POST.get('right_axis_distance')
            right_corrected_distance = request.POST.get('right_corrected_distance')
            right_sph_near = request.POST.get('right_sph_near')
            right_cyl_near = request.POST.get('right_cyl_near')
            right_axis_near = request.POST.get('right_axis_near')
            right_corrected_near = request.POST.get('right_corrected_near')
            left_sph_distance = request.POST.get('left_sph_distance')
            left_cyl_distance = request.POST.get('left_cyl_distance')
            left_axis_distance = request.POST.get('left_axis_distance')
            left_corrected_distance = request.POST.get('left_corrected_distance')
            left_sph_near = request.POST.get('left_sph_near')
            left_cyl_near = request.POST.get('left_cyl_near')
            left_axis_near = request.POST.get('left_axis_near')
            left_corrected_near = request.POST.get('left_corrected_near')
            unifocal='unifocal' in request.POST
            bifocal='bifocal' in request.POST
            cr_39='cr_39' in request.POST
            h_index='h_index' in request.POST
            odd_rt_lt='odd_rt_lt' in request.POST
            kb='kb' in request.POST
            valius='valius' in request.POST
            dee='dee' in request.POST
            execution='execution' in request.POST
            arc='arc' in request.POST
            bluecut='bluecut' in request.POST
        if prescription:
            prescription.symptoms = symptoms
            prescription.on_examination = on_examination
            prescription.instructions = instructions
            prescription.weight = weight
            prescription.temperature = temperature
            prescription.blood_pressure = blood_pressure
            if request.user.vendor_doctor.eye_specialist:
                prescription.right_sph_distance = right_sph_distance
                prescription.right_cyl_distance = right_cyl_distance
                prescription.right_axis_distance = right_axis_distance
                prescription.right_corrected_distance = right_corrected_distance
                prescription.right_sph_near = right_sph_near
                prescription.right_cyl_near = right_cyl_near
                prescription.right_axis_near = right_axis_near
                prescription.right_corrected_near = right_corrected_near
                prescription.left_sph_distance = left_sph_distance
                prescription.left_cyl_distance = left_cyl_distance
                prescription.left_axis_distance = left_axis_distance
                prescription.left_corrected_distance = left_corrected_distance
                prescription.left_sph_near = left_sph_near
                prescription.left_cyl_near = left_cyl_near
                prescription.left_axis_near = left_axis_near
                prescription.left_corrected_near = left_corrected_near
                prescription.unifocal = unifocal
                prescription.bifocal = bifocal
                prescription.cr_39 = cr_39
                prescription.h_index = h_index
                prescription.odd_rt_lt = odd_rt_lt
                prescription.kb = kb
                prescription.valius = valius
                prescription.dee = dee
                prescription.execution = execution
                prescription.arc = arc
                prescription.bluecut = bluecut
            prescription.save()
            # পুরাতন ঔষধসমূহ মুছে ফেলা
            prescription.medicines.all().delete()
        else:
            if request.user.vendor_doctor.eye_specialist:
                prescription = Prescription.objects.create(
                    appointment = appointment,
                    symptoms = symptoms,
                    on_examination = on_examination,
                    instructions = instructions, 
                    weight = weight, 
                    temperature = temperature,
                    blood_pressure = blood_pressure,
                    right_sph_distance = right_sph_distance,
                    right_cyl_distance = right_cyl_distance,
                    right_axis_distance = right_axis_distance,
                    right_corrected_distance = right_corrected_distance,
                    right_sph_near = right_sph_near,
                    right_cyl_near = right_cyl_near,
                    right_axis_near = right_axis_near,
                    right_corrected_near = right_corrected_near,
                    left_sph_distance = left_sph_distance,
                    left_cyl_distance = left_cyl_distance,
                    left_axis_distance = left_axis_distance,
                    left_corrected_distance = left_corrected_distance,
                    left_sph_near = left_sph_near,
                    left_cyl_near = left_cyl_near,
                    left_axis_near = left_axis_near,
                    left_corrected_near = left_corrected_near,
                    unifocal = unifocal,
                    bifocal = bifocal,
                    cr_39 = cr_39,
                    h_index = h_index,
                    odd_rt_lt = odd_rt_lt,
                    kb = kb,
                    valius = valius,
                    dee = dee,
                    execution = execution,
                    arc = arc,
                    bluecut = bluecut, 
                )
            else:
                prescription = Prescription.objects.create(
                    appointment=appointment,
                    symptoms=symptoms,
                    on_examination = on_examination,
                    instructions=instructions,
                    weight=weight,
                    temperature = temperature,
                    blood_pressure = blood_pressure
                )

        # নতুন ঔষধ যোগ করা
        med_names = request.POST.getlist('med_name')
        generic = request.POST.getlist('generic')
        strength = request.POST.getlist('strength')
        dosage_form = request.POST.getlist('dosage_form')
        med_times = request.POST.getlist('med_time')
        meal_times = request.POST.getlist('meal_time')
        durations = request.POST.getlist('duration')

        for name, generic, strength, dosage_form, time, meal, duration in zip(med_names, generic, strength, dosage_form, med_times, meal_times, durations):
            if name:  # নাম না থাকলে বাদ দিন
                PatientMedicine.objects.create(
                    prescription=prescription,
                    name=name,
                    generic=generic,
                    strength=strength,
                    dosage_form=dosage_form,
                    time=time,
                    meal_time=meal,
                    duration=duration
                )
            if name and not Medicine.objects.filter(name__iexact=name).exists():
                Medicine.objects.create(name=name, generic=generic, strength=strength, dosage_form=dosage_form)
        # টেস্ট আপডেট
        Test.objects.filter(appointment=appointment).delete()
        test_names = request.POST.getlist('test_name')
        test_instructions = request.POST.getlist('test_instructions')
        for name, instruction in zip(test_names, test_instructions):
            if name:
                Test.objects.create(
                    appointment=appointment,
                    test_name=name,
                    instructions=instruction,
                )

        return redirect('prescription_detail', prescription.id)

    context = {
        'appointment': appointment,
        'prescription': prescription,
        'tests': tests,
    }
    return render(request, 'prescription_create.html', context)

@login_required
def delete_prescription(request, prescription_id):
    prescription = get_object_or_404(Prescription, id=prescription_id)

    if prescription.appointment.doctor.vendor != request.user:
        return HttpResponseForbidden("আপনি এই প্রেসক্রিপশন মুছে ফেলার অনুমতি পাননি।")

    prescription.delete()
    return redirect('doctor_dashboard')

@require_GET
def symptom_suggestions(request):
    q = request.GET.get('q', '')
    suggestions = Prescription.objects.filter(symptoms__icontains=q) \
                    .values_list('symptoms', flat=True).distinct()[:10]
    # Flatten multi-line symptoms into individual suggestions
    unique_suggestions = set()
    for s in suggestions:
        for line in s.split("\n"):
            if q.lower() in line.lower():
                unique_suggestions.add(line.strip())
    return JsonResponse([{"name": s} for s in unique_suggestions], safe=False)

@require_GET
def instruction_suggestions(request):
    q = request.GET.get('q', '')
    suggestions = Prescription.objects.filter(instructions__icontains=q) \
                    .values_list('instructions', flat=True).distinct()[:10]
    unique_suggestions = set()
    for s in suggestions:
        for line in s.split("\n"):
            if q.lower() in line.lower():
                unique_suggestions.add(line.strip())
    return JsonResponse([{"name": s} for s in unique_suggestions], safe=False)

@require_GET
def on_examination_suggestions(request):
    q = request.GET.get('q', '')
    suggestions = Prescription.objects.filter(on_examination__icontains=q) \
                    .values_list('on_examination', flat=True).distinct()[:10]
    unique_suggestions = set()
    for s in suggestions:
        for line in s.split("\n"):
            if q.lower() in line.lower():
                unique_suggestions.add(line.strip())
    return JsonResponse([{"name": s} for s in unique_suggestions], safe=False)


@require_GET
def autocomplete_tests(request):
    q = request.GET.get('q', '')
    tests = Test.objects.filter(test_name__icontains=q).values_list('test_name', flat=True).distinct()[:10]
    return JsonResponse(list(tests), safe=False)

@require_GET
def autocomplete_instructions(request):
    q = request.GET.get('q', '')
    instructions = (
        Test.objects.filter(instructions__icontains=q)
        .values_list('instructions', flat=True)
        .distinct()[:10]
    )
    
    return JsonResponse(list(instructions), safe=False)

@require_GET
def duration_suggestions(request):
    q = request.GET.get("q", "").strip()
    durations = PatientMedicine.objects.values_list("duration", flat=True).distinct()

    if q:
        durations = durations.filter(duration__icontains=q)  # case-insensitive filtering

    return JsonResponse(list(durations), safe=False)

def robot_view(request):
    return render(request, "robots.txt", content_type="text/plain")


@login_required
def update_patient(request, pk):

    # Only doctor can access
    if request.user.role != 'Doctor':
        return HttpResponseForbidden("Access denied.")

    patient = get_object_or_404(MyUser, pk=pk, role='Patient')

    if request.method == 'POST':
        form = PatientUpdateForm(
            request.POST,
            instance=patient
        )

        if form.is_valid():
            form.save()
            messages.success(request, "Patient information updated successfully.")
            return redirect('doctor_dashboard')

    else:
        form = PatientUpdateForm(instance=patient)

    context = {
        'form': form,
        'patient': patient
    }

    return render(request, 'update_patient.html', context)