File "ParentApiController.php"

Full Path: /home/trinadezambia/public_html/admin_panel/app/Http/Controllers/Api/ParentApiController.php
File size: 112.7 KB
MIME-type: text/x-php
Charset: utf-8

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\TimetableCollection;
use App\Http\Resources\UserDataResource;
use App\Models\School;
use App\Repositories\Announcement\AnnouncementInterface;
use App\Repositories\Assignment\AssignmentInterface;
use App\Repositories\AssignmentSubmission\AssignmentSubmissionInterface;
use App\Repositories\Attendance\AttendanceInterface;
use App\Repositories\DiaryStudent\DiaryStudentInterface;
use App\Repositories\Exam\ExamInterface;
use App\Repositories\ExamResult\ExamResultInterface;
use App\Repositories\Fees\FeesInterface;
use App\Repositories\FeesPaid\FeesPaidInterface;
use App\Repositories\Holiday\HolidayInterface;
use App\Repositories\Lessons\LessonsInterface;
use App\Repositories\OnlineExam\OnlineExamInterface;
use App\Repositories\PaymentConfiguration\PaymentConfigurationInterface;
use App\Repositories\PaymentTransaction\PaymentTransactionInterface;
use App\Repositories\SchoolSetting\SchoolSettingInterface;
use App\Repositories\Sliders\SlidersInterface;
use App\Repositories\Student\StudentInterface;
use App\Repositories\SubjectTeacher\SubjectTeacherInterface;
use App\Repositories\SystemSetting\SystemSettingInterface;
use App\Repositories\Timetable\TimetableInterface;
use App\Repositories\Topics\TopicsInterface;
use App\Repositories\User\UserInterface;
use App\Services\CachingService;
use App\Services\FeaturesService;
use App\Services\FcmTokenService;
use App\Services\GeneralFunctionService;
use App\Services\Payment\PaymentService;
use App\Services\ResponseService;
use Barryvdh\DomPDF\Facade\Pdf;
use DateTime;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use JetBrains\PhpStorm\NoReturn;
use Throwable;
use App\Models\DiaryCategory;
use App\Models\PromoteStudent;
use App\Models\Students;
use App\Services\UserService;

class ParentApiController extends Controller
{

    private StudentInterface $student;
    private UserInterface $user;
    private AssignmentInterface $assignment;
    private AssignmentSubmissionInterface $assignmentSubmission;
    private CachingService $cache;
    private TimetableInterface $timetable;
    private ExamInterface $exam;
    private ExamResultInterface $examResult;
    private LessonsInterface $lesson;
    private TopicsInterface $lessonTopic;
    private AttendanceInterface $attendance;
    private HolidayInterface $holiday;
    private SubjectTeacherInterface $subjectTeacher;
    private AnnouncementInterface $announcement;
    private OnlineExamInterface $onlineExam;
    private FeesInterface $fees;
    private PaymentTransactionInterface $paymentTransaction;
    private SlidersInterface $sliders;
    private FeesPaidInterface $feesPaid;
    private SubjectTeacherInterface $subjectTeachers;
    private PaymentConfigurationInterface $paymentConfigurations;
    private SystemSettingInterface $systemSetting;
    private SchoolSettingInterface $schoolSetting;
    private GeneralFunctionService $generalFunction;
    private DiaryStudentInterface $diaryStudent;
    private UserService $userService;


    public function __construct(StudentInterface $student, UserInterface $user, AssignmentInterface $assignment, AssignmentSubmissionInterface $assignmentSubmission, CachingService $cache, TimetableInterface $timetable, ExamInterface $exam, ExamResultInterface $examResult, LessonsInterface $lesson, TopicsInterface $lessonTopic, AttendanceInterface $attendance, HolidayInterface $holiday, SubjectTeacherInterface $subjectTeacher, AnnouncementInterface $announcement, OnlineExamInterface $onlineExam, FeesInterface $fees, PaymentTransactionInterface $paymentTransaction, SlidersInterface $sliders, PaymentConfigurationInterface $paymentConfigurations, FeesPaidInterface $feesPaid, SubjectTeacherInterface $subjectTeachers, SystemSettingInterface $systemSetting, SchoolSettingInterface $schoolSetting, GeneralFunctionService $generalFunction, DiaryStudentInterface $diaryStudent, UserService $userService)
    {
        $this->student = $student;
        $this->user = $user;
        $this->assignment = $assignment;
        $this->assignmentSubmission = $assignmentSubmission;
        $this->cache = $cache;
        $this->timetable = $timetable;
        $this->exam = $exam;
        $this->examResult = $examResult;
        $this->lesson = $lesson;
        $this->lessonTopic = $lessonTopic;
        $this->attendance = $attendance;
        $this->holiday = $holiday;
        $this->subjectTeacher = $subjectTeacher;
        $this->announcement = $announcement;
        $this->onlineExam = $onlineExam;
        $this->fees = $fees;
        $this->paymentTransaction = $paymentTransaction;
        $this->sliders = $sliders;
        $this->paymentConfigurations = $paymentConfigurations;
        $this->feesPaid = $feesPaid;
        $this->subjectTeachers = $subjectTeachers;
        $this->systemSetting = $systemSetting;
        $this->schoolSetting = $schoolSetting;
        $this->generalFunction = $generalFunction;
        $this->diaryStudent = $diaryStudent;
        $this->userService = $userService;
    }


