<?php

namespace Modules\ParentModule\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Traits\StudentCollectionTrait;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\Academic\Models\AbsentFine;
use Modules\Academic\Models\Assignment;
use Modules\Academic\Models\ClassModel;
use Modules\Academic\Models\ClassRoutine;
use Modules\Academic\Models\Event;
use Modules\Academic\Models\Exam;
use Modules\Academic\Models\ExamSchedule;
use Modules\Academic\Models\LibraryMember;
use Modules\Academic\Models\Notice;
use Modules\Academic\Models\Section;
use Modules\Academic\Models\Student;
use Modules\Academic\Models\StudentAttendance;
use Modules\Academic\Models\StudentSession;
use Modules\Academic\Models\Subject;
use Modules\Examination\Models\ClassExam;
use Modules\Examination\Models\ExamMark;
use Modules\Finance\Models\Fee;
use Modules\Finance\Models\StudentCollectionDetailsSubHead;
use Modules\Library\Models\BookIssue;
use Modules\ParentModule\Models\ParentModel;
use Modules\Student\Models\AssignmentSubmit;
use Modules\Teacher\Models\Behavior;
use Modules\Teacher\Models\Gamification;
use Modules\Teacher\Models\Prayer;

class ParentModuleController extends Controller
{
    use StudentCollectionTrait;

    public function myProfile(): JsonResponse
    {
        $parent = ParentModel::where('parent_models.id', get_parent_id())->with('user', 'student')->first();

        return $this->responseSuccess($parent, 'Profile fetch successfully.');
    }

    public function defaultChildGet(): JsonResponse
    {
        $parent = ParentModel::where('parent_models.id', get_parent_id())->with('student')->first();
        if (! $parent) {
            return $this->responseError([], _lang('Something went wrong. Parent not found.'), 404);
        }

        return $this->responseSuccess($parent->student, 'Default Child fetch successfully.');
    }

    public function myChildrenList(): JsonResponse
    {
        $childrenList = Student::where('students.parent_id', get_parent_id())
            ->join('student_sessions', 'students.id', '=', 'student_sessions.student_id')
            ->join('classes', 'classes.id', '=', 'student_sessions.class_id')
            ->join('sections', 'sections.id', '=', 'student_sessions.section_id')
            // ->where('student_sessions.session_id', get_option('academic_year'))
            ->select('students.*', 'classes.class_name', 'sections.section_name')
            ->get();

        return $this->responseSuccess($childrenList, 'Children List fetch successfully.');
    }

    public function defaultChildAssign(Request $request): JsonResponse
    {
        $studentId = (int) $request->student_id;
        $parent = ParentModel::where('parent_models.id', get_parent_id())->first();
        if (! $parent) {
            return $this->responseError([], _lang('Something went wrong. Parent not found.'), 404);
        }

        $parent->student_id = $studentId;
        $parent->save();

        return $this->responseSuccess($parent, 'Default Child Assign successfully.');
    }

    public function dashboardData(Request $request)
    {
        $studentId = (int) get_authenticated_parent_student_id();

        $studentSession = StudentSession::where('student_id', $studentId)->with('class')->first();

        if (! $studentSession) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        $classId = $studentSession->class_id;

        // Monthly Attendance
        $monthlyAttendance = StudentAttendance::where('student_id', $studentId)
            ->where('period_id', 1)
            ->whereBetween('date', [
                now()->startOfMonth()->toDateString(),
                now()->endOfMonth()->toDateString(),
            ])
            ->get();

        $monthlyTotal = $monthlyAttendance->count();
        $monthlyPresent = $monthlyAttendance->where('attendance', '1')->count();
        $monthlyPercentage = $monthlyTotal > 0 ? round(($monthlyPresent / $monthlyTotal) * 100, 2) : 0;

        // Overall Attendance
        $allAttendance = StudentAttendance::where('student_id', $studentId)
            ->where('period_id', 1)
            ->get();

        $totalAttendance = $allAttendance->count();
        $totalPresent = $allAttendance->where('attendance', '1')->count();
        $overallPercentage = $totalAttendance > 0 ? round(($totalPresent / $totalAttendance) * 100, 2) : 0;

        // Pending Assignments (class-wise)
        $pendingTasks = Assignment::where('class_id', $classId)
            ->count();

        // Upcoming Exams (class-wise)
        $upcomingExams = ExamSchedule::where('class_id', $classId)
            ->where('date', '>=', now()->toDateString())
            ->count();

        $data = [
            'attendance' => [
                'monthly_percentage' => $monthlyPercentage,
                'overall_percentage' => $overallPercentage,
            ],
            'tasks' => $pendingTasks,
            'upcoming_exams' => $upcomingExams,
        ];

        return $this->responseSuccess($data, 'Child overview data fetch successfully.');
    }

