<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Exam;
use App\Models\ExamHall;
use App\Models\ExamSchedule;
use App\Models\ExamRollNumber;
use App\Models\ExamHallAssignment;
use App\Models\Classe;
use App\Models\School_setting;
use App\Models\Subject;
use App\Models\Student;

use App\Models\Staff_member;
use Illuminate\Support\Facades\DB;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Barryvdh\DomPDF\Facade\Pdf;

class ExamController extends Controller
{

    public function exam()
    {
        $all_exams = Exam::all();
        return view('exam.index', compact('all_exams'));
    }
    public function create()
    {
        return view('exam.create');
    }
    public function show($id)
    {
        return view('exam.show', compact('id'));
    }
    public function edit($id)
    {
        return view('exam.edit', compact('id'));
    }
    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required',
            'exam_type' => 'required',
            'notes' => 'required',
        ]);

        Exam::create([
            'title' => $request->name,
            'type' => $request->exam_type,
            'notes' => $request->notes,
        ])->save();

        return redirect()->route('exam')->with('success', 'Exam created successfully.');
    }
    public function delete_exam($id)
    {
        $exam = Exam::find($id);
        if ($exam) {
            $exam->delete();
            return redirect()->route('exam')->with('success', 'Exam deleted successfully.');
        } else {
            return redirect()->route('exam')->with('error', 'Exam not found.');
        }
    }
    public function update_exam(Request $request, $id)
    {
        $request->validate([
            'name' => 'required',
            'exam_type' => 'required',
            'notes' => 'required',
        ]);

        $exam = Exam::find($id);
        if ($exam) {
            $exam->title = $request->name;
            $exam->type = $request->exam_type;
            $exam->notes = $request->notes;
            $exam->save();
            return redirect()->route('exam')->with('success', 'Exam updated successfully.');
        } else {
            return redirect()->route('exam')->with('error', 'Exam not found.');
        }
    }

    //Exam Halls Functions
    public function exam_halls()
    {
        $all_exam_halls = ExamHall::all();
        return view('exam.exam_halls', compact('all_exam_halls'));
    }
    public function create_exam_hall()
    {
        return view('exam.create_exam_hall');
    }
    public function show_exam_hall($id)
    {
        return view('exam.show_exam_hall', compact('id'));
    }
    public function edit_exam_hall($id)
    {
        return view('exam.edit_exam_hall', compact('id'));
    }
    public function store_exam_hall(Request $request)
    {

        $request->validate([
            'name' => 'required',
            'capacity' => 'required|integer',
            'location' => 'required',
            'notes' => 'required',
        ]);

        if (!$request->name || !$request->capacity || !$request->location || !$request->notes) {
            return back()->with(['error' => 'All fields are required.']);
        }


        ExamHall::create([
            'name' => $request->name,
            'capacity' => $request->capacity,
            'location' => $request->location,
            'notes' => $request->notes,
        ])->save();


        return redirect()->route('exam.hall')->with('success', 'Exam Hall created successfully.');
    }
    public function delete_exam_hall($id)
    {
        $exam_hall = ExamHall::find($id);
        if ($exam_hall) {
            $exam_hall->delete();
            return redirect()->route('exam.hall')->with('success', 'Exam Hall deleted successfully.');
        } else {
            return redirect()->route('exam.hall')->with('error', 'Exam Hall not found.');
        }
    }
    public function update_exam_hall(Request $request, $id)
    {
        $request->validate([
            'name' => 'required',
            'capacity' => 'required|integer',
            'location' => 'required',
            'notes' => 'required',
        ]);

        $exam_hall = ExamHall::find($id);
        if ($exam_hall) {
            $exam_hall->name = $request->name;
            $exam_hall->capacity = $request->capacity;
            $exam_hall->location = $request->location;
            $exam_hall->notes = $request->notes;
            $exam_hall->save();
            return redirect()->route('exam.hall')->with('success', 'Exam Hall updated successfully.');
        } else {
            return redirect()->route('exam.hall')->with('error', 'Exam Hall not found.');
        }
    }

    public function exam_timetable()
    {
        

        // ✅ Original full timetable grouped by exam_id
        $exam_time_table = ExamSchedule::with(['exam', 'class', 'hallAssignments.student'])
            ->orderBy('exam_date')
            ->get()
            ->groupBy('exam_id');

        // ✅ Get distinct exam_schedule_ids from exam_hall_assignments
        $assignedExamScheduleIds = DB::table('exam_hall_assignments')
            ->distinct()
            ->pluck('exam_schedule_id');

        // ✅ Get distinct class_ids from those assigned exam_schedules
        $assignedClassIds = ExamSchedule::whereIn('id', $assignedExamScheduleIds)
            ->distinct()
            ->pluck('class_id');

        // ✅ Get only those classes that have hall assignments
        $timetable_classes = Classe::whereIn('id', $assignedClassIds)
            ->orderBy('name')
            ->get();
      
        // ✅ Get class-wise schedules grouped by exam_date
        $classwise_schedules = ExamSchedule::with(['exam', 'class'])
            ->whereIn('class_id', $assignedClassIds)
            ->orderBy('exam_date')
            ->get()
            ->groupBy('exam_date');
 
        // ✅ Pass all data to the view
        return view('exam.exam_timetable', compact(
            'exam_time_table',
            'classwise_schedules',
            'timetable_classes'
        ));
    }

    public function getExamTimetableDetails($examId)
    {
        $examTimetable = ExamSchedule::with(['exam', 'class'])
            ->where('exam_id', $examId)
            ->orderBy('exam_date')
            ->get();

        if ($examTimetable->isEmpty()) {
            return response()->json(['error' => 'Exam timetable not found'], 404);
        }

        $examTitle = $examTimetable->first()->exam->title;
        $classes = $examTimetable->pluck('class.name')->unique()->values()->all();

        // Group by date
        $groupedByDate = $examTimetable->groupBy(function ($item) {
            return Carbon::parse($item->exam_date)->format('Y-m-d');
        });

        $schedule = [];
        foreach ($groupedByDate as $date => $items) {
            $dateObj = Carbon::parse($date);
            $day = $dateObj->format('l');

            $classItems = [];
            foreach ($classes as $className) {
                $classItem = $items->firstWhere('class.name', $className);
                $classItems[] = [
                    'className' => $className,
                    'subject' => $classItem ? $classItem->subject : '-'
                ];
            }

            $schedule[] = [
                'date' => $dateObj->format('M d, Y'),
                'day' => $day,
                'classes' => $classItems
            ];
        }

        return response()->json([
            'examTitle' => $examTitle,
            'classes' => $classes,
            'schedule' => $schedule
        ]);
    }


    public function exam_create_timetable()
    {
        $exams = Exam::all();
        $subjects = Subject::all();
        $academic_year = School_setting::where('setting_key', 'academic_year')->value('setting_value');

        // Get only classes that have active students with admissions
        $classes = Classe::whereIn('id', function ($query) {
            $query->select('class_id')
                ->from('admissions')
                ->join('students', 'admissions.student_id', '=', 'students.id')
                ->where('students.status', 'active'); // Only active students
        })->get();

        return view('exam.exam_create_timetable', compact('exams', 'classes', 'academic_year', 'subjects'));
    }

    public function store_exam_timetable(Request $request)
    {
        $request->validate([
            'exam_id' => 'required|exists:exams,id',
            'schedules' => 'required|array',
            'schedules.*.exam_date' => 'required|date',
        ]);
       
        try {
            DB::beginTransaction();

            $total_classes_count  = count($request->class_id);
            $total_subjects_count  = count($request->schedules);

            $skippedSchedules = [];
            
            // for ($j = 0; $j < $total_classes_count; $j++) {
            foreach ($request->class_id as $index => $classId) {
               
                for ($i = 0; $i < $total_subjects_count; $i++) {

                   

                    if (!isset($request->schedules[$i])) {
                        Log::warning("Missing schedule data for index {$i}");
                        continue;
                    }

                    $classId = $request->class_id[$index];
                    $subjectId = $request->schedules[$i][$classId]['subject_id'];
                    if ($subjectId === 'none') {
                        $subjectId = null; // store null in DB
                    }
                     // Check if schedule already exists
                    $existingSchedule = ExamSchedule::where('exam_id', $request->exam_id)
                        ->where('class_id', $classId)
                        ->where('subject_id', $subjectId)
                        ->first();

                    if ($existingSchedule) {
                        Log::warning( "Class ID: {$classId} already has a schedule for Subject ID: {$subjectId}.");
                         continue; 
                    }

                    // Create exam schedule
                    $examSchedule = ExamSchedule::create([
                        'exam_id' => $request->exam_id,
                        'class_id' => $classId,
                        'subject_id' => $subjectId,
                        'exam_date' => $request->schedules[$i]['exam_date'],
                        'invigilator_id' => $request->schedules[$i]['invigilator_id'] ?? null,
                        'special_notes' => $request->schedules[$i]['special_notes'] ?? null,
                        'special_notes' => $request->academic_session ?? null,
                    ]);
                    Log::info("Created ExamSchedule ID: {$examSchedule->id} for Class ID: {$classId}");

                    // Get students for this class
                    $students = Student::with('latestAdmission')->get()->filter(function ($student) use ($classId) {
                        return $student->latestAdmission && $student->latestAdmission->class_id == $classId;
                    });
                    Log::info("Students found for Class ID {$classId}: " . $students->count());

                    foreach ($students as $student) {
                        try {
                            Log::info("Processing student ID: {$student->id}");

                            // Skip if ExamHallAssignment already exists for this exam & schedule
                            $existingAssignment = ExamHallAssignment::where('exam_id', $request->exam_id)
                                ->where('student_id', $student->id)
                                ->where('exam_schedule_id', $examSchedule->id)
                                ->first();

                            if ($existingAssignment) {
                                Log::warning("Duplicate hall assignment skipped for Student ID: {$student->id}");
                                continue;
                            }

                            // Skip if ExamRollNumber already exists for this exam
                            $existingRoll = ExamRollNumber::where('exam_id', $request->exam_id)
                                ->where('student_id', $student->id)
                                ->first();

                            if ($existingRoll) {
                                Log::warning("Duplicate roll number skipped for Student ID: {$student->id}");
                                continue;
                            }

                            // Assign hall, seat number, and roll number
                            $assignedHallId = $this->assignHallAutomatically($request->exam_id, $classId);
                            $seatNumber = $this->generateSeatNumber($assignedHallId);
                            $rollNumber = $this->generateRollNumber($student, $examSchedule);

                            // Create hall assignment
                            ExamHallAssignment::create([
                                'head_code' => $student->latestAdmission->head_code ?? null,
                                'reg_no' => $student->latestAdmission->reg_no ?? null,
                                'exam_schedule_id' => $examSchedule->id,
                                'student_id' => $student->id,
                                'exam_id' => $request->exam_id,
                                'exam_hall_id' => $assignedHallId,
                                'seat_number' => $seatNumber,
                                'roll_number' => $rollNumber,
                            ]);

                            // Create roll number record
                            ExamRollNumber::create([
                                'student_id' => $student->id,
                                'exam_id' => $request->exam_id,
                                'qr_code' => $this->generateQrCode($student->id),
                                'issued_at' => now(),
                            ]);
                        } catch (\Exception $e) {
                            Log::error("Failed to assign hall or roll number for student ID {$student->id}: " . $e->getMessage());
                            continue; // Skip this student but keep processing others
                        }
                    }
                }
            }

            DB::commit();
            Log::info("Finished processing all schedules successfully.");

            return redirect()->route('exam.timetable')->with('success', 'Exam timetables created successfully.');
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error("Transaction failed: " . $e->getMessage());
            return back()->with('error', 'An error occurred: ' . $e->getMessage());
        }
    }




    public function exam_show_timetable($id)
    {
        return view('exam.exam_show_timetable', compact('id'));
    }
    public function exam_edit_timetable($id)
    {
        return view('exam.exam_edit_timetable', compact('id'));
    }
    public function exam_delete_timetable($id)
    {
        return view('exam.exam_delete_timetable', compact('id'));
    }
    public function exam_update_timetable($id)
    {
        return view('exam.exam_update_timetable', compact('id'));
    }


    private function assignHallAutomatically($examId, $classId)
    {
        // More intelligent hall assignment
        return ExamHall::where('capacity', '>', 0)
            ->orderBy('capacity', 'desc')
            ->first()->id;
    }

    private function generateSeatNumber($hallId)
    {
        // Seat number based on hall capacity
        $lastSeat = ExamHallAssignment::where('exam_hall_id', $hallId)
            ->selectRaw('MAX(CAST(seat_number AS UNSIGNED)) as max_seat')
            ->value('max_seat');

        return $lastSeat ? $lastSeat + 1 : 1;
    }

    private function generateRollNumber($student, $examSchedule)
    {
        // More structured roll number
        return sprintf(
            '%s-%03d',
            $student->reg_no,
            $student->id
        );
    }

    public function generateQrCode($studentId)
    {
        $qr = QrCode::size(200)->generate($studentId);

        return view('qr.view', compact('qr'));
    }

    public function downloadExamTimetablePdf($examId)
{
    $settings = School_setting::pluck('setting_value', 'setting_key')->toArray();
      
        // Now you can use:
        $schoolName = $settings['school_name'] ?? '';
        $schoolAddress = $settings['school_address'] ?? '';
        $academicYear = $settings['academic_year'] ?? '';

    $examTimetable = ExamSchedule::with(['exam', 'class'])
            ->where('exam_id', $examId)
            ->orderBy('exam_date')
            ->get();

        if ($examTimetable->isEmpty()) {
            return response()->json(['error' => 'Exam timetable not found'], 404);
        }

        $examTitle = $examTimetable->first()->exam->title;
        $classes = $examTimetable->pluck('class.name')->unique()->values()->all();

        // Group by date
        $groupedByDate = $examTimetable->groupBy(function ($item) {
            return Carbon::parse($item->exam_date)->format('Y-m-d');
        });

        $schedule = [];
        foreach ($groupedByDate as $date => $items) {
            $dateObj = Carbon::parse($date);
            $day = $dateObj->format('l');

            $classItems = [];
            foreach ($classes as $className) {
                $classItem = $items->firstWhere('class.name', $className);
                $classItems[] = [
                    'className' => $className,
                    'subject' => $classItem ? $classItem->subject : '-'
                ];
            }

            $schedule[] = [
                'date' => $dateObj->format('M d, Y'),
                'day' => $day,
                'classes' => $classItems
            ];
        } 
    
    $pdf = Pdf::loadView('exam.timetable_pdf', compact('examTitle', 'classes', 'schedule','schoolName', 'schoolAddress', 'academicYear'));

    return $pdf->download($examTitle . '_Timetable.pdf');
}