    #[NoReturn] public function login(Request $request)
    {

        $validator = Validator::make($request->all(), [
            'email' => 'required|email',
            'password' => 'required',
        ], [
            'email.required' => 'The email field cannot be empty.',
            'email.email' => 'Please provide a valid email address.',
            'password.required' => 'The password field cannot be empty.',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }

        $school = School::on('mysql')->where('code', $request->school_code)->first();

        if ($school) {
            DB::setDefaultConnection('school');
            Config::set('database.connections.school.database', $school->database_name);
            DB::purge('school');
            DB::connection('school')->reconnect();
            DB::setDefaultConnection('school');
        } else {
            ResponseService::errorResponse('Invalid Login Credentials', null, config('constants.RESPONSE_CODE.INVALID_LOGIN'));
        }

        if (
            Auth::attempt([
                'email' => $request->email,
                'password' => $request->password
            ])
        ) {
            // $auth = Auth::user()->load('child.user', 'child.class_section.class', 'child.class_section.section', 'child.class_section.medium', 'child.user.school');

            // Only active child
            $auth = Auth::user()->load([
                'child' => function ($q) {
                    $q->whereHas('user.student', function ($q) {
                        $q->where('status', 1);
                    })->with('class_section.class', 'class_section.section', 'class_section.medium', 'user.school');
                }
            ]);
            // ==============================

            // $auth->assignRole('Guardian');
            if (!$auth->hasRole('Guardian')) {
                ResponseService::errorResponse('Invalid Login Credentials', null, config('constants.RESPONSE_CODE.INVALID_LOGIN'));
            }

            // check if guardian has any child
            if ($auth->child->isEmpty()) {
                ResponseService::errorResponse('Invalid Login Credentials', null, config('constants.RESPONSE_CODE.INVALID_LOGIN'));
            }

            // Store FCM tokens using FcmTokenService
            $fcmTokenService = app(FcmTokenService::class);
            if ($request->fcm_id) {
                $fcmTokenService->storeOrUpdateToken(
                    $auth,
                    $request->fcm_id,
                    $request->device_type ?? 'android',
                    $request->device_id ?? null
                );
            }


            // session(['database_name' => $school->database_name]);
            $token = $auth->createToken($auth->first_name)->plainTextToken;
            // $token = $auth->createToken('API Token', ['school_code' => $request->school_code])->plainTextToken;
            $user = $auth;
            $extraData = [
                'fcm_id' => $request->fcm_id,
                'web_fcm' => $request->web_fcm,
                'device_type' => $request->device_type,
            ];
            $user->extra_data = $extraData;

            $request->headers->set('school_code', $request->school_code);
            ResponseService::successResponse('User logged-in!', new UserDataResource($user), ['token' => $token], config('constants.RESPONSE_CODE.LOGIN_SUCCESS'));
        } else {
            ResponseService::errorResponse('Invalid Login Credentials', null, config('constants.RESPONSE_CODE.INVALID_LOGIN'));
        }
    }

    public function subjects(Request $request)
    {
        $validator = Validator::make($request->all(), ['child_id' => 'required|numeric',]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->first();
            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($children)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $subjects = $children->currentSemesterSubjects();
            ResponseService::successResponse('Student Subject Fetched Successfully.', $subjects);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function classSubjects(Request $request)
    {
        $validator = Validator::make($request->all(), ['child_id' => 'required|numeric',]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $children = $request->user()->guardianRelationChild()->where('id', $request->child_id)->first();
            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($children)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $subjects = $children->currentSemesterClassSubjects();
            ResponseService::successResponse('Class Subject Fetched Successfully.', $subjects);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getTimetable(Request $request)
    {
        $validator = Validator::make($request->all(), ['child_id' => 'required|numeric',]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($children)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }

            // Get student's subjects
            $studentSubjects = $children->currentSemesterSubjects();

            $core_subjects = $studentSubjects["core_subject"]->pluck('id')->toArray();

            $elective_subjects = $studentSubjects["elective_subject"] ?? [];

            if ($elective_subjects) {
                $elective_subjects = $elective_subjects->pluck('class_subject.subject.id')->toArray();
            }

            $subjectIds = array_merge($core_subjects, $elective_subjects);

            // Get timetable with filtered subjects
            $timetable = $this->timetable->builder()
                ->where('class_section_id', $children->class_section_id)
                ->where(function ($query) use ($subjectIds) {
                    $query->whereIn('subject_id', $subjectIds)
                        ->orWhereNull('subject_id');
                })
                ->where(function ($query) use ($subjectIds) {
                    $query->whereHas('subject_teacher', function ($q) use ($subjectIds) {
                        $q->whereIn('subject_id', $subjectIds);
                    })
                        ->orWhereDoesntHave('subject_teacher');
                })
                ->with([
                    'subject_teacher.subject:id,name,type,code,bg_color,image',
                    'subject_teacher.teacher:id,first_name,last_name'
                ])
                ->orderBy('day')
                ->orderBy('start_time')
                ->get();

            ResponseService::successResponse("Timetable Fetched Successfully", new TimetableCollection($timetable));
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }


    public function getLessons(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'lesson_id' => 'nullable|numeric',
            'class_subject_id' => 'required',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }

        try {
            //            $children = $request->user()->guardianRelationChild()->where('id', $request->child_id)->first();
            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($children)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $lessonQuery = $this->lesson->builder()->whereHas('lesson_commons', function ($q) use ($request, $children) {
                $q->whereHas('syllabus.class_subject', function ($q) use ($request) {
                    $q->where('id', $request->class_subject_id);
                })->where('class_section_id', $children->class_section_id);
            })->with('topic', 'file')->orderBy('id', 'desc');
            if ($request->lesson_id) {
                $lessonQuery->where('id', $request->lesson_id);
            }

            $lessonData = $lessonQuery->get();

            ResponseService::successResponse("Lessons Fetched Successfully", $lessonData);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }


    public function getLessonTopics(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'lesson_id' => 'required|numeric',
            'topic_id' => 'nullable|numeric',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }

        try {
            $student = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($student)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $data = $this->lessonTopic->builder()->where('lesson_id', $request->lesson_id)->with('file');
            if ($request->topic_id) {
                $data->where('id', $request->topic_id);
            }
            $data = $data->get();
            ResponseService::successResponse("Topics Fetched Successfully", $data);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getAssignments(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'assignment_id' => 'nullable|numeric',
            'class_subject_id' => 'nullable|numeric',
            'is_submitted' => 'nullable|numeric',
        ]);

        if ($validator->fails()) {
            return ResponseService::validationError($validator->errors()->first());
        }

        try {
            /* -------------------------------------------------
             | 1. Resolve child (student) safely
             -------------------------------------------------*/
            $child = Auth::user()
                ->guardianRelationChild()
                ->where('id', $request->child_id)
                ->whereHas('user', function ($q) {
                    $q->whereNull('deleted_at');
                })
                ->with('class_section')
                ->first();

            if (
                !$child ||
                !$child->class_section_id ||
                !$child->class_section ||
                !$child->class_section->class_id
            ) {
                return ResponseService::errorResponse(
                    "Child's Account is not Active. Contact School Support",
                    null,
                    config('constants.RESPONSE_CODE.INACTIVE_CHILD')
                );
            }

            $classSectionId = $child->class_section_id;
            $classId = $child->class_section->class_id;

            /* -------------------------------------------------
             | 2. Resolve allowed class_subject_ids for child
             -------------------------------------------------*/
            $allowedClassSubjectIds = DB::table('class_subjects')
                ->where('class_id', $classId)
                ->where(function ($q) use ($child) {

                    // Compulsory → always allowed
                    $q->where('type', 'Compulsory')

                        // Elective → only if assigned to child
                        ->orWhere(function ($q) use ($child) {
                            $q->where('type', 'Elective')
                                ->whereExists(function ($sub) use ($child) {
                                    $sub->select(DB::raw(1))
                                        ->from('student_subjects')
                                        ->whereColumn(
                                            'student_subjects.class_subject_id',
                                            'class_subjects.id'
                                        )
                                        ->where('student_subjects.student_id', $child->user_id);
                                });
                        });
                })
                ->pluck('id');

            /* -------------------------------------------------
             | 3. Base assignment query
             -------------------------------------------------*/
            $data = $this->assignment->builder()
                ->with([
                    'file',
                    'class_subject.subject',
                    'submission' => function ($query) use ($child) {
                        $query->where('student_id', $child->user_id)
                            ->with('file');
                    }
                ])
                ->whereHas('assignment_commons', function ($query) use ($classSectionId, $allowedClassSubjectIds) {
                    $query->where('class_section_id', $classSectionId)
                        ->whereIn('class_subject_id', $allowedClassSubjectIds);
                });

            /* -------------------------------------------------
             | 4. Filters
             -------------------------------------------------*/
            if ($request->assignment_id) {
                $data->where('id', $request->assignment_id);
            }

            // Optional class_subject filter (still validated server-side)
            if ($request->class_subject_id) {
                $data->whereHas('assignment_commons', function ($query) use ($request, $allowedClassSubjectIds) {
                    $query->where('class_subject_id', $request->class_subject_id)
                        ->whereIn('class_subject_id', $allowedClassSubjectIds);
                });
            }

            // Submission filter
            if (isset($request->is_submitted)) {
                if ((int) $request->is_submitted === 1) {
                    $data->whereHas('submission', function ($q) use ($child) {
                        $q->where('student_id', $child->user_id);
                    });
                } else {
                    $data->whereDoesntHave('submission', function ($q) use ($child) {
                        $q->where('student_id', $child->user_id);
                    });
                }
            }

            /* -------------------------------------------------
             | 5. Response
             -------------------------------------------------*/
            $result = $data
                ->orderBy('id', 'desc')
                ->paginate(15);

            ResponseService::successResponse(
                'Assignments Fetched Successfully',
                $result
            );
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getAttendance(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'month' => 'nullable|numeric',
            'year' => 'nullable|numeric',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $children = $request->user()->guardianRelationChild()->where('id', $request->child_id)->first();
            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($children)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $sessionYear = $this->cache->getDefaultSessionYear($children->school_id);

            $attendance = $this->attendance->builder()->where(['student_id' => $children->user_id, 'session_year_id' => $sessionYear->id]);
            $holidays = $this->holiday->builder();
            if (isset($request->month)) {
                $attendance = $attendance->whereMonth('date', $request->month);
                $holidays = $holidays->whereMonth('date', $request->month);
            }

            if (isset($request->year)) {
                $attendance = $attendance->whereYear('date', $request->year);
                $holidays = $holidays->whereYear('date', $request->year);
            }
            $attendance = $attendance->get();
            $holidays = $holidays->get();

            $data = ['attendance' => $attendance, 'holidays' => $holidays, 'session_year' => $sessionYear];

            ResponseService::successResponse("Attendance Details Fetched Successfully", $data);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getAnnouncements(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'type' => 'required|in:subject,class',
            'child_id' => 'required_if:type,subject,class|numeric',
            'class_subject_id' => 'required_if:type,subject|numeric'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $children = $request->user()->guardianRelationChild()->where('id', $request->child_id)->first();
            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($children)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $classSectionId = $children->class_section_id;

            $sessionYear = $this->cache->getDefaultSessionYear($children->school_id);
            if (isset($request->type) && $request->type == "subject") {
                $table = $this->subjectTeacher->builder()->where(['class_section_id' => $children->class_section_id, 'class_subject_id' => $request->class_subject_id])->get()->pluck('id');
                if ($table === null) {
                    ResponseService::errorResponse("Invalid Subject ID", null, config('constants.RESPONSE_CODE.INVALID_SUBJECT_ID'));
                }
            }
            $data = $this->announcement->builder()->with('file')->where('session_year_id', $sessionYear->id);

            if (isset($request->type) && $request->type == "class") {
                $data = $data->whereHas('announcement_class', function ($query) use ($classSectionId) {
                    $query->where(['class_section_id' => $classSectionId, 'class_subject_id' => null]);
                });
            }


            if (isset($request->type) && $request->type == "subject") {
                $data = $data->whereHas('announcement_class', function ($query) use ($classSectionId, $request) {
                    $query->where(['class_section_id' => $classSectionId, 'class_subject_id' => $request->class_subject_id]);
                });
            }

            $data = $data->orderBy('id', 'desc')->paginate(15);
            ResponseService::successResponse("Announcement Details Fetched Successfully", $data);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getSessionYear(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $children = $request->user()->guardianRelationChild()->where('id', $request->child_id)->first();
            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($children)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $sessionYear = $this->cache->getDefaultSessionYear($children->school_id);
            ResponseService::successResponse("Session Year Fetched Successfully", $sessionYear ?? []);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getChildProfileDetails(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $childData = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->with(['class_section' => function ($query) {
            //                $query->with('section', 'class', 'medium', 'class.shift', 'class.stream');
            //            }, 'guardian', 'user'                                                                                      => function ($q) {
            //                $q->with('extra_student_details.form_field', 'school');
            //            }])->first();

            $childData = Auth::user()->guardianRelationChild()->with([
                'class_section' => function ($query) {
                    $query->with('section', 'class', 'medium', 'class.shift', 'class.stream');
                },
                'guardian',
                'user' => function ($q) {
                    $q->with('extra_student_details.form_field', 'school');
                }
            ])->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($childData)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }

            $data = array(
                'id' => $childData->id,
                'first_name' => $childData->user->first_name,
                'last_name' => $childData->user->last_name,
                'mobile' => $childData->user->mobile,
                'roll_number' => $childData->roll_number,
                'admission_no' => $childData->admission_no,
                'admission_date' => $childData->admission_date,
                'gender' => $childData->user->gender,
                'image' => $childData->user->image,
                'dob' => $childData->user->dob,
                'current_address' => $childData->user->current_address,
                'permanent_address' => $childData->user->permanent_address,
                'occupation' => $childData->user->occupation,
                'status' => $childData->user->status,
                'fcm_id' => $childData->user->fcm_id,
                'school_id' => $childData->school_id,
                'session_year_id' => $childData->session_year_id,
                'email_verified_at' => $childData->user->email_verified_at,
                'created_at' => $childData->created_at,
                'updated_at' => $childData->updated_at,
                'class_section' => $childData->class_section,
                'guardian' => $childData->guardian,
                'extra_details' => $childData->user->extra_student_details,
                'school' => $childData->user->school,
            );
            ResponseService::successResponse('Data Fetched Successfully', $data);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getExamList(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'status' => 'nullable:digits:0,1,2,3'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $student = $this->student->findById($request->child_id, ['id', 'user_id', 'class_section_id'], ['class_section']);
            $student = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($student)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $classId = $student->class_section->class_id;
            $exam = $this->exam->builder()
                ->where('class_id', $classId)
                ->with([
                    'timetable' => function ($query) {
                        $query->selectRaw('* , SUM(total_marks) as total_marks')
                            ->groupBy('exam_id');
                    }
                ])->has('timetable')->orderBy('id', 'DESC')->get();

            $exam_data = array();
            // 3 => All Details, 0 => Upcoming, 1 => On Going, 2 => Completed
            foreach ($exam as $data) {
                if (isset($request->status) && $request->status != $data->exam_status && $request->status != 3) {
                    continue;
                }

                $exam_data[] = [
                    'id' => $data->id,
                    'name' => $data->name,
                    'description' => $data->description,
                    'publish' => $data->publish,
                    'session_year' => $data->session_year->name,
                    'exam_starting_date' => $data->start_date,
                    'exam_ending_date' => $data->end_date,
                    'exam_status' => $data->exam_status,
                ];
            }

            ResponseService::successResponse("Exam List fetched Successfully", $exam_data ?? []);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e, 'parentApiController :- getExamList Method');
            ResponseService::errorResponse();
        }
    }

    public function getExamDetails(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'exam_id' => 'required|nullable'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $studentData = $this->student->findById($request->child_id, ['id', 'user_id', 'class_section_id'], ['class_section']);
            $studentData = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($studentData)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $classId = $studentData->class_section->class_id;
            $studentSubjects = $studentData->currentSemesterSubjects();
            $coreSubjects = $studentSubjects['core_subject']->pluck('id')->toArray();
            $electiveSubjects = $studentSubjects['elective_subject'] ?? [];
            if ($electiveSubjects) {
                $electiveSubjects = $electiveSubjects->pluck('class_subject.subject.id')->toArray();
            }
            $subjectIds = array_merge($coreSubjects, $electiveSubjects);
            $examData = $this->exam->builder()
                ->where([
                    'id' => $request->exam_id,
                    'class_id' => $classId
                ])
                ->with([
                    'timetable' => function ($query) use ($subjectIds) {
                        $query->owner()
                            ->with(['class_subject.subject'])
                            ->whereHas('class_subject', function ($q) use ($subjectIds) {
                                $q->whereIn('subject_id', $subjectIds); // filter by actual subject
                            })
                            ->orderBy('date');
                    }
                ])
                ->first();


            if (!$examData) {
                ResponseService::successResponse("", []);
            }


            foreach ($examData->timetable as $data) {
                $exam_data[] = array(
                    'exam_timetable_id' => $data->id,
                    'total_marks' => $data->total_marks,
                    'passing_marks' => $data->passing_marks,
                    'date' => $data->date,
                    'starting_time' => $data->start_time,
                    'ending_time' => $data->end_time,
                    'subject' => array(
                        'id' => $data->class_subject->subject->id,
                        'class_subject_id' => $data->class_subject_id,
                        'name' => $data->class_subject->subject->name,
                        'bg_color' => $data->class_subject->subject->bg_color,
                        'image' => $data->class_subject->subject->image,
                        'type' => $data->class_subject->subject->type,
                    )
                );
            }
            ResponseService::successResponse("", $exam_data ?? []);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e, 'parentApiController :- getExamDetails Method');
            ResponseService::errorResponse();
        }
    }

    public function getExamMarks(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            // Student Data
            //            $studentData = $this->student->findById($request->child_id, ['id', 'user_id', 'class_section_id'], ['class_section']);
            $studentData = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($studentData)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            // Exam Result Data
            $examResultDB = $this->examResult->builder()->with([
                'user' => function ($q) {
                    $q->select('id', 'first_name', 'last_name')->with('student:id,user_id,roll_number');
                },
                'exam.timetable:id,exam_id,start_time,end_time',
                'session_year',
                'exam.marks' => function ($q) use ($studentData) {
                    $q->where('student_id', $studentData->user_id)
                        ->with([
                            'class_subject' => function ($q) {
                                $q->withTrashed()->with([
                                    'subject' => function ($q) {
                                        $q->withTrashed();
                                    }
                                ]);
                            }
                        ]);;
                }
            ])->where('student_id', $studentData->user_id);

            if ($request->session_year_id) {
                $examResultDB = $examResultDB->where('session_year_id', $request->session_year_id);
            }

            $examResultDB = $examResultDB->get();


            // Check that Exam Result DB is not empty
            if (count($examResultDB)) {
                foreach ($examResultDB as $examResultData) {
                    $exam_result = array(
                        'result_id' => $examResultData->id,
                        'exam_id' => $examResultData->exam_id,
                        'exam_name' => $examResultData->exam->name,
                        'class_name' => $studentData->class_section->full_name,
                        'student_name' => $examResultData->user->full_name,
                        'exam_date' => $examResultData->exam->start_date,
                        'total_marks' => $examResultData->total_marks,
                        'obtained_marks' => $examResultData->obtained_marks,
                        'percentage' => $examResultData->percentage,
                        'grade' => $examResultData->grade,
                        'session_year' => $examResultData->session_year->name,
                    );
                    $exam_marks = array();
                    foreach ($examResultData->exam->marks as $marks) {
                        $exam_marks[] = array(
                            'marks_id' => $marks->id,
                            'subject_name' => $marks->class_subject->subject->name,
                            'subject_type' => $marks->class_subject->subject->type,
                            'total_marks' => $marks->timetable->total_marks,
                            'passing_marks' => $marks->timetable->passing_marks,
                            'obtained_marks' => $marks->obtained_marks,
                            'teacher_review' => $marks->teacher_review,
                            'grade' => $marks->grade,
                        );
                    }
                    $data[] = array(
                        'result' => $exam_result,
                        'exam_marks' => $exam_marks,
                    );
                }
                ResponseService::successResponse("Exam Result Fetched Successfully", $data ?? null);
            } else {
                ResponseService::successResponse("Exam Result Fetched Successfully", []);
            }
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getOnlineExamList(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'class_subject_id' => 'nullable|numeric'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $student = $this->student->findById($request->child_id, ['id', 'user_id', 'class_section_id', 'school_id'], ['class_section']);
            $student = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($student)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $classSectionId = $student->class_section->id;
            $sessionYear = $this->cache->getDefaultSessionYear($student->school_id);

            $onlineExamData = $this->onlineExam->builder()
                ->whereHas('online_exam_commons', function ($query) use ($student) {
                    $query->where('class_section_id', $student->class_section_id);
                })
                ->where('session_year_id', $sessionYear->id)
                ->where('end_date', '>=', now())
                ->has('question_choice')
                ->with('class_subject', 'question_choice:id,online_exam_id,marks')
                ->whereDoesntHave('student_attempt', function ($q) use ($student) {
                    $q->where('student_id', $student->user_id);
                })
                ->when($request->class_subject_id, function ($query) use ($request) {
                    $query->whereHas('online_exam_commons', function ($q) use ($request) {
                        $q->where('class_subject_id', $request->class_subject_id);
                    });
                })
                ->orderby('start_date')
                ->paginate(15);

            ResponseService::successResponse('Data Fetched Successfully', $onlineExamData);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e, "Parent API ");
            ResponseService::errorResponse();
        }
    }

    public function getOnlineExamResultList(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'class_subject_id' => 'nullable|numeric'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $student = $this->student->findById($request->child_id, ['id', 'user_id', 'class_section_id', 'school_id'], ['class_section']);
            $student = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($student)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $classSectionId = $student->class_section_id;
            if ($request->session_year_id) {
                $sessionYear = $request->session_year_id;
            } else {
                $sessionYear = $this->cache->getDefaultSessionYear($student->school_id);
                $sessionYear = $sessionYear->id;
            }

            $studentSubjects = $student->selectedStudentSubjects()->pluck('class_subject_id');
            // Get Online Exam Data Where Logged in Student have attempted data and Relation Data with Question Choice , Student's answer with user submitted question with question and its option
            $onlineExamData = $this->onlineExam->builder()
                ->when($request->class_subject_id, function ($query) use ($request, $classSectionId) {
                    $query->whereHas('online_exam_commons', function ($q) use ($request, $classSectionId) {
                        $q->where('class_subject_id', $request->class_subject_id)
                            ->where('class_section_id', $classSectionId);
                    });
                })
                ->where(['session_year_id' => $sessionYear])
                ->whereHas('student_attempt', function ($q) use ($student) {
                    $q->where('student_id', $student->user_id);
                })
                ->with('student_attempt')
                ->whereIn('class_subject_id', $studentSubjects)
                ->with([
                    'student_answers' => function ($q) use ($student) {
                        $q->where('student_id', $student->user_id)
                            ->with('user_submitted_questions.questions:id', 'user_submitted_questions.questions.options:id,question_id,is_answer');
                    }
                ])->with('question_choice:id,online_exam_id,marks', 'class_subject.subject:id,name,type,code,bg_color,image')
                // ->with('question_choice:id,online_exam_id,marks', 'student_answers.user_submitted_questions.questions:id', 'student_answers.user_submitted_questions.questions.options:id,question_id,is_answer', 'class_subject.subject:id,name,type,code,bg_color,image')
                ->orderBy('id', 'desc')->paginate(15)->toArray();

            $examListData = array(); // Initialized Empty examListData Array

            // Loop through Exam data
            foreach ($onlineExamData['data'] as $data) {
                // Reset for each exam
                $examSubmittedDate = null;
                $examSubmittedCreatedDate = null;

                // Get Total Marks of Particular Exam
                $totalMarks = collect($data['question_choice'])->sum('marks');


                // Initialized totalObtainedMarks with 0
                $totalObtainedMarks = 0;

                // Group Student's Answers by question_id
                $grouped_answers = [];
                foreach ($data['student_answers'] as $student_answer) {
                    $examSubmittedDate = date('Y-m-d', strtotime($student_answer['submitted_date']));
                    $examSubmittedCreatedDate = date('d-m-Y H:i', strtotime($student_answer['created_at']));

                    if (isset($student_answer['question_marks'])) {
                        if ($student_answer['true_answer'] == 1) {
                            $totalObtainedMarks += $student_answer['question_marks'];
                        }
                    } else {
                        $grouped_answers[$student_answer['question_id']][] = $student_answer;
                    }
                }

                // Fallback to student_attempt created_at if examSubmittedCreatedDate is not set
                if (!$examSubmittedCreatedDate && isset($data['student_attempt'][0]['created_at'])) {
                    $examSubmittedCreatedDate = date('d-m-Y H:i', strtotime($data['student_attempt'][0]['created_at']));
                }

                // Loop through Student's Grouped answers
                if (isset($grouped_answers) && count($grouped_answers) > 0) {
                    foreach ($grouped_answers as $student_answers) {

                        // Filter the options whose is_answer values is 1
                        $correct_option_ids = array_filter($student_answers[0]['user_submitted_questions']['questions']['options'], static function ($option) {
                            return $option['is_answer'] == 1;
                        });

                        // Get All Correct Options
                        $correct_option_ids = array_column($correct_option_ids, 'id');

                        // Get Student's Correct Options
                        $student_option_ids = array_column($student_answers, 'option_id');

                        // Check if the student's answers exactly match the correct answers then add marks with totalObtainedMarks
                        if (!array_diff($correct_option_ids, $student_option_ids) && !array_diff($student_option_ids, $correct_option_ids)) {
                            $totalObtainedMarks += $student_answers[0]['user_submitted_questions']['marks'];
                        }
                    }
                }

                // Make Exam List Data
                $examListData[] = array(
                    'online_exam_id' => $data['id'],
                    'subject' => array(
                        'id' => $data['class_subject']['subject']['id'],
                        'name' => $data['class_subject']['subject']['name'] . ' - ' . $data['class_subject']['subject']['type'],
                    ),
                    'title' => $data['title'],
                    'obtained_marks' => $totalObtainedMarks ?? "0",
                    'total_marks' => $totalMarks ?? "0",
                    'exam_submitted_date' => $examSubmittedCreatedDate
                );
            }

            $examList = array(
                'current_page' => $onlineExamData['current_page'],
                'data' => $examListData,
                'from' => $onlineExamData['from'],
                'last_page' => $onlineExamData['last_page'],
                'per_page' => $onlineExamData['per_page'],
                'to' => $onlineExamData['to'],
                'total' => $onlineExamData['total'],
            );

            ResponseService::successResponse("", $examList);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getOnlineExamResult(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'online_exam_id' => 'required|numeric',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $student = $this->student->findById($request->child_id, ['id', 'user_id', 'class_section_id'], ['class_section']);
            $student = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($student)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            // Online Exam Data
            $onlineExam = $this->onlineExam->builder()
                ->where('id', $request->online_exam_id)
                ->whereHas('student_attempt', function ($q) use ($student) {
                    $q->where('student_id', $student->user_id);
                })
                // ->with([
                //     'question_choice:id,online_exam_id,marks',
                //     'student_answers.user_submitted_questions.questions:id',
                //     'student_answers.user_submitted_questions.questions.options:id,question_id,is_answer',
                // ])
                ->with([
                    'student_answers' => function ($q) use ($student) {
                        $q->where('student_id', $student->user_id)
                            ->with('user_submitted_questions.questions:id', 'user_submitted_questions.questions.options:id,question_id,is_answer');
                    }
                ])->with('question_choice:id,online_exam_id,marks', 'class_subject.subject:id,name,type,code,bg_color,image')
                ->first();

            if (isset($onlineExam) && $onlineExam != null) {


                $totalQuestions = $onlineExam->question_choice->count();
                $totalMarks = $onlineExam->question_choice->sum('marks');


                $correctQuestionData = array();
                $inCorrectQuestionData = array();
                $correctQuestions = 0;
                $incorrectQuestions = 0;
                $totalObtainedMarks = "0";
                $correctQuestionIds = [];
                // Group Student's Answers by question_id
                $grouped_answers = [];
                foreach ($onlineExam->student_answers as $student_answer) {
                    if (isset($student_answer->question_marks)) {
                        if ($student_answer->true_answer == 1) {
                            $correctQuestions++;
                            $correctQuestionData[] = [
                                'question_id' => $student_answer->question_id,
                                'marks' => $student_answer->question_marks
                            ];
                            $totalObtainedMarks += $student_answer->question_marks;
                            $correctQuestionIds[] = $student_answer->question_id;
                        }
                    } else {
                        $grouped_answers[$student_answer['question_id']][] = $student_answer->toArray();
                    }
                }
                $incorrectQuestions = $totalQuestions - $correctQuestions;
                if (!empty($correctQuestionIds)) {
                    $incorrectQuestionsData = $onlineExam->question_choice
                        ->whereNotIn('id', $correctQuestionIds);
                } else {
                    $incorrectQuestionsData = $onlineExam->question_choice;
                }
                foreach ($incorrectQuestionsData as $incorrectData) {
                    $inCorrectQuestionData[] = [
                        'question_id' => $incorrectData->id,
                        'marks' => $incorrectData->marks
                    ];
                }

                // Loop through Student's Grouped answers
                if (isset($grouped_answers) && $grouped_answers != null) {
                    foreach ($grouped_answers as $student_answers) {

                        // Filter the options whose is_answer values is 1
                        $correct_option_ids = array_filter($student_answers[0]['user_submitted_questions']['questions']['options'], static function ($option) {
                            return $option['is_answer'] == 1;
                        });

                        // Get All Correct Options
                        $correct_option_ids = array_column($correct_option_ids, 'id');

                        // Get Student's Correct Options
                        $student_option_ids = array_column($student_answers, 'option_id');

                        // Check if the student's answers exactly match the correct answers then add marks with totalObtainedMarks
                        if (!array_diff($correct_option_ids, $student_option_ids) && !array_diff($student_option_ids, $correct_option_ids)) {

                            // Sum Question marks with ObtainedMarks
                            $totalObtainedMarks += $student_answers[0]['user_submitted_questions']['marks'];

                            // Get Correct Questions Ids
                            $correctQuestionIds[] = $student_answers[0]['user_submitted_questions']['id'];

                            // Increment Correct Question by 1
                            ++$correctQuestions;

                            // Correct Question Data
                            $correctQuestionData[] = array(
                                'question_id' => $student_answers[0]['user_submitted_questions']['id'],
                                'marks' => $student_answers[0]['user_submitted_questions']['marks']
                            );
                        }
                    }


                    // Check correctQuestionIds exists and not empty
                    if (!empty($correctQuestionIds)) {
                        // Get Incorrect Questions Excluding Correct answer using correctQuestionIds
                        $incorrectQuestionsData = $onlineExam->question_choice->whereNotIn('id', $correctQuestionIds);
                    } else {
                        // Get All Question Choice as incorrectQuestionsData
                        $incorrectQuestionsData = $onlineExam->question_choice;
                    }

                    // Total Incorrect Questions
                    $incorrectQuestions = $incorrectQuestionsData->count();

                    // Incorrect Question Data
                    $inCorrectQuestionData = array();
                    foreach ($incorrectQuestionsData as $incorrectData) {
                        $inCorrectQuestionData[] = array(
                            'question_id' => $incorrectData->id,
                            'marks' => $incorrectData->marks
                        );
                    }
                }

                // Final Array Data
                $onlineExamResult = array(
                    'total_questions' => $totalQuestions,
                    'correct_answers' => array(
                        'total_questions' => $correctQuestions,
                        'question_data' => $correctQuestionData
                    ),
                    'in_correct_answers' => array(
                        'total_questions' => $incorrectQuestions,
                        'question_data' => $inCorrectQuestionData
                    ),
                    'total_obtained_marks' => $totalObtainedMarks,
                    'total_marks' => $totalMarks ?? '0'
                );
                ResponseService::successResponse("", $onlineExamResult);
            } else {
                ResponseService::successResponse("", []);
            }
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getOnlineExamReport(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'class_subject_id' => 'required|numeric'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $student = $this->student->findById($request->child_id, ['id', 'user_id', 'class_section_id', 'school_id'], ['class_section']);
            $student = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($student)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $sessionYear = $this->cache->getDefaultSessionYear($student->school_id);

            $onlineExams = $this->onlineExam->builder()
                ->has('question_choice')
                ->when($request->class_subject_id, function ($query) use ($request, $student) {
                    $query->whereHas('online_exam_commons', function ($q) use ($request, $student) {
                        $q->where('class_subject_id', $request->class_subject_id)
                            ->where('class_section_id', $student->class_section_id);
                    });
                })
                ->where(['session_year_id' => $sessionYear->id])
                ->whereHas('student_attempt', function ($q) use ($student) {
                    $q->where('student_id', $student->user_id);
                })
                // ->with([
                //     'question_choice:id,online_exam_id,marks',
                //     'student_answers.user_submitted_questions.questions:id',
                //     'student_answers.user_submitted_questions.questions.options:id,question_id,is_answer',
                //     'class_subject.subject:id,name,type,code,bg_color,image'
                // ])
                ->with([
                    'student_answers' => function ($q) use ($student) {
                        $q->where('student_id', $student->user_id)
                            ->with('user_submitted_questions.questions:id', 'user_submitted_questions.questions.options:id,question_id,is_answer');
                    }
                ])->with('question_choice:id,online_exam_id,marks', 'class_subject.subject:id,name,type,code,bg_color,image')
                ->paginate(10);
            $totalMarks = 0;
            $totalObtainedMarks = 0;
            if ($onlineExams->count() > 0) {
                $totalExamIds = $onlineExams->pluck('id')->toArray();
                $totalExamsAttempted = $this->user->builder()->role('Student')->where('id', $student->user_id)->has('online_exam_attempts')->count();

                $examList = array();
                foreach ($onlineExams->toArray()['data'] as $onlineExam) {
                    if (isset($onlineExam['student_answers'][0]['question_marks'])) {
                        $totalMarks = 0;
                    } else {
                        $totalMarks = collect($onlineExam['question_choice'])->sum('marks');
                    }

                    // Initialized totalObtainedMarks with 0
                    $totalObtainedMarks = "0";

                    // Group Student's Answers by question_id
                    $grouped_answers = [];
                    foreach ($onlineExam['student_answers'] as $student_answer) {
                        if (isset($student_answer['question_marks'])) {
                            $totalMarks += $student_answer['question_marks'];
                            if ($student_answer['true_answer'] == 1) {
                                $totalObtainedMarks += $student_answer['question_marks'];
                            }
                        } else {
                            $grouped_answers[$student_answer['question_id']][] = $student_answer;
                        }
                    }

                    // Loop through Student's Grouped answers
                    if (isset($grouped_answers) && count($grouped_answers) > 0) {
                        foreach ($grouped_answers as $student_answers) {

                            // Filter the options whose is_answer values is 1
                            $correct_option_ids = array_filter($student_answers[0]['user_submitted_questions']['questions']['options'], static function ($option) {
                                return $option['is_answer'] == 1;
                            });

                            // Get All Correct Options
                            $correct_option_ids = array_column($correct_option_ids, 'id');

                            // Get Student's Correct Options
                            $student_option_ids = array_column($student_answers, 'option_id');

                            // Check if the student's answers exactly match the correct answers then add marks with totalObtainedMarks
                            if (!array_diff($correct_option_ids, $student_option_ids) && !array_diff($student_option_ids, $correct_option_ids)) {
                                $totalObtainedMarks += $student_answers[0]['user_submitted_questions']['marks'];
                            }
                        }
                    }

                    // Add exam to the list
                    $examList[] = [
                        'online_exam_id' => $onlineExam['id'],
                        'title' => $onlineExam['title'],
                        'obtained_marks' => (string) $totalObtainedMarks,
                        'total_marks' => (string) $totalMarks,
                    ];
                }


                // Calculate Percentage
                if ($totalMarks > 0) {
                    // Avoid division by zero error
                    $percentage = number_format(($totalObtainedMarks * 100) / max($totalMarks, 1), 2);
                } else {
                    // If total marks is zero, then percentage is also zero
                    $percentage = 0;
                }

                // Build the final data array
                $onlineExamReportData = array(
                    'total_exams' => count($totalExamIds),
                    'attempted' => $totalExamsAttempted,
                    'missed_exams' => count($totalExamIds) - $totalExamsAttempted,
                    'total_marks' => (string) $totalMarks,
                    'total_obtained_marks' => (string) $totalObtainedMarks,
                    'percentage' => (string) $percentage,
                    'exam_list' => [
                        'current_page' => (string) $onlineExams->currentPage(),
                        'data' => array_values($examList),
                        'from' => (string) $onlineExams->firstItem(),
                        'last_page' => (string) $onlineExams->lastPage(),
                        'per_page' => (string) $onlineExams->perPage(),
                        'to' => (string) $onlineExams->lastItem(),
                        'total' => (string) $onlineExams->total(),
                    ],
                );
            } else {
                $onlineExamReportData = [];
            }


            // Return the response
            ResponseService::successResponse("", $onlineExamReportData);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getAssignmentReport(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'class_subject_id' => 'required|numeric'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            //            $student = $this->student->findById($request->child_id, ['id', 'user_id', 'class_section_id', 'school_id'], ['class_section']);
            $student = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($student)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $sessionYear = $this->cache->getDefaultSessionYear($student->school_id);

            // Assignment Data
            $assignments = $this->assignment->builder()
                ->where(['session_year_id' => $sessionYear->id])
                ->whereHas('assignment_commons', function ($query) use ($request, $student) {
                    $query->where('class_section_id', $student->class_section_id)
                        ->where('class_subject_id', $request->class_subject_id);
                })
                ->whereNotNull('points')
                ->get();

            // Get the assignment submissions
            $submitted_assignment_ids = $this->assignmentSubmission->builder()->where('student_id', $student->user_id)->whereIn('assignment_id', $assignments->pluck('id'))->pluck('assignment_id');

            // Calculate various statistics
            $total_assignments = $assignments->count();
            $total_submitted_assignments = $submitted_assignment_ids->count();
            $total_assignment_submitted_points = $assignments->sum('points');
            $total_points_obtained = $this->assignmentSubmission->builder()->whereIn('assignment_id', $submitted_assignment_ids)->sum('points');

            // Calculate the percentage
            $percentage = $total_assignment_submitted_points ? number_format(($total_points_obtained * 100) / $total_assignment_submitted_points, 2) : 0;

            // Get the submitted assignment data with points (using pagination manually)
            $perPage = 15;
            $currentPage = $request->input('page', 1);
            $offset = ($currentPage - 1) * $perPage;
            $submitted_assignment_data_with_points = $assignments->filter(function ($assignment) use ($submitted_assignment_ids) {
                return $assignment->points !== null && $submitted_assignment_ids->contains($assignment->id);
            })->slice($offset, $perPage)->map(function ($assignment) {
                return [
                    'assignment_id' => $assignment->id,
                    'assignment_name' => $assignment->name,
                    'obtained_points' => optional($assignment->submission)->points ?? 0,
                    'total_points' => $assignment->points
                ];
            });

            $assignment_report = [
                'assignments' => $total_assignments,
                'submitted_assignments' => $total_submitted_assignments,
                'unsubmitted_assignments' => $total_assignments - $total_submitted_assignments,
                'total_points' => $total_assignment_submitted_points,
                'total_obtained_points' => $total_points_obtained,
                'percentage' => $percentage,
                'submitted_assignment_with_points_data' => [
                    'current_page' => $currentPage,
                    'data' => array_values($submitted_assignment_data_with_points->toArray()),
                    'from' => $offset + 1,
                    'to' => $offset + $submitted_assignment_data_with_points->count(),
                    'per_page' => $perPage,
                    'total' => $total_submitted_assignments,
                    'last_page' => ceil($total_submitted_assignments / $perPage),
                ],
            ];


            ResponseService::successResponse("Data Fetched Successfully", $assignment_report);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    //Get Fees Details
    public function getFees(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required',
            'session_year_id' => 'nullable|numeric'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {

            $student = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            });

            if (isset($request->session_year_id) && $request->session_year_id != '') {
                $student = $student->where('session_year_id', $request->session_year_id);
            }

            $student = $student->first();


            $sessionYearId = $request->session_year_id;

            if (empty($student)) {
                // find student records from promote_students table
                $student = Students::where('id', $request->child_id)->with('class_section', 'user.optional_fees')->WhereHas('promote_student_history', function ($q) use ($sessionYearId) {
                    $q->where('session_year_id', $sessionYearId);
                })
                    ->with(['promote_student_history' => function ($q) use ($sessionYearId) {
                        $q->where('session_year_id', $sessionYearId)->with('class_section.class');
                    }])->first();
                if (empty($student)) {
                    ResponseService::successResponse("No records found");
                }
                $classId = $student->promote_student_history->class_section->class_id;
            } else {
                $classId = $student->class_section->class_id;
            }

            $fees = $this->fees->builder()->where('class_id', $classId)
                ->with([
                    'fees_class_type.fees_type',
                    'fees_paid' => function ($query) use ($student) {
                        $query->where(['student_id' => $student->user_id])
                            ->with(['compulsory_fee' => function ($q) {
                                $q->whereNull('deleted_at')->with('advance_fees');
                            }])
                            ->where('amount', '>', 0)
                            ->with([
                                'optional_fee' => function ($q) {
                                    $q->whereNull('deleted_at');
                                }
                            ]);
                    },
                    'session_year',
                    'class.medium',
                    'class.stream'
                ])->where(['session_year_id' => $sessionYearId])->orderBy('id', 'desc')->get();


            $currentDateTimestamp = new DateTime(date('Y-m-d'));

            foreach ($fees as $fee) {
                $dueCharges = 0;
                $totalFeesPaidAmount = 0;
                $totalFeesDuePaidAmount = 0;
                $fee->due_charges_in_percentage = $fee->due_charges ?? 0;
                $feesDateTimestamp = new DateTime($fee->due_date);

                // Set Optional Fees Data in response
                if (count($fee->optional_fees) > 0) {
                    collect($fee->optional_fees)->map(function ($optionalFees) use ($student) {
                        $isOptionalFeesPaid = $student->user->optional_fees->first(function ($optionalFeesPaid) use ($optionalFees, $student) {
                            return $optionalFeesPaid->fees_class_id == $optionalFees->id && $optionalFeesPaid->student_id == $student->user->id;
                        });
                        $optionalFees['is_paid'] = $isOptionalFeesPaid ? true : false;
                        $optionalFees['paid_date'] = $isOptionalFeesPaid['date'] ?? null;
                        return $optionalFees;
                    });
                }


                // Set Compulsory Fees Data in response
                if (count($fee->compulsory_fees) > 0) {
                    $fee->is_overdue = $currentDateTimestamp > $feesDateTimestamp; // true/false
                    collect($fee->compulsory_fees)->map(function ($compulsoryFees) use ($student) {
                        $isCompulsoryFeesPaid = $student->user->compulsory_fees->whereNull('deleted_at')->first(function ($compulsoryFeesPaid) use ($student) {
                            return $compulsoryFeesPaid->type == 'Full Payment' && $compulsoryFeesPaid->student_id == $student->user->id;
                        });
                        $compulsoryFees['is_paid'] = $isCompulsoryFeesPaid ? true : false;
                        return $compulsoryFees;
                    });
                }

                // Set Installment Data in Response
                if (count($fee->installments) > 0) {
                    $totalFeesAmount = $fee->total_compulsory_fees;
                    $totalInstallments = count($fee->installments);
                    $paidInstallments = 0;
                    $totalPaidAmount = 0;

                    // First pass - identify paid installments
                    foreach ($fee->installments as $installment) {
                        $installment['paid_amount'] = 0;

                        // $installment['due_date'] = date($schoolSettings['date_format'], strtotime($installment['due_date']));
                        // $installmentPaid = $student->user->compulsory_fees->whereNull('deleted_at')->first(function ($compulsoryFeesPaid) use ($installment, $student) {
                        //     return $compulsoryFeesPaid->type == "Installment Payment" && $compulsoryFeesPaid->installment_id == $installment->id && $compulsoryFeesPaid->student_id == $student->user->id;
                        // });

                        $installmentPaidAmount = $student->user->compulsory_fees
                            ->whereNull('deleted_at')
                            ->filter(function ($compulsoryFeesPaid) use ($installment, $student) {
                                return $compulsoryFeesPaid->type == "Installment Payment"
                                    && $compulsoryFeesPaid->installment_id == $installment->id
                                    && $compulsoryFeesPaid->student_id == $student->user->id;
                            });

                        $totalInstallmentPaidAmount = $installmentPaidAmount->sum('amount');

                        $installmentPaid = $installmentPaidAmount->first();

                        if (!empty($installmentPaid)) {
                            $paidInstallments++;
                            $totalPaidAmount += $installmentPaid->amount;
                            if (intval($installment->installment_amount) == intval($totalInstallmentPaidAmount)) {
                                $installment['is_paid'] = true;
                            } else {
                                $installment['is_paid'] = false;
                            }
                            $installment['minimum_amount'] = $totalInstallmentPaidAmount;
                            $installment['maximum_amount'] = $totalInstallmentPaidAmount;
                            $installment['paid_amount'] = $totalInstallmentPaidAmount;
                            $installment['due_charges_amount'] = $installmentPaid->due_charges;
                            $totalFeesPaidAmount += $totalInstallmentPaidAmount;
                            $totalFeesDuePaidAmount += $installmentPaid->due_charges;
                        } else {
                            $installment['is_paid'] = false;
                        }
                    }

                    $fee->total_paid_amount = $totalFeesPaidAmount;
                    $fee->total_due_paid_amount = $totalFeesDuePaidAmount;

                    // Calculate remaining amount and installments
                    $remainingAmount = $totalFeesAmount - $totalPaidAmount;
                    $remainingInstallments = $totalInstallments - $paidInstallments;

                    // Second pass - handle unpaid installments
                    if ($remainingInstallments > 0) {
                        // Equal amount for first (n-1) unpaid installments
                        $equalInstallmentAmount = 0;
                        if ($remainingInstallments > 1) {
                            $equalInstallmentAmount = $installment->installment_amount;
                        }

                        $unpaidInstallmentsProcessed = 0;
                        $amountDistributed = 0;

                        foreach ($fee->installments as $index => $installment) {
                            if ($installment['is_paid']) {
                                continue; // Skip paid installments
                            }

                            $unpaidInstallmentsProcessed++;
                            $installmentDueDateTimestamp = new DateTime($installment['due_date']);

                            // For last unpaid installment, use remaining balance
                            $installment['minimum_amount'] = $installment->installment_amount;

                            if ($unpaidInstallmentsProcessed == $remainingInstallments) {
                                $installment['maximum_amount'] = $remainingAmount;
                            } else {
                                $installment['maximum_amount'] = $remainingAmount - $amountDistributed;
                                $amountDistributed += $installment->installment_amount;
                            }

                            // Calculate due charges if applicable
                            if ($currentDateTimestamp > $installmentDueDateTimestamp) {
                                if ($installment->due_charges_type == "percentage") {
                                    $installment['due_charges_amount'] = ($installment['minimum_amount'] * $installment['due_charges']) / 100;
                                } else if ($installment->due_charges_type == "fixed") {
                                    $installment['due_charges_amount'] = $installment->due_charges;
                                }
                            } else {
                                $installment['due_charges_amount'] = 0;
                            }
                            $dueCharges += $installment['due_charges_amount'];

                            $fee->due_charges = $dueCharges;
                        }
                    }

                    $previousInstallmentDate = new DateTime('now -1 day');
                    // Third pass - identify current installment
                    foreach ($fee->installments as $installment) {
                        $installmentDueDateTimestamp = new DateTime($installment['due_date']);

                        /* Current date should be less then the due date && greater than the due date of previous installments */
                        /* In case of first installment, previous installment date will be current date - 1 */
                        if ($currentDateTimestamp <= $installmentDueDateTimestamp && $currentDateTimestamp > $previousInstallmentDate) {
                            $installment['is_current'] = true;
                        } else {
                            $installment['is_current'] = false;
                        }
                        $previousInstallmentDate = new DateTime($installment['due_date']);
                    }
                }
            }

            ResponseService::successResponse("Fees Fetched Successfully", $fees);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function payCompulsoryFees(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required',
            'fees_id' => 'required',
            'installment_ids' => 'nullable|array',
            'installment_ids.*' => 'required|integer',
            'advance' => 'present|numeric',
            'payment_method' => 'required|in:Stripe,Razorpay,Flutterwave,Paystack',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            DB::beginTransaction();

            // dd($request->all());

            $paymentConfigurations = $this->paymentConfigurations->builder()->where(['status' => 1, 'payment_method' => $request->payment_method])->first();

            if (empty($paymentConfigurations)) {
                ResponseService::errorResponse("Payment is not Enabled", [], config('constants.RESPONSE_CODE.ENABLE_PAYMENT_GATEWAY'));
            }

            $parentId = Auth::user()->id;

            $studentData = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($studentData)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $schoolId = $studentData->user->school_id;
            $compulsory_fees = $studentData->user->compulsory_fees()->whereNull('deleted_at')->whereHas('fees_paid', function ($q) use ($request) {
                $q->where('fees_id', $request->fees_id);
            })->get();



            $sessionYear = $this->cache->getDefaultSessionYear($schoolId);

            $fees = $this->fees->builder()
                ->where('id', $request->fees_id)
                ->with([
                    'fees_class_type' => function ($q) {
                        $q->where('optional', 0);
                    },
                    'fees_class_type.fees_type',
                    'installments.compulsory_fees' => function ($query) use ($studentData) {
                        $query->whereNull('deleted_at')->where(['student_id' => $studentData->user_id]);
                    },
                    'fees_paid' => function ($query) use ($studentData) {
                        $query->where(['student_id' => $studentData->user_id])->with('compulsory_fee', 'optional_fee');
                    }
                ])->firstOrFail();
            $fees->append(['total_compulsory_fees']);

            if (!empty($fees->fees_paid) && !empty($fees->fees_paid->is_fully_paid)) {
                ResponseService::errorResponse("Fees Already Paid", "", config('constants.RESPONSE_CODE.FEE_ALREADY_PAID'));
            }

            // If installment id is not empty then user is going to pay in installment
            $installmentDetails = [];
            if (isset($request->installment_ids) && count($request->installment_ids)) {
                $amount = 0;
                $dueChargesAmount = $instalmentWiseDue = 0;
                $validInstallmentIDS = array_intersect($fees->installments->pluck('id')->toArray(), $request->installment_ids);

                if (empty($validInstallmentIDS)) {
                    ResponseService::errorResponse('Invalid Installment ID');
                }

                // \Log::info("Valid installment IDs: ", [$validInstallmentIDS]);
                // dd('here');

                $totalInstallments = count($fees->installments);
                $remainingAmount = $fees->total_compulsory_fees;

                if (count($compulsory_fees) > 0) {
                    // $validInstallmentIDS = array_diff($validInstallmentIDS, $compulsory_fees->pluck('installment_id')->toArray());
                    // $validInstallmentIDS = 
                    // Removing the Paid installments from total installments so that minimum amount can be calculated for the remaining installments.
                    foreach ($compulsory_fees as $paidInstallment) {
                        if (!empty($paidInstallment->installment_id)) {
                            --$totalInstallments;
                            $remainingAmount -= $paidInstallment->amount;
                        }
                    }
                }


                // Calculate amount per installment
                // dd($totalInstallments, $remainingAmount);
                // $installmentAmount = $remainingAmount / $totalInstallments;

                $installmentAmount = $remainingAmount;


                foreach ($validInstallmentIDS as $key => $installment_id) {
                    $installment = $fees->installments->first(function ($data) use ($installment_id) {
                        return $data->id == $installment_id;
                    });

                    $paidByAdvance = 0;
                    foreach ($installment->compulsory_fees ?? [] as $paidFees) {
                        if (!empty($paidFees)) {
                            $paidByAdvance += $paidFees->amount;
                        }
                    }

                    // \Log::info("Paid by advance: ", [$paidByAdvance]);
                    // \Log::info("Installment data: ", [$installment]);
                    // dd($installment);

                    $installmentAmount = $installment['installment_amount'] - $paidByAdvance;
                    // Calculate Due Charges amount if installment is overdue
                    if (new DateTime(date('Y-m-d')) > new DateTime($installment['due_date'])) {
                        if ($installment->due_charges_type == "percentage") {
                            $dueChargesAmount += ($installmentAmount * $installment['due_charges']) / 100;
                            $instalmentWiseDue = ($installmentAmount * $installment['due_charges']) / 100;
                        } else if ($installment->due_charges_type == "fixed") {
                            $dueChargesAmount += $installment->due_charges;
                            $instalmentWiseDue = $installment->due_charges;
                        }
                        $amount += $installmentAmount + $instalmentWiseDue;
                    } else {
                        $dueChargesAmount = 0;
                        $amount += $installmentAmount;
                        $instalmentWiseDue = 0;
                    }
                    // Removing installment amount from remaining amount so that we can add validation for advance amount
                    // $remainingAmount -= $installmentAmount;
                    $installmentDetails[$key] = [
                        'id' => $installment_id,
                        'amount' => $installmentAmount,
                        'dueChargesAmount' => $instalmentWiseDue,
                        'due_date' => $installment['due_date'],
                    ];
                }

                // dd($installmentDetails);

                // $amount = $remainingAmount;

                if ($request->advance > $remainingAmount) {
                    ResponseService::errorResponse("Advance Amount cannot be greater then : " . $remainingAmount);
                }
            } else {
                /* Full Payment */
                $dueChargesAmount = 0;
                $amount = $fees->total_compulsory_fees;

                if (new DateTime(date('Y-m-d')) > new DateTime($fees->due_date)) {
                    $dueChargesAmount = $fees->due_charges_amount;
                    $amount += $dueChargesAmount;
                }
            }



            // if advance amount is greater than 0 and less than amount then add advance amount to amount
            // if ($request->advance > 0 && $request->advance <= $amount) {
            //     $finalAmount = $request->advance + $amount;
            // } else {
            //     $finalAmount = $amount;
            // }

            if ($request->advance > 0) {
                $finalAmount = $request->advance + $amount;
            } else {
                $finalAmount = $amount;
            }

            // \Log::info("Request data: ", [$request->all()]);
            // \Log::info("Installment data: ", [$installmentDetails]);
            // \Log::info("Compulsory fees data: ", [$compulsory_fees]);
            // \Log::info("Amount: ", [$amount]);
            // \Log::info("Final amount: ", [$finalAmount]);
            // dd($amount);

            //Add Payment Data to Payment Transactions Table
            $paymentTransactionData = $this->paymentTransaction->create([
                'user_id' => $parentId,
                'amount' => $finalAmount,
                'payment_gateway' => $request->payment_method,
                'payment_status' => 'Pending',
                'school_id' => $schoolId,
                'order_id' => null
            ]);
            // \Log::info("Due charges: ", [$dueChargesAmount, $finalAmount]);
            // dd($paymentTransactionData);

            $paymentIntent = PaymentService::create($request->payment_method, $schoolId)->createPaymentIntent(round($finalAmount, 2), [
                'user_id' => Auth::user()->id,
                'fees_id' => $request->fees_id,
                'student_id' => $studentData->user_id,
                'parent_id' => $parentId,
                'session_year_id' => $sessionYear->id,
                'payment_transaction_id' => $paymentTransactionData->id,
                'installment' => json_encode($installmentDetails, JSON_THROW_ON_ERROR),
                'total_amount' => $finalAmount,
                'advance_amount' => $request->advance,
                'dueChargesAmount' => $dueChargesAmount,
                'school_id' => $schoolId,
                'type' => 'fees',
                'fees_type' => 'compulsory',
                'is_fully_paid' => $amount > $fees->total_compulsory_fees,
                'name' => Auth::user()->full_name,
                'email' => Auth::user()->email,
                'phone' => Auth::user()->mobile,
            ]);

            // \Log::info("Payment Intent:", ['payment_intent' => $paymentIntent]);
            // dd($paymentIntent);

            if ($request->payment_method == "Flutterwave" || $request->payment_method == "Paystack") {
                $this->paymentTransaction->update($paymentTransactionData->id, ['order_id' => $paymentIntent['order_id'] ?? null, 'school_id' => $schoolId]);
                $paymentTransactionData = $this->paymentTransaction->findById($paymentTransactionData->id);
                DB::commit();

                \Log::info("Payment Intent:", ['payment_intent' => $paymentIntent]);

                // Return only the payment_link for Flutterwave
                if ($request->payment_method == "Flutterwave") {
                    ResponseService::successResponse("", [
                        "payment_link" => $paymentIntent['payment_link']
                    ]);
                } else {
                    ResponseService::successResponse("", [
                        "payment_link" => $paymentIntent['data']['authorization_url']
                    ]);
                }
            } else {
                $this->paymentTransaction->update($paymentTransactionData->id, ['order_id' => $paymentIntent->id, 'school_id' => $schoolId]);

                $paymentTransactionData = $this->paymentTransaction->findById($paymentTransactionData->id);
                // Custom Array to Show as response
                $paymentGatewayDetails = array(
                    ...$paymentIntent->toArray(),
                    'payment_transaction_id' => $paymentTransactionData->id,
                );
                DB::commit();
                ResponseService::successResponse("", ["payment_intent" => $paymentGatewayDetails, "payment_transaction" => $paymentTransactionData]);
            }
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function payOptionalFees(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required',
            'fees_id' => 'required',
            'optional_id' => 'required|array',
            'optional_id.*' => 'required|integer',
            'payment_method' => 'required|in:Stripe,Razorpay,Flutterwave,Paystack',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            DB::beginTransaction();
            $parentId = Auth::user()->id;
            $studentData = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($studentData)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            $classId = $studentData->class_section->class_id;
            $schoolId = $studentData->user->school_id;
            $sessionYear = $this->cache->getDefaultSessionYear($schoolId);

            $paymentConfigurations = $this->paymentConfigurations->builder()->where(['status' => 1, 'payment_method' => $request->payment_method])->first();

            if (empty($paymentConfigurations)) {
                ResponseService::errorResponse("Payment is not Enabled", [], config('constants.RESPONSE_CODE.ENABLE_PAYMENT_GATEWAY'));
            }


            // Fees Data
            $fees = $this->fees->builder()
                ->where('id', $request->fees_id)
                ->with([
                    'fees_class_type' => function ($q) use ($request) {
                        $q->where('optional', 1)->whereIn('id', $request->optional_id);
                    },
                    'fees_class_type.fees_type',
                    'fees_paid' => function ($query) use ($studentData) {
                        $query->where(['student_id' => $studentData->user_id])->with('optional_fee');
                    }
                ])->firstOrFail();

            $optional_fees = $studentData->user->optional_fees()->whereIn('fees_class_id', $request->optional_id)->whereHas('fees_paid', function ($q) use ($request) {
                $q->where('fees_id', $request->fees_id);
            })->get();

            if (count($optional_fees) > 0) {
                ResponseService::errorResponse("Please select only unpaid fees");
            }
            $amount = $fees->total_optional_fees;

            if ($amount <= 0) {
                ResponseService::errorResponse("No Optional Fees Found");
            }

            $optional_fee = [];
            foreach ($fees->fees_class_type as $row) {
                $optional_fee[] = [
                    'id' => $row->id,
                    'amount' => $row->amount
                ];
            }
            // Add Payment Data to Payment Transactions Table
            $paymentTransactionData = $this->paymentTransaction->create([
                'user_id' => $parentId,
                'amount' => $amount,
                'payment_gateway' => $request->payment_method,
                'payment_status' => 'Pending',
                'school_id' => $schoolId,
                'order_id' => null
            ]);

            $paymentIntent = PaymentService::create($request->payment_method, $schoolId)->createPaymentIntent($amount, [
                'fees_id' => $request->fees_id,
                'student_id' => $studentData->user_id,
                'parent_id' => $parentId,
                'session_year_id' => $sessionYear->id,
                'payment_transaction_id' => $paymentTransactionData->id,
                'total_amount' => $amount,
                'school_id' => $schoolId,
                'class_id' => $classId,
                'optional_fees_id' => json_encode($optional_fee, JSON_THROW_ON_ERROR),
                'type' => 'fees',
                'fees_type' => 'optional',
                'name' => Auth::user()->full_name,
                'email' => Auth::user()->email,
                'mobile' => Auth::user()->mobile
            ]);

            if ($request->payment_method == "Flutterwave" || $request->payment_method == "Paystack") {
                $this->paymentTransaction->update($paymentTransactionData->id, ['order_id' => $paymentIntent['order_id'] ?? null, 'school_id' => $schoolId]);
                $paymentTransactionData = $this->paymentTransaction->findById($paymentTransactionData->id);
                DB::commit();

                \Log::info("Payment Intent:", ['payment_intent' => $paymentIntent]);

                // Return only the payment_link for Flutterwave
                if ($request->payment_method == "Flutterwave") {
                    ResponseService::successResponse("", [
                        "payment_link" => $paymentIntent['payment_link']
                    ]);
                } else {
                    ResponseService::successResponse("", [
                        "payment_link" => $paymentIntent['data']['authorization_url']
                    ]);
                }
            } else {
                $this->paymentTransaction->update($paymentTransactionData->id, ['order_id' => $paymentIntent->id, 'school_id' => $schoolId]);

                $paymentTransactionData = $this->paymentTransaction->findById($paymentTransactionData->id);
                // Custom Array to Show as response
                $paymentGatewayDetails = array(
                    ...$paymentIntent->toArray(),
                    'payment_transaction_id' => $paymentTransactionData->id,
                );
                DB::commit();
                ResponseService::successResponse("", ["payment_intent" => $paymentGatewayDetails, "payment_transaction" => $paymentTransactionData]);
            }
            ResponseService::successResponse("Payment Intent Created Successfully");
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function feesPaidReceiptPDF(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|integer',
            'fees_id' => 'required|integer'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }

        try {
            // $student = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
            //     $q->whereNull('deleted_at');
            // })->with('user:id,first_name,last_name', 'class_section.class.stream', 'class_section.section', 'class_section.medium')->first();

            // if (empty($student)) {
            //     ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            // }
            // $feesPaid = $this->feesPaid->builder()->where(['fees_id' => $request->fees_id, 'student_id' => $student->user_id])
            //     ->with([
            //         'fees' => function ($q) {
            //             $q->with('class:id,medium_id,name', 'class.medium', 'fees_class_type.fees_type');
            //         },
            //         'compulsory_fee.installment_fee:id,name',
            //         'optional_fee' => function ($q) {
            //             $q->with([
            //                 'fees_class_type' => function ($q) {
            //                     $q->select('id', 'fees_type_id')->with('fees_type:id,name');
            //                 }
            //             ]);
            //         },
            //     ])->first();
            // $systemVerticalLogo = $this->systemSetting->builder()->where('name', 'vertical_logo')->first();
            // $schoolVerticalLogo = $this->schoolSetting->builder()->where('name', 'vertical_logo')->first();
            // $school = $this->cache->getSchoolSettings();
            // $data = explode("storage/", $school['horizontal_logo'] ?? '');
            // $school['horizontal_logo'] = end($data);
            // if ($school['horizontal_logo'] == null) {
            //     $systemSettings = $this->cache->getSystemSettings();
            //     $data = explode("storage/", $systemSettings['horizontal_logo'] ?? '');
            //     $school['horizontal_logo'] = end($data);
            // }
            // //            return view('fees.fees_receipt', compact('systemVerticalLogo', 'school', 'feesPaid', 'student', 'schoolVerticalLogo'));

            $student = Students::find($request->child_id);
            if (empty($student)) {
                ResponseService::errorResponse("Student Not Found");
            }


            $response = $this->userService->generateSchoolFeesReceiptPDF($request->fees_id, $student->user_id, 'api');
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
        return response()->json($response);
    }

    public function getSchoolSettings(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
            'session_year_id' => 'nullable'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $child = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($child)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }

            $settings = $this->cache->getSchoolSettings(['*'], $child->user->school_id);
            $sessionYear = $this->cache->getDefaultSessionYear($child->user->school_id);
            $semester = $this->cache->getDefaultSemesterData($child->user->school_id);
            $features = FeaturesService::getFeatures($child->user->school_id);
            $paymentGateways = $this->paymentConfigurations->builder()->select(['id', 'payment_method', 'api_key', 'currency_code'])->where('status', 1)->get();
            $data = [
                'school_id' => $child->user->school_id,
                'settings' => $settings,
                'session_year' => $sessionYear,
                'semester' => $semester,
                'features' => (count($features) > 0) ? $features : (object) [],
                'payment_gateway' => $paymentGateways
            ];
            ResponseService::successResponse('Settings Fetched Successfully.', $data);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getSliders(Request $request)
    {
        try {
            $data = $this->sliders->builder()->whereIn('type', [1, 3])->get();
            ResponseService::successResponse("Sliders Fetched Successfully", $data);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function test(Request $request)
    {
        // return $request->header();
        // DB::setDefaultConnection('school');
        // return DB::getDatabaseName();
        return Auth::user();
    }


    // add the transaction data in transaction table
    //    public function completeFeeTransaction(Request $request) {
    //        $validator = Validator::make($request->all(), [
    //            'child_id'               => 'required',
    //            'payment_transaction_id' => 'required',
    //            'payment_id'             => 'required',
    //            'payment_signature'      => 'required',
    //        ]);
    //        if ($validator->fails()) {
    //            ResponseService::validationError($validator->errors()->first());
    //        }
    //        try {
    //            DB::beginTransaction();
    //            $child = $this->student->findById($request->child_id);
    //            $this->paymentTransaction->update($request->payment_transaction_id, ['payment_id' => $request->payment_id, 'payment_signature' => $request->payment_signature, 'school_id' => $child->school_id]);
    //            DB::commit();
    //            ResponseService::successResponse("Data Updated Successfully");
    //        } catch (Throwable $e) {
    //            DB::rollBack();
    //            ResponseService::logErrorResponse($e);
    //            ResponseService::errorResponse();
    //        }
    //    }

    //get the fees paid list
    //    public function feesPaidList(Request $request) {
    //        $validator = Validator::make($request->all(), [
    //            'child_id'        => 'required',
    //            'session_year_id' => 'nullable'
    //        ]);
    //
    //        if ($validator->fails()) {
    //            ResponseService::validationError($validator->errors()->first());
    //        }
    //        try {
    //            $child = $this->student->findById($request->child_id);
    //            $currentSessionYear = $this->cache->getDefaultSessionYear($child->user->school_id);
    //            $sessionYearId = $request->session_year_id ?? $currentSessionYear->id;
    //            $fees_paid = $this->feesPaid->builder()->where(['student_id' => $child->user_id, 'session_year_id' => $sessionYearId])->with('session_year:id,name', 'class.medium')->get();
    //
    //            ResponseService::successResponse("", $fees_paid);
    //        } catch (Throwable $e) {
    //            DB::rollBack();
    //            ResponseService::logErrorResponse($e);
    //            ResponseService::errorResponse();
    //        }
    //    }


    // // Make Transaction Fail API
    // public function failPaymentTransactionStatus(Request $request){
    //     try{
    //         $update_status = PaymentTransaction::findOrFail($request->payment_transaction_id);
    //         $update_status->payment_status = 0;
    //         $update_status->save();
    //         $response = array(
    //             'error' => false,
    //             'message' => 'Data Updated Successfully',
    //             'code' => 200,
    //         );
    //     } catch (\Exception $e) {
    //         $response = array(
    //             'error' => true,
    //             'message' => trans('error_occurred'),
    //             'code' => 103,
    //         );
    //     }

    public function getStudentDiaries(Request $request)
    {
        try {
            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($children)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }
            // $student = Students::where('guardian_id', Auth::id())->first();

            // if (!$student) {
            //     return response()->json(['message' => 'Guardian record not found.'], 404);
            // }

            $diaryStudents = $this->diaryStudent->builder()
                ->where('student_id', $children->id)
                ->with([
                    'diary' => function ($query) {
                        $query->with(['diary_category', 'session_year', 'subject']);
                    }
                ])
                ->get();

            ResponseService::successResponse("Student Diaries Fetched Successfully", $diaryStudents);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }


    public function showStudentDiaryDetail(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'id' => 'required|nullable'
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }

        try {
            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();

            if (empty($children)) {
                ResponseService::errorResponse("Child's Account is not Active.Contact School Support", NULL, config('constants.RESPONSE_CODE.INACTIVE_CHILD'));
            }

            $diaryStudents = $this->diaryStudent->builder()
                ->where('id', $request->id)
                ->where('student_id', $children->id)
                ->with([
                    'diary' => function ($query) {
                        $query->with(['diary_category', 'session_year', 'subject']);
                    }
                ])
                ->firstOrFail();

            ResponseService::successResponse("Student Diary Fetched Successfully", $diaryStudents);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getChildDiaryCategories(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_id' => 'required|numeric',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {

            $children = Auth::user()->guardianRelationChild()->where('id', $request->child_id)->whereHas('user', function ($q) {
                $q->whereNull('deleted_at');
            })->first();
            // dd($children);
            $categoryIds = $this->diaryStudent
                ->builder()
                ->where('student_id', $children->user_id)
                ->with([
                    'diary' => function ($query) {
                        $query->withTrashed();
                    }
                ])
                ->get()
                ->pluck('diary.diary_category_id')
                ->unique()
                ->filter()
                ->values();

            // Fetch the DiaryCategory models with these IDs
            $categories = DiaryCategory::withTrashed()
                ->whereIn('id', $categoryIds)
                ->get();

            ResponseService::successResponse("Student Diary Categories Fetched Successfully", $categories);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getParentData()
    {
        try {

            $auth = Auth::user()->load([
                'child' => function ($q) {
                    $q->whereHas('user.student', function ($q) {
                        $q->where('status', 1);
                    })->with('class_section.class', 'class_section.section', 'class_section.medium', 'user.school');
                }
            ]);
            if (!$auth->hasRole('Guardian')) {
                ResponseService::errorResponse("Unauthorized Access");
            }
            ResponseService::successResponse("Parent Data Fetched Successfully", new UserDataResource($auth));
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }
}