    public function myChildrenProfile(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();
        $student = Student::join('users', 'users.id', '=', 'students.user_id')
            ->join('student_sessions', 'students.id', '=', 'student_sessions.student_id')
            ->join('classes', 'classes.id', '=', 'student_sessions.class_id')
            ->join('sections', 'sections.id', '=', 'student_sessions.section_id')
            ->join('parent_models', 'parent_models.id', '=', 'students.parent_id')
            // ->where('student_sessions.session_id', get_option('academic_year'))
            ->where('students.parent_id', get_parent_id())
            ->where('students.id', $studentId)->first();

        return $this->responseSuccess($student, 'Children Profile fetch successfully.');
    }

    public function childrenAttendance(Request $request): JsonResponse
    {
        $request->validate([
            'month' => 'required|integer|between:1,12',
            'year' => 'required|integer|min:2000|max:2100',
        ]);

        $studentId = (int) get_authenticated_parent_student_id();
        $month = (int) $request->month;
        $year = (int) $request->year;

        $num_of_days = cal_days_in_month(CAL_GREGORIAN, $month, $year);

        $attendances = DB::table('student_attendances')
            ->select('student_attendances.*')
            ->join('students', 'student_attendances.student_id', '=', 'students.id')
            ->where('student_attendances.student_id', $studentId)
            ->where('students.parent_id', get_parent_id())
            ->whereMonth('date', $month)
            ->whereYear('date', $year)
            ->orderBy('date', 'asc')
            ->get();

        $report_data = [];
        $attendance_value = [
            '0' => '',
            '1' => _lang('Present'),
            '2' => _lang('Absent'),
            '3' => _lang('Late'),
        ];

        // Build date => status map
        $attendanceMap = [];
        foreach ($attendances as $attendance) {
            $attendanceMap[$attendance->date] = $attendance_value[$attendance->attendance] ?? '';
        }

        // Convert to structured day list
        $days = [];
        for ($day = 1; $day <= $num_of_days; $day++) {
            $date = sprintf('%04d-%02d-%02d', $year, $month, $day);
            $days[] = [
                'date' => $date,
                'day' => date('l', strtotime($date)), // Full weekday name
                'status' => $attendanceMap[$date] ?? '',
            ];
        }

        return response()->json([
            'month' => [
                'month' => $month,
                'year' => $year,
            ],
            'days' => $days,
        ]);
    }

    public function mySubjects(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();
        $student = StudentSession::where('student_id', $studentId)->first();
        if (! $student) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        // Fetch compulsory subjects with group_id as null
        $compulsorySubjects = Subject::select('subjects.id AS id', 'subjects.subject_name', 'subjects.subject_code', 'subjects.subject_type', 'subjects.class_id', 'subjects.group_id')
            ->join('classes', 'classes.id', '=', 'subjects.class_id')
            ->where('subjects.class_id', $student->class_id)
            ->whereNull('subjects.group_id')
            ->get();

        // Fetch subjects based on the student's class and group
        $studentSubjects = Subject::select('*', 'subjects.id AS id')
            ->join('classes', 'classes.id', '=', 'subjects.class_id')
            ->where('subjects.class_id', $student->class_id)
            ->where('subjects.group_id', $student->student->group)
            ->get();

        // Merge the two subject collections
        $subjects = $compulsorySubjects->merge($studentSubjects);

        if (! $subjects) {
            return $this->responseError([], _lang('Something went wrong. Subject not found.'));
        }

        return $this->responseSuccess($subjects, 'Student Subjects fetch successfully.');
    }