public function edit_exam_timetable($exam_id)
{
    \Log::info("Editing timetable for exam: " . $exam_id);
    
    try {
        $exam = Exam::findOrFail($exam_id);
        
        $classIds = ExamSchedule::where('exam_id', $exam_id)
            ->distinct()
            ->pluck('class_id');
            
        $classes = Classe::whereIn('id', $classIds)->get();
        
        $schedulesByClass = [];
        
        foreach ($classes as $class) {
            $schedules = ExamSchedule::with(['subject'])
                ->where('exam_id', $exam_id)
                ->where('class_id', $class->id)
                ->get()
                ->map(function ($schedule) {
                    return [
                        'id' => $schedule->id,
                        'subject_id' => $schedule->subject_id,
                        'subject_name' => $schedule->subject ? $schedule->subject->name : 'N/A',
                        'exam_date' => $schedule->exam_date,
                        'invigilator_id' => $schedule->invigilator_id,
                        'invigilator_name' => $schedule->invigilator ? $schedule->invigilator->name : 'N/A',
                        'special_notes' => $schedule->special_notes,
                        'academic_session' => $schedule->academic_session,
                    ];
                });
                
            $schedulesByClass[$class->id] = $schedules;
        }    
 
      
        
        return view('exam.edit-exam-timetable', [
            'exam' => $exam,
            'exams' => Exam::all(),
            'academic_year' => School_setting::where('setting_key', 'academic_year')->value('setting_value'),
            'classes' => $classes,
            'schedulesByClass' => $schedulesByClass,
            'subjects' => Subject::all(),
            'invigilators' => Staff_member::where('status', true)->get(),
            'halls' => ExamHall::all(),
        ]);
        
    } catch (\Exception $e) {
        \Log::error("Edit timetable failed: " . $e->getMessage());
        return redirect()->route('exam.timetable')->with('error', 'Failed to load timetable: ' . $e->getMessage());
    }
}