    public function classRoutine(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();
        $student = StudentSession::where('student_id', $studentId)->first();
        if (! $student) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        $data = [];
        $data['class'] = ClassModel::find($student->class_id);
        $data['section'] = Section::find($student->section_id);
        $data['routine'] = ClassRoutine::getRoutineView($student->class_id, $student->section_id);

        if (! $data) {
            return $this->responseError([], _lang('Something went wrong. Class Routine not found.'));
        }

        return $this->responseSuccess($data, 'Student Class Routines fetch successfully.');
    }

    public function examRoutine(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();

        $studentSession = StudentSession::with('student')
            ->where('student_id', $studentId)
            ->first();

        if (! $studentSession || ! $studentSession->student) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        $classId = $studentSession->class_id;
        $studentGroupId = $studentSession->student->group; // assuming 'group' stores group_id

        // Fetch all exams
        $exams = Exam::all();

        // Fetch compulsory subjects (group_id null)
        $compulsorySubjects = Subject::where('class_id', $classId)
            ->whereNull('group_id');

        // Fetch group-specific subjects
        $groupSubjects = Subject::where('class_id', $classId)
            ->where('group_id', $studentGroupId);

        // Merge query results with union
        $subjectsQuery = $compulsorySubjects->union($groupSubjects);

        // Fetch all exam schedules for these subjects (for any exam)
        $subjectsWithSchedules = DB::table(DB::raw("({$subjectsQuery->toSql()}) as subjects"))
            ->mergeBindings($subjectsQuery->getQuery()) // bind params
            ->leftJoin('exam_schedules', 'subjects.id', '=', 'exam_schedules.subject_id')
            ->select(
                'subjects.id as subject_id',
                'subjects.subject_name',
                'subjects.subject_code',
                'subjects.subject_type',
                'subjects.class_id',
                'subjects.group_id',
                'exam_schedules.id as schedule_id',
                'exam_schedules.exam_id',
                'exam_schedules.date',
                'exam_schedules.start_time',
                'exam_schedules.end_time',
                'exam_schedules.room',
            )
            ->get();

        // Group schedules by exam
        $examSchedulesGrouped = [];

        foreach ($exams as $exam) {
            $examSchedulesGrouped[$exam->id] = [
                'exam' => $exam,
                'subjects' => $subjectsWithSchedules->where('exam_id', $exam->id)->values(),
            ];
        }

        // If you want to return as array (not keyed by exam id)
        $response = array_values($examSchedulesGrouped);

        return $this->responseSuccess($response, _lang('Student Exam Routines fetched successfully.'));
    }

    public function myAssignment(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();
        $student = StudentSession::where('student_id', $studentId)->first();
        if (! $student) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        $assignments = Assignment::select('assignments.id', 'assignments.title', 'assignments.description', 'subjects.subject_name', 'subjects.subject_code', 'subjects.subject_type', 'assignments.deadline', 'assignments.file', 'assignments.file_2', 'assignments.file_3', 'assignments.file_4')
            ->join('subjects', 'subjects.id', '=', 'assignments.class_id')
            ->where('assignments.class_id', $student->class_id)
            ->where('assignments.section_id', $student->section_id)
            ->where('assignments.session_id', get_option('academic_year'))
            ->where('assignments.institute_id', get_institute_id())
            ->where('assignments.branch_id', get_branch_id())
            ->orderBy('assignments.id', 'DESC')
            ->paginate($request->per_page ?: 10);

        if (! $assignments) {
            return $this->responseError([], _lang('Something went wrong. Assignments not found.'));
        }

        return $this->responseSuccess($assignments, 'Student Assignments fetch successfully.');
    }

    public function assignmentSubmit(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();
        $student = StudentSession::where('student_id', $studentId)->first();
        if (! $student) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        $assignmentSubmits = AssignmentSubmit::select(
            'assignment_submits.*',
            'assignments.title AS assignment_title',
            'assignments.description AS assignment_description',
            'assignments.deadline AS assignment_deadline',
            'classes.class_name',
            'sections.section_name',
            'subjects.subject_name'
        )
            ->join('assignments', 'assignments.id', '=', 'assignment_submits.assignment_id') // Link to assignments
            ->join('classes', 'classes.id', '=', 'assignments.class_id') // Link to classes
            ->join('sections', 'sections.id', '=', 'assignments.section_id') // Link to sections
            ->join('subjects', 'subjects.id', '=', 'assignments.subject_id') // Link to subjects
            ->where('assignment_submits.student_id', $studentId)
            ->where('assignments.session_id', get_option('academic_year'))
            ->where('assignments.institute_id', get_institute_id())
            ->where('assignments.branch_id', get_branch_id()) // Ensure correct academic year
            ->orderBy('assignment_submits.id', 'DESC')
            ->paginate($request->per_page ?: 10);

        if (! $assignmentSubmits) {
            return $this->responseError([], _lang('Something went wrong. Assignment Submit not found.'));
        }

        return $this->responseSuccess($assignmentSubmits, 'Assignment Submit fetch successfully.');
    }

    public function studentAttendanceFineReport(Request $request): JsonResponse
    {
        // Step 1: Get authenticated student ID (parent or student context)
        $studentId = (int) get_authenticated_parent_student_id();
        // Step 2: Fetch student session
        $studentSession = StudentSession::with('student')->where('student_id', $studentId)->first();
        if (! $studentSession || ! $studentSession->student) {
            return $this->responseError([], _lang('Student session or student record not found.'), 404);
        }

        // Step 3: Required IDs
        $classId = $studentSession->class_id;
        $sectionId = $studentSession->section_id;

        // Step 4: Get base fine value
        $attendanceFine = AbsentFine::where('period_id', 1)->first();
        if (! $attendanceFine) {
            return $this->responseError([], _lang('Attendance fine not assigned. Please assign it first.'), 422);
        }

        $attendanceFineAmount = (float) $attendanceFine->fee_amount;

        // Step 5: Query attendance with absent counts
        $attendances = DB::table('student_attendances')
            ->join('student_sessions', 'student_sessions.student_id', '=', 'student_attendances.student_id')
            ->where('student_attendances.student_id', $studentId)
            ->where('student_attendances.class_id', $classId)
            ->where('student_attendances.section_id', $sectionId)
            ->where('student_attendances.attendance', 2) // Absent
            ->where('student_attendances.period_id', 1)
            ->whereYear('student_attendances.date', current_year())
            ->select(
                DB::raw('MONTH(student_attendances.date) as month'),
                DB::raw('COUNT(student_attendances.id) as absent_count')
            )
            ->groupBy('month')
            ->orderBy('month', 'ASC')
            ->get();

        // Step 6: Format results
        $months = [];
        $totalFineAmount = 0;

        foreach ($attendances as $record) {
            $month = (int) $record->month;
            $absentCount = (int) $record->absent_count;
            $fineAmount = $absentCount * $attendanceFineAmount;

            $months[] = [
                'month' => $month,
                'month_name' => \Carbon\Carbon::create()->month($month)->format('F'),
                'absent_count' => $absentCount,
                'fine_amount' => number_format($fineAmount, 2),
            ];

            $totalFineAmount += $fineAmount;
        }

        // Step 7: Final response structure
        $responseData = [
            'student_name' => $studentSession->student->first_name ?? 'N/A',
            'roll' => $studentSession->roll ?? '',
            'section_name' => Section::where('id', $sectionId)->value('section_name') ?? '',
            'attendance_fine' => number_format($attendanceFineAmount, 2),
            'total_fine_amount' => number_format($totalFineAmount, 2),
            'months' => $months,
        ];

        return $this->responseSuccess($responseData, 'Student Attendance Fine Report fetched successfully.');
    }

    public function getPaymentInfoStudent(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();
        $studentSession = StudentSession::with('student')->where('student_id', $studentId)->first();

        if (! $studentSession || ! $studentSession->student) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        // Fetch student info
        $student = $studentSession->student;

        // Total paid amount from student_collections
        $totalPaidAmount = DB::table('student_collections')
            ->where('student_id', $studentId)
            ->sum('total_paid');

        // Collection history from student_collection_details
        $collectionDetails = DB::table('student_collection_details as scd')
            ->join('student_collections as sc', 'sc.id', '=', 'scd.student_collection_id')
            ->leftJoin('fee_heads as fh', 'fh.id', '=', 'scd.fee_head_id')
            ->select(
                'sc.invoice_id',
                'sc.invoice_date',
                'fh.name as fee_head_name',
                'scd.fee_and_fine_paid',
                'scd.waiver',
                'scd.fine_payable',
                'scd.previous_due_paid'
            )
            ->where('sc.student_id', $studentId)
            ->orderByDesc('sc.invoice_date')
            ->get()
            ->map(function ($row) {
                return [
                    'invoice_id' => $row->invoice_id,
                    'invoice_date' => \Carbon\Carbon::parse($row->invoice_date)->format('d M, Y'),
                    'fee_head_name' => $row->fee_head_name,
                    'paid_amount' => number_format($row->fee_and_fine_paid, 2),
                    'waiver' => number_format($row->waiver, 2),
                    'fine_amount' => number_format($row->fine_payable, 2),
                    'previous_due_paid' => number_format($row->previous_due_paid, 2),
                ];
            });

        // Response payload
        $data = [
            'student' => [
                'name' => $student->first_name.' '.$student->last_name,
                'roll' => $studentSession->roll,
                'class_id' => $studentSession->class_id,
                'section_id' => $studentSession->section_id,
            ],
            'total_paid_amount' => number_format($totalPaidAmount, 2),
            'collection_history' => $collectionDetails,
        ];

        return $this->responseSuccess($data, 'Student Payment Info fetched successfully.');
    }