public function update_exam_timetable(Request $request, $exam_id)
{
    $request->validate([
        'schedules' => 'required|array',
        'schedules.*.exam_date' => 'required|date',
        'class_id' => 'required|array',
    ]);

    try {
        DB::beginTransaction();

        $updatedSchedules = [];
        $skippedSchedules = [];

        foreach ($request->schedules as $subjectIndex => $scheduleData) {
           
            // Get the common exam date for this subject row
            $commonExamDate = $scheduleData['exam_date'];
            
            // Process each class in this subject row
            foreach ($request->class_id as $classId) {
                if (!isset($scheduleData[$classId]['subject_id'])) {
                    continue;
                }

                // Find the schedule ID - either from hidden field or by querying
               $scheduleId = $scheduleData['classes'][$classId]['sch_id'] ?? null; 
                
                if (!$scheduleId) {
                    // Alternative: Find by exam_id, class_id, and subject_id
                    $examSchedule = ExamSchedule::where([
                        'exam_id' => $exam_id,
                        'class_id' => $classId,
                        'subject_id' => $scheduleData[$classId]['subject_id']
                    ])->first();
                } else {
                    $examSchedule = ExamSchedule::find($scheduleId);
                }

                if (!$examSchedule) {
                    Log::warning("Schedule not found for class {$classId} and subject index {$subjectIndex}");
                    $skippedSchedules[] = ['class' => $classId, 'subject_index' => $subjectIndex];
                    continue;
                }

                // Handle subject_id (convert 'none' to null)
                $subjectId = $scheduleData[$classId]['subject_id'] ?? null;
                $subjectId = ($subjectId === 'none') ? null : $subjectId;

                // Update exam schedule
                $examSchedule->update([
                    'subject_id' => $subjectId,
                    'exam_date' => $commonExamDate,
                    'invigilator_id' => $scheduleData[$classId]['invigilator_id'] ?? null,
                    'special_notes' => $scheduleData[$classId]['special_notes'] ?? null,
                    'academic_session' => $request->academic_session,
                ]);

                $updatedSchedules[] = $examSchedule->id;
                Log::info("Updated ExamSchedule ID: {$examSchedule->id} for class {$classId}");

                // Update related hall assignments
                /* ExamHallAssignment::where('exam_schedule_id', $examSchedule->id)
                    ->update([
                        'exam_date' => $commonExamDate,
                        // Add other fields as needed
                    ]); */
            }
        }

        DB::commit();
        
        $message = "Exam timetables updated successfully. Updated " . count($updatedSchedules) . " schedules.";
        if (count($skippedSchedules)) {
            $message .= " Skipped " . count($skippedSchedules) . " schedules (not found).";
        }

        return redirect()->route('exam.timetable')
            ->with('success', $message)
            ->with('updated_schedules', $updatedSchedules);

    } catch (\Exception $e) {
        DB::rollBack();
        Log::error("Failed to update exam timetable: " . $e->getMessage());
        return back()->with('error', 'Failed to update timetable: ' . $e->getMessage());
    }
}


}