    public function getUnpaidFeeInfoStudent(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();

        $studentSession = StudentSession::with(['student.user', 'class', 'section', 'student.studentGroup'])
            ->where('student_id', $studentId)
            ->first();

        if (! $studentSession || ! $studentSession->student) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        $student = $studentSession->student;
        $sessionId = $studentSession->session_id;
        $classId = $studentSession->class_id;
        $sectionId = $studentSession->section_id;

        // Fetch fee configurations for this class/section
        $amountConfigs = Fee::with('feeHead.feeSubHeads')
            ->where('class_id', $classId)
            ->where('section_id', $sectionId)
            ->get();

        $feeHeadsData = [];
        $totalDueAmount = 0;

        foreach ($amountConfigs as $config) {
            $feeHead = $config->feeHead;
            $feeHeadId = $feeHead->id;
            $subHeads = $feeHead->feeSubHeads;

            foreach ($subHeads as $subHead) {
                $collectionSub = StudentCollectionDetailsSubHead::where('student_id', $studentId)
                    ->where('session_id', $sessionId)
                    ->where('fee_head_id', $feeHeadId)
                    ->where('sub_head_id', $subHead->id)
                    ->first();

                if (! $collectionSub || optional($collectionSub->collectionDetail)->total_paid == 0) {
                    $payable = $this->getCollectionAmountsByFeeHeadAndSubHeads(
                        $studentId,
                        $feeHeadId,
                        [$subHead->id]
                    );

                    // Initialize fee head entry if not already set
                    if (! isset($feeHeadsData[$feeHeadId])) {
                        $feeHeadsData[$feeHeadId] = [
                            'fee_head_id' => $feeHeadId,
                            'fee_head_name' => $feeHead->name,
                            'sub_heads' => [],
                        ];
                    }

                    $feeHeadsData[$feeHeadId]['sub_heads'][] = [
                        'sub_head_id' => $subHead->id,
                        'sub_head_name' => $subHead->name,
                        'fee_and_fine_payable' => number_format($payable['fee_and_fine_payable'], 2),
                    ];

                    $totalDueAmount += $payable['fee_and_fine_payable'];
                }
            }
        }

        // Convert associative to indexed array
        $feeHeadsData = array_values($feeHeadsData);

        // Build final student data structure
        $studentData = [
            'id' => $student->id,
            'name' => $student->user?->name ?? '',
            'email' => $student->user?->email ?? '',
            'phone' => $student->user?->phone ?? '',
            'roll' => $studentSession->roll,
            'class_name' => $studentSession->class?->class_name ?? '',
            'section_name' => $studentSession->section?->section_name ?? '',
            'group_name' => $studentSession->studentGroup?->group_name ?? '',
            'student_category_id' => $student->student_category_id,
            'fee_heads' => $feeHeadsData,
            'total_due_amount' => number_format($totalDueAmount, 2),
        ];

        return $this->responseSuccess([
            'student_data' => $studentData,
        ], 'Student Unpaid Info fetched successfully.');
    }

    public function studentNoticeGet(Request $request): JsonResponse
    {
        $perPage = (int) $request->per_page ?: 10;
        $notices = Notice::select('id', 'title', 'notice', 'date', 'created_by')->with('userType')->paginate($perPage);

        return $this->responseSuccess($notices, 'Notices fetch successfully.');
    }

    public function studentEventGet(Request $request): JsonResponse
    {
        $perPage = (int) $request->per_page ?: 10;
        $events = Event::select('id', 'start_date', 'end_date', 'name', 'details', 'location')->paginate($perPage);

        return $this->responseSuccess($events, 'Events fetch successfully.');
    }

    public function studentBehaviorGet(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();

        $perPage = (int) $request->per_page ?: 10;
        $events = Behavior::where('institute_id', get_institute_id())
            ->where('branch_id', get_branch_id())
            ->where('student_id', $studentId)
            ->paginate($perPage);

        return $this->responseSuccess($events, 'Behaviors fetch successfully.');
    }

    public function studentGamificationGet(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();

        $perPage = (int) $request->per_page ?: 10;
        $events = Gamification::where('institute_id', get_institute_id())
            ->where('branch_id', get_branch_id())
            ->where('student_id', $studentId)
            ->paginate($perPage);

        return $this->responseSuccess($events, 'Gamification fetch successfully.');
    }

    public function subjectList(): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();

        $studentSession = StudentSession::with('student')->where('student_id', $studentId)->first();
        if (! $studentSession) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        $group = $studentSession->student?->group;

        // Fetch compulsory subjects
        $compulsorySubjects = Subject::select(
            'subjects.id AS id',
            'subjects.subject_name',
            'subjects.subject_code',
            'subjects.subject_type',
            'subjects.class_id',
            'subjects.group_id'
        )
            ->where('subjects.class_id', $studentSession->class_id)
            ->whereNull('subjects.group_id')
            ->get();

        // Fetch group-based subjects
        $groupSubjects = Subject::select(
            'subjects.id AS id',
            'subjects.subject_name',
            'subjects.subject_code',
            'subjects.subject_type',
            'subjects.class_id',
            'subjects.group_id'
        )
            ->where('subjects.class_id', $studentSession->class_id)
            ->where('subjects.group_id', $group)
            ->get();

        // Merge results
        $subjects = $compulsorySubjects->merge($groupSubjects);

        if ($subjects->isEmpty()) {
            return $this->responseError([], _lang('Something went wrong. Subject not found.'));
        }

        return $this->responseSuccess($subjects, 'Student Subjects fetched successfully.');
    }

    public function studentPrayerGet(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();
        $studentSession = StudentSession::where('student_id', $studentId)->first();
        if (! $studentSession) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        $student = $studentSession->student;
        $perPage = (int) $request->per_page ?: 10;
        $events = Prayer::where('institute_id', get_institute_id())
            ->where('branch_id', get_branch_id())
            ->where('user_id', $student->user?->id)
            ->paginate($perPage);

        return $this->responseSuccess($events, 'Prayers fetch successfully.');
    }

    public function examList(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();
        $studentSession = StudentSession::where('student_id', $studentId)->first();
        if (! $studentSession) {
            return $this->responseError([], _lang('Something went wrong. Student not found.'), 404);
        }

        // Check for existing assignments in a single query
        $existingExams = ClassExam::where('class_id', $studentSession->class_id)
            ->with('exam', 'class', 'meritType')
            ->get();

        return $this->responseSuccess($existingExams, 'Exams fetch successfully.');
    }

    public function examResult(Request $request): JsonResponse
    {
        $studentId = (int) get_authenticated_parent_student_id();
        $examId = (int) $request->exam_id;

        $studentSession = StudentSession::with(['student', 'class', 'section'])
            ->where('student_id', $studentId)
            ->first();

        if (! $studentSession) {
            return $this->responseError([], _lang('Student session not found.'), 404);
        }

        $examMarks = ExamMark::with(['subject', 'exam'])
            ->where('student_id', $studentId)
            ->where('exam_id', $examId)
            ->get();

        if ($examMarks->isEmpty()) {
            return $this->responseSuccess([], _lang('No exam results found.'));
        }

        $totalObtained = $examMarks->sum('total_marks');
        $totalGradePoint = $examMarks->sum('grade_point');
        $totalSubjects = $examMarks->count();

        $fullMarksPerSubject = 100;
        $totalFullMarks = $fullMarksPerSubject * $totalSubjects;
        $percentage = round(($totalObtained / $totalFullMarks) * 100, 2);
        $overallGrade = $this->getOverallGrade($percentage);
        $overallGradePoint = round($totalGradePoint / $totalSubjects, 2); // average

        // Grade to remark map
        $getRemarks = function ($grade) {
            return match ($grade) {
                'A+' => 'Excellent',
                'A' => 'Very Good',
                'B+' => 'Good',
                'B' => 'Satisfactory',
                'C' => 'Needs Improvement',
                default => 'Poor',
            };
        };

        // Map each subject result
        $subjects = $examMarks->map(function ($mark) use ($fullMarksPerSubject, $getRemarks) {
            return [
                'name' => $mark->subject->subject_name,
                'full_marks' => $fullMarksPerSubject,
                'marks_obtained' => (float) $mark->total_marks,
                'grade' => $mark->grade,
                'remarks' => $getRemarks($mark->grade),
            ];
        });

        // Calculate position in class (optional)
        $position = (int) $this->getStudentPosition($studentSession->class_id, $studentSession->section_id, $examId, $studentId);

        // Final response
        $response = [
            'student' => [
                'id' => $studentSession->student->student_id ?? 'STU12345',
                'name' => $studentSession->student->full_name ?? $studentSession->student->first_name.' '.$studentSession->student->last_name,
                'class' => $studentSession->class->class_name ?? 'N/A',
                'section' => $studentSession->section->section_name ?? 'N/A',
                'roll' => $studentSession->roll,
            ],
            'exam' => [
                'name' => $examMarks[0]->exam->name,
                'year' => now()->year,
                'total_marks' => $totalFullMarks,
                'obtained_marks' => $totalObtained,
                'percentage' => $percentage,
                'grade' => $overallGrade,
                'grade_point' => $overallGradePoint,
                'result' => $percentage >= 40 ? 'Pass' : 'Fail',
            ],
            'subjects' => $subjects,
            'position_in_class' => $position,
            'teacher_remarks' => 'Great performance overall. Keep improving!',
            'issue_date' => now()->toDateString(),
        ];

        return $this->responseSuccess($response, 'Progress report fetched successfully.');
    }

    private function getStudentPosition($classId, $sectionId, $examId, $studentId): string
    {
        // Get all students' total marks in the same class & section for this exam
        $allMarks = ExamMark::selectRaw('student_id, SUM(total_marks) as total')
            ->where('exam_id', $examId)
            ->where('class_id', $classId)
            ->where('group_id', $sectionId) // Assuming section is stored in group_id
            ->groupBy('student_id')
            ->orderByDesc('total')
            ->get();

        // Get the position (rank) of the current student
        foreach ($allMarks as $index => $mark) {
            if ($mark->student_id == $studentId) {
                return $index + 1;
            }
        }

        return 'N/A';
    }

    private function getOverallGrade($percentage): string
    {
        return match (true) {
            $percentage >= 80 => 'A+',
            $percentage >= 70 => 'A',
            $percentage >= 60 => 'B+',
            $percentage >= 50 => 'B',
            $percentage >= 40 => 'C',
            default => 'F',
        };
    }

    public function libraryHistory(Request $request): JsonResponse
    {
        $studentId = get_authenticated_parent_student_id();

        // Fetch the member by student ID
        $member = LibraryMember::join('users', 'users.id', '=', 'library_members.user_id')
            ->select(
                'users.id',
                'users.name',
                'users.email',
                'users.phone',
                'users.user_type',
                'users.image',
                'library_members.*'
            )
            ->where('library_members.student_id', $studentId)
            ->first();

        if (! $member) {
            return $this->responseError([], _lang('Library member not found.'));
        }

        // Fetch the book issues for the student
        $issues = BookIssue::select(
            'book_issues.id',
            'book_issues.library_id',
            'book_issues.issue_date',
            'book_issues.due_date',
            'book_issues.return_date',
            'book_issues.type',
            'books.id as book_id',
            'books.book_name',
            'books.code',
            'books.category'
        )
            ->join('books', 'books.id', '=', 'book_issues.book_id')
            ->where('book_issues.student_id', $studentId)
            ->orderByDesc('book_issues.id')
            ->get();

        // Prepare response
        $data = $member->toArray();
        $data['issues'] = $issues;

        return $this->responseSuccess($data, 'Student Library History fetched successfully.');
    }
}
