<?php 
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;

if(!class_exists('Progress')){
    include_once ST_PROQYZ_LIBS_DIR . '/lms/class-progress.php'; 
}

/**
 * v3.1.0
 * status: pending
 * public Ielts Lms Ajax
 */
/**
 * steps: 
 * 0. 2 params ( quiz = null, submission_id = null)
 * 1. if quiz_version_id is not null, then get the quiz from the versioning table by version_id 
 * 2. convert the fetched quiz to unserialized quiz object 
 * 3. then with params.quiz get the params.quiz._lastModfied 
 * 4. compare the params.quiz._lastModfied with the fetched quiz._lastModfied and hash of the params.quiz with the fetched quiz hash (sha256)
 * 5. if all are same then return the quiz_version_id 
 * 6. if not same then insert the params.quiz into the versioning table, increment usage_count by 1 
 * 7. but also need to use the param.quiz_version_id to update the versioning table by usage_count decrement by 1 (quiz no longer using this version)
 * 
 */

# quiz versioning function for add or get version id
function proqyz_utils_quiz_versioning($quiz = null, $submission_id = null) {
    global $wpdb, $table_proqyz_v3_submissions_versioning, $table_proqyz_v3_progress_submissions_meta;
    # Step 0: Validate params
    if( !$quiz || !$submission_id ) {
       wp_send_json([
        "success" => false,
        "res"     => "saving failed due to required fields missing [quiz, submission_id]"
       ]);
       return;
    }

    # checking condition 
    $has_old_quiz = false; 
    $has_same_version = false;
    $update_used_counter = true; // pending check

    # Step 1: If quiz_version_id is not null, get the quiz from the versioning table by version_id
    $old_quiz = null;
    $old_quiz_version = null;
    $old_quiz_hash = null;
    
    $old_quiz_id = null;
    # get quiz version id
    $quiz_version_id = $wpdb->get_var($wpdb->prepare("SELECT meta_value FROM {$table_proqyz_v3_progress_submissions_meta} WHERE submission_id = %d AND meta_key = 'quiz_version_id'", $submission_id));
    if ( $quiz_version_id ) {
        $old_quiz_row = $wpdb->get_row($wpdb->prepare(
            "SELECT meta_value, meta_version, meta_hash, meta_data_id FROM {$table_proqyz_v3_submissions_versioning} 
            WHERE version_id = %d AND meta_key = 'quiz' LIMIT 1",
            $quiz_version_id
        ));

        if ( $old_quiz_row ) {
            $old_quiz = @unserialize($old_quiz_row->meta_value);
            $old_quiz_version = $old_quiz_row->meta_version;
            $old_quiz_hash = $old_quiz_row->meta_hash;
            $old_quiz_id = $old_quiz_row->meta_data_id;
            $has_old_quiz = true;
        }
    }

    # Step 2: Process the new quiz parameter
    $new_quiz = $quiz;
    # Step 3: Get params.quiz._lastModified
    $new_inner_quiz = isset($new_quiz->quiz)? $new_quiz->quiz : null;
    $new_quiz_version = isset($new_inner_quiz->_lastModified)? $new_inner_quiz->_lastModified : 1;
    $new_quiz_hash = hash('sha256', serialize($new_quiz));
    $new_quiz_id = isset($new_inner_quiz->_id)? $new_inner_quiz->_id : null; 


    # Step 4: Compare params.quiz._lastModified with fetched quiz._lastModified and hash comparison
    # Step 5: If all are same then return the quiz_version_id (do nothing here)
    if ( $has_old_quiz ) {
        if ( $old_quiz_version == $new_quiz_version && $old_quiz_id == $new_quiz_id ) {
            # same quiz_version_id
            # do nothing
            $has_same_version = true;
        } 

        if ( $old_quiz_version != $new_quiz_version || $old_quiz_id != $new_quiz_id ) {
            
            # then make the has_old_quiz to false
            $has_same_version = false;
        }
    }

    if( $has_old_quiz ) {
        if( $has_same_version ) {
            # nothing to do here 
            return;
        } else {
            # quiz is not same as old quiz, first update the old quiz version usage count by -1
            $wpdb->query($wpdb->prepare(
                "UPDATE {$table_proqyz_v3_submissions_versioning} 
                 SET usage_count = GREATEST(usage_count - 1, 0) 
                 WHERE version_id = %d",
                $quiz_version_id
            ));
        }
    }

    if ( !$has_old_quiz ) {
        # check if new quiz with id and version stil on versioning table then get that version_id
        $new_quiz_version_id = $wpdb->get_var($wpdb->prepare(
            "SELECT version_id FROM {$table_proqyz_v3_submissions_versioning} 
            WHERE meta_key = 'quiz' AND meta_data_id = %s AND meta_version = %s",
            $new_quiz_id,
            $new_quiz_version
        ));
        if( $new_quiz_version_id ) {
            # new quiz with id and version already exists, so return
            # update the usage count by +1 and submission meta of quiz_version_id with new_quiz_version 
            proqyz_utils_submissions_meta($submission_id, 'quiz_version_id', $new_quiz_version_id);
            # update the usage count by +1 for the new quiz version_id
            $wpdb->query($wpdb->prepare(
                "UPDATE {$table_proqyz_v3_submissions_versioning} 
                 SET usage_count = usage_count + 1, 
                     updated_at = %d 
                 WHERE version_id = %d",
                time(),
                $new_quiz_version_id
            ));
            return;
        } else {
            # new quiz is not on versioning table, so insert the new quiz into the versioning table
            $quiz_inserted = $wpdb->insert($table_proqyz_v3_submissions_versioning, [
                'meta_key' => 'quiz',
                'meta_data_id' => $new_quiz_id,
                'meta_version' => $new_quiz_version,
                'meta_value' => serialize($new_quiz),
                'meta_hash' => $new_quiz_hash,
                'created_at' => time(),
                'usage_count' => 1,
            ]);
            # new version_id
            if( $quiz_inserted ) {
                $new_version_id = $wpdb->insert_id;
                #  update the submissions meta with the new version_id
                proqyz_utils_submissions_meta($submission_id, 'quiz_version_id', $new_version_id);
                return;
            }
        }
        
    }
}

// create utils function for submissions meta for checking if meta exists or not  
// if not exists then add it
// if exists then update it
function proqyz_utils_submissions_meta($submission_id, $meta_key, $meta_value) {
    global $wpdb, $table_proqyz_v3_progress_submissions_meta;
    $meta_exists = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$table_proqyz_v3_progress_submissions_meta} WHERE submission_id = %d AND meta_key = %s", $submission_id, $meta_key));
    if($meta_exists) {
        $wpdb->update($table_proqyz_v3_progress_submissions_meta, ['meta_value' => $meta_value], ['submission_id' => $submission_id, 'meta_key' => $meta_key]);
    } else {
        $wpdb->insert($table_proqyz_v3_progress_submissions_meta, ['submission_id' => $submission_id, 'meta_key' => $meta_key, 'meta_value' => $meta_value, 'created_at' => date("U")]);
    }
}

// v2.1.0 
// util function for removing submissions meta by given submission_id and meta key
function proqyz_utils_remove_submissions_meta($submission_id = null, $meta_key = null) {
    if( $submission_id && $meta_key ) {
        $wpdb->delete($table_proqyz_progress_submissions_meta, ['submission_id' => $submission_id, 'meta_key' => $meta_key]);
    }
}

// v2.1.0 util function for remove all submissions meta by given submission_id
/**
 * working: this removes the ongoing submission data and related data
 * exlcludes: review, review_meta, evaluation_meta
 */
function proqyz_utils_remove_all_submissions_meta($submission_id = null) {
    global $wpdb, 
    $table_proqyz_v3_progress_submissions_meta, 
    $table_proqyz_v3_submissions_versioning, 
    $table_proqyz_v3_progress_submissions_user_response, 
    $table_proqyz_v3_progress_submissions_session,
    $table_proqyz_v3_progress_submissions_score,
    $table_proqyz_v3_submissions_evaluation_meta;

    if( $submission_id ) {
        # decrement the usage_count by 1 for the quiz_version_id by first fetching the quiz_version_id from the submissions meta
        $quiz_version_id = $wpdb->get_var($wpdb->prepare("SELECT meta_value FROM {$table_proqyz_v3_progress_submissions_meta} WHERE submission_id = %d AND meta_key = 'quiz_version_id'", $submission_id));
        if( $quiz_version_id ) {
            $wpdb->query($wpdb->prepare(
                "UPDATE {$table_proqyz_v3_submissions_versioning} 
                 SET usage_count = GREATEST(usage_count - 1, 0), 
                     updated_at = %d 
                 WHERE version_id = %d",
                time(),
                $quiz_version_id
            ));
        }

        # remove the json from the user response table
        # table (table_proqyz_v3_progress_submissions_user_response) reference @class-st-proqyz.php line (989 - 1006) - result key: submission_id
        $wpdb->delete($table_proqyz_v3_progress_submissions_user_response, ['submission_id' => $submission_id]);
        # remove the session detail from the session table
        # table (table_proqyz_v3_progress_submissions_session) reference @class-st-proqyz.php line (1026 - 1043) - result key: submission_id
        $wpdb->delete($table_proqyz_v3_progress_submissions_session, ['submission_id' => $submission_id]);
        # remove all submissions meta by given submission_id
        # table (table_proqyz_v3_progress_submissions_meta) reference @class-st-proqyz.php line (851 - 866) - result key: submission_id
        $wpdb->delete($table_proqyz_v3_progress_submissions_meta, ['submission_id' => $submission_id]);
        # remove the score from the submissions score table
        # table (table_proqyz_v3_progress_submissions_score) reference @class-st-proqyz.php line (1065 - 1085) - result key: submission_id
        $wpdb->delete($table_proqyz_v3_progress_submissions_score, ['submission_id' => $submission_id]);
        # remove evaluation meta from the submissions evaluation meta table
        # table (table_proqyz_v3_submissions_evaluation_meta) reference @class-st-proqyz.php line (1109 - 1129) - result key: session_id
        // $wpdb->delete($table_proqyz_v3_submissions_evaluation_meta, ['session_id' => $submission_id]);
        # remove review with review meta 
        # table (table_proqyz_v3_submissions_review) reference @class-st-proqyz.php line (1143 - 1163) - result key: result_id
    }
}

# all of params data are non serialized
function proqyz_utils_submisstion_meta_updater($submission_id = null, $params = [], $finish = 3) {
    global $wpdb, 
    $table_proqyz_v3_progress_submissions_meta, 
    $table_proqyz_v3_progress_submissions_session,
    $table_proqyz_v3_progress_submissions_user_response;

    if( $submission_id ) {
        # quiz is a non serialized quiz object (quiz, sections, questions, etc.)
        $quiz = isset($params['quiz'])? $params['quiz'] : null; 
        # quiz_title is a string
        $quiz_title = isset($params['quiz_title'])? $params['quiz_title'] : null;
        # quiz_slug is a string
        $quiz_slug = isset($params['quiz_slug'])? $params['quiz_slug'] : null;
        # session_detail is a non serialized session object (session, course, lesson, topic, etc.)
        $session_detail = isset($params['session_detail'])? $params['session_detail'] : null;
        # score is a non serialized score object (score, total_score, etc.)
        $score = isset($params['score'])? $params['score'] : null;
        # json is a non serialized json object (json, questions, answers, etc.)
        $json = isset($params['json'])? $params['json'] : null;
        $course_title = isset($params['course_title'])? $params['course_title'] : null;
        $course_subcategory = isset($params['course_subcategory'])? $params['course_subcategory'] : null;
        $session_category = isset($params['session_category'])? $params['session_category'] : null;
        $sections = isset($params['sections'])? $params['sections'] : null;

        # quiz validation ------------ 1
        if( $finish == 1 ) {
            if( !$quiz ) {
                wp_send_json([
                    "success" => false,
                    "res"     => "saving failed due to required fields missing [quiz]"
                ]);
                return;
            }
        }
        

        # add/update _migrated_from_id
        proqyz_utils_submissions_meta($submission_id, '_migrated_from_id', $submission_id);

        # get quiz version id
        if( $finish == 1 ) {
            proqyz_utils_quiz_versioning($quiz, $submission_id);
        }
        # add/update quiz_version_id
        // proqyz_utils_submissions_meta($submission_id, 'quiz_version_id', $new_quiz_version_id);


        
        // add/update quiz_title
        if( $quiz_title ) {
            proqyz_utils_submissions_meta($submission_id, 'quiz_title', $quiz_title);
        }
        // add/update quiz_slug
        if( $quiz_slug ) {
            proqyz_utils_submissions_meta($submission_id, 'quiz_slug', $quiz_slug);
        }
        // add/update session_detail
        if( $session_detail ) {
            // get check or update session_detail in '$table_proqyz_v3_progress_submissions_session' table
            $session_detail_id = $wpdb->get_var($wpdb->prepare("SELECT ID FROM {$table_proqyz_v3_progress_submissions_session} WHERE submission_id = %d", $submission_id));
            if( $session_detail_id ) {
                $wpdb->update($table_proqyz_v3_progress_submissions_session, ['session_data' => serialize($session_detail), 'updated_at' => date("U")], ['ID' => $session_detail_id]);
            } else {
                $wpdb->insert($table_proqyz_v3_progress_submissions_session, ['submission_id' => $submission_id, 'session_data' => serialize($session_detail), 'created_at' => date("U")]);
            }
        }
        // add/update json
        if( $json ) {
            // get check or update json in '$table_proqyz_v3_progress_submissions_user_response' table
            $json_id = $wpdb->get_var($wpdb->prepare("SELECT ID FROM {$table_proqyz_v3_progress_submissions_user_response} WHERE submission_id = %d", $submission_id));
            if( $json_id ) {
                $wpdb->update($table_proqyz_v3_progress_submissions_user_response, ['response_data' => serialize($json), 'updated_at' => date("U")], ['ID' => $json_id]);
            } else {
                $wpdb->insert($table_proqyz_v3_progress_submissions_user_response, ['submission_id' => $submission_id, 'response_data' => serialize($json), 'created_at' => date("U")]);
            }
        }

        // add/update score
        if( $score ) {
            //proqyz_utils_submissions_meta($submission_id, 'score', serialize($score));
            // skipped moved to direct result page
        }
        

        // add/update sections
        if( $sections ) {
            proqyz_utils_submissions_meta($submission_id, 'sections', $sections);
        }
        if( $session_category === "course" ) {
            // add/update course_title
            if( $course_title ) {
                proqyz_utils_submissions_meta($submission_id, 'course_title', $course_title);
            }
            // add/update course_subcategory
            if( $course_subcategory ) {
                proqyz_utils_submissions_meta($submission_id, 'course_subcategory', $course_subcategory);
            }
        }
    }
}







/**
 * status: completed
 */
function proqyz_ajax_save_quiz_progress() {
    global $wpdb, $table_proqyz_v3_progress_submissions, $table_proqyz_fullmock_tests_progress;
    # check if user is logged in
    if(!is_user_logged_in()){
        wp_send_json([
            "success" => false,
            "res"     => "user not logged in"
        ]);
        return;
    }

    $student_id = get_current_user_id();
    $req_data   = isset($_POST['data'])? (object) $_POST['data'] : null;
    $answers    = isset($req_data->answers)? (object) json_decode($req_data->answers) : null;

    # validation 1
    if( !$req_data ){
        wp_send_json([
            "success" => false,
            "res"     => "saving failed due to required fields missing"
        ]);
    }

    # validation 2
    if( !$answers ) {
        wp_send_json([
            "success" => false,
            "res"     => "saving failed due to required fields missing answers"
        ]);
    }

    $json_request = isset($req_data->json)? (object) $req_data->json : null;
    $finish       = isset($req_data->finish)? (int) $req_data->finish : 3;
    $json_quiz    = isset($req_data->quiz)? json_decode(stripslashes($req_data->quiz)) : null;

    # validation 3
    if($finish == 1){
        if( !$json_quiz ) {
            wp_send_json([
                "success" => false,
                "res"     => "[JSON] saving failed due to required fields missing [quiz]"
            ]);
        }
    }

    # validation 4
    if( !$json_request ){
        wp_send_json([
            "success" => false,
            "res"     => "[JSON] saving failed due to required fields missing [json]"
        ]);
    }

    # report session details
    $session = isset($json_request->session)? (object) $json_request->session : null;
    # session_category :- single,course
    if( !$session ) {
        wp_send_json([
            "success" => false,
            "res"     => "[JSON] saving failed due to required fields missing [session]"
        ]);
    }

    $progress_report = new Progress((object) $session);
    $session_report  = (object) $progress_report->check_session();
    $session_details = (object) $progress_report->get_session();

    # validation 5
    if(!$session_report && !$session_details) {
        wp_send_json([
            "success" => false,
            "res"       => "could not save the session report due to some reasons",
            "report"    => $session_report
        ]);
    } 
    
    # validation 6
    if(!isset($session_report->status)) {
        wp_send_json([
            "success" => false,
            "res"       => "could not save the session report due to some reasons",
            "report"    => $session_report
        ]);
    }


    $session_type       = isset($session_report->session_type)? $session_report->session_type : null;
    $session_category   = isset($session_report->session_category)? $session_report->session_category : null;
    $session_logic      = isset($session_report->logic)? $session_report->logic : null;
    $session_id         = isset($session_report->resume_id)? $session_report->resume_id : null;

    $report_stats = (object) [
        "quiz"  => (object) [
            "api_id"            => $session_details->api_id,
            "time"              => $req_data->time,
            "diff"              => $req_data->diff,
            "quiz_category"     => $session_details->quiz_category,
            "audio_time"        => $req_data->audio
        ],
        "answers"   => json_decode(stripslashes($req_data->answers))
    ];

    if(
        $session_type !== null && 
        $session_category !== null && 
        $session_logic !== null
    ){

        # full quiz object with questions, sections etc.
        $json_q = (object) $json_quiz;
        # main quiz object
        $quiz_j = isset($json_q->quiz)? (object) $json_q->quiz : null;
        $quiz_slug = isset($quiz_j->slug)? $quiz_j->slug : null;
        $quiz_title = isset($quiz_j->title)? $quiz_j->title : ''; 
        $course = isset($session->course)? (object) $session->course : null;
        $course_title = isset($course->title)? $course->title : '';
        $course_subcategory = isset($course->category)? $course->category : ''; 
        # sections for speaking/writing quiz type 
        $simplified_sections = array();
        $sections = null;
        $serilized_sections = null;
        if( $session_details->quiz_category === "ielts-speaking" ) {
            $sections = isset($json_q->sections)? (array) $json_q->sections : null;
        } else if( $session_details->quiz_category === "ielts-writing" ) {
            $sections = isset($json_q->sections)? (array) $json_q->sections : null;
        }

        if( $sections ) {
            foreach ($sections as $section) {
                if (is_object($section)) {
                    $simplified_section = new stdClass();
                    
                    // Extract only the required fields
                    if (isset($section->_id)) {
                        $simplified_section->_id = $section->_id;
                    }
                    if (isset($section->title)) {
                        $simplified_section->title = $section->title;
                    }
                    if (isset($section->order)) {
                        $simplified_section->order = $section->order;
                    }
                    
                    $simplified_sections[] = $simplified_section;
                }
            }
            
            // Serialize and store the simplified sections array
            if (!empty($simplified_sections)) {
                $serilized_sections = serialize($simplified_sections);
            }
        }

        $update_session = false;
        if( $session_logic == "insert" ) {

            $report_data = [
                "user_id"               => $student_id,
                "quiz_category"         => $session_details->quiz_category,
                "session_type"          => $session_details->session_type,
                "session_category"      => $session_details->session_category,
                "session_status"        => $finish? $finish : $session_details->session_status,
                "course_category"       => $session_details->course_category,
                "course_id"             => $session_details->course_id,
                "topic_id"              => $session_details->topic_id,
                "lesson_id"             => $session_details->lesson_id,
                "api_id"                => $session_details->api_id,
                "status"                => 1,
                "date_created"          => date("U")
            ];

            $insert_session = $wpdb->insert($table_proqyz_v3_progress_submissions, $report_data);
            if( $insert_session ) {
                $session_id = $wpdb->insert_id;
                $update_session = true;
            } else {
                wp_send_json([
                    "success"           => false,
                    "res"               => "Unable to save into database"     
                ]);
            }

        } else if( $session_logic == "update" ) {
            $update_session = true;
        }

        if( $update_session && $session_id ) {
            // result url if finished 
            $result_url = st_proqyz_get_result_url( $session_details->quiz_category, $quiz_slug, $session_details->api_id, $session_id );

            // update session meta by using session_id
            $pre_post_result_url = st_proqyz_get_result_analyze_url($session_details->quiz_category, $quiz_slug, $session_details->api_id, $session_id);
            // here dubug
            
            proqyz_utils_submisstion_meta_updater($session_id, [
                'quiz' => isset($json_quiz)? $json_quiz : null, # non serialized quiz object (quiz, sections, questions, etc.)
                'quiz_title' => $quiz_title,
                'quiz_slug' => $quiz_slug,
                'session_detail' => $session, # serialize($session)
                'score' => '',
                'json' => $report_stats, # serialize($report_stats)
                'session_category' => $session_details->session_category,
                'course_title' => $course_title,
                'course_subcategory' => $course_subcategory,
                'sections' => $serilized_sections
            ], $finish);

            

            // finish logic
            if($finish == 1){
                $session_status = 3; 
                // need to set progress_submission colum session_status to 3 as partical-completed 
                $isUpdate = $wpdb->update($table_proqyz_v3_progress_submissions, ['session_status' => $session_status, 'date_modified' => date("U")], ['ID' => $session_id]);
                if( !$isUpdate ) {
                    wp_send_json([
                        "success"           => false,
                        "res"               => "Unable to update session status"     
                    ]);
                }
                # apply filter for learndash course type - moving to own result analyze page
                
                # email hook - moved to own result analyze page

                // fullmock-test logic
                if( $session_category === "fullmock-test" ) {
                    $mock_test__course_id = $session_details->course_id;
                    $mock_test__lesson_id = $session_details->lesson_id;
                    $mock_test__quiz_category = $session_details->quiz_category;


                    $meta_to_add_or_update = array(
                        "user_id"               => $student_id,
                        "course_id"             => $mock_test__course_id,
                        "lesson_id"             => $mock_test__lesson_id,
                        "date"                  => date("U"),
                        "course_meta"           => serialize($session) 
                    );
                    
                    if ($mock_test__quiz_category === "ielts-listening") {
                        $mock_test__step = "listening-completed--reading-start";
                        $meta_to_add_or_update["listening"] = $session_id;
                        $meta_to_add_or_update["status"]    = 2;

                    } else if ($mock_test__quiz_category === "ielts-reading") {
                        $mock_test__step = "reading-completed--writing-start";
                        $meta_to_add_or_update["reading"] = $session_id;
                        $meta_to_add_or_update["status"]  = 2;

                    } else if ($mock_test__quiz_category === "ielts-writing") {
                        $mock_test__step = "writing-completed--speaking-start";
                        $meta_to_add_or_update["writing"] = $session_id;
                        $meta_to_add_or_update["status"]  = 2;

                    } else if ($mock_test__quiz_category === "ielts-speaking") {
                        $mock_test__step = "speaking-completed--finish-test";
                        $meta_to_add_or_update["speaking"] = $session_id;
                        $meta_to_add_or_update["status"]   = 1;

                    } else {
                        $mock_test__step = "speaking-completed--finish-test";
                        $meta_to_add_or_update["status"]   = 2;
                    }

                    update_user_meta(
                        $student_id,
                        "proqyz__full-mock-test--{$mock_test__course_id}-{$mock_test__lesson_id}",
                        [
                            'status' => $mock_test__step,
                            'date'   => current_time('mysql'),
                            'next'   => "ielts-reading"    
                        ]
                    );

                    // need table for full mock test - since 2025
                    $is_valid_mocktest_submitted = false;
                    $get_fullmock_test_session = $wpdb->get_row("SELECT * FROM {$table_proqyz_fullmock_tests_progress} WHERE `user_id` = '$student_id' AND `course_id` = '$mock_test__course_id' AND `lesson_id` = '$mock_test__lesson_id' ");
                    if( !$get_fullmock_test_session ) {
                        $is_valid_mocktest_submitted = $wpdb->insert($table_proqyz_fullmock_tests_progress, $meta_to_add_or_update);
                    } else {
                        $is_valid_mocktest_submitted = $wpdb->update($table_proqyz_fullmock_tests_progress, $meta_to_add_or_update, [
                            "user_id"               => $student_id,
                            "course_id"             => $mock_test__course_id,
                            "lesson_id"             => $mock_test__lesson_id,
                        ]);
                    }

                    // generate fullmock-analyize url
                    // $fullmock_analyize_url = st_proqyz_get_fullmock_analyize_url($mock_test__step, $session_id);
                    if($is_valid_mocktest_submitted) {
                        wp_send_json([
                            "success"           => true,
                            "res"               => "Finished",
                            "redirect"          => true,
                            "url"               => st_proqyz_get_mock_test_url( $mock_test__course_id, $mock_test__lesson_id ),
                            "result_id"         => $session_id      
                        ]);
                    } else {
                        wp_send_json([
                            "success"           => false,
                            "res"               => "Cannot submit mock test report, contact to site support team",
                            "redirect"          => true,
                            "url"               => st_proqyz_get_mock_test_url( $mock_test__course_id, $mock_test__lesson_id ),
                            "result_id"         => $session_id,
                            "error"             => $wpdb->last_error
                        ]);
                    }
                    

                } else {
                    wp_send_json([
                        "success"           => true,
                        "res"               => "Finished",
                        "redirect"          => ($quiz_slug == null)? false : true,
                        "url"               => $pre_post_result_url,
                        "result_id"         => $session_id
                    ]);
                }

            }

            // not finish then mark as saved
            wp_send_json([
                "success"           => true,
                "res"               => "saved"     
            ]);

        } else {
            wp_send_json([
                "success"           => false,
                "res"               => "Unable to save changes into db"     
            ]);
        }

    } else {
        wp_send_json([
            "success" => false,
            "res"       => "could not save the session report due to some reasons",
            "report"    => $session_report
        ]);
    }      
}



/**
 * status: completed
 */
function proqyz_ajax_save_quiz_progress_unauthorize(){
    wp_send_json([
        "success" => false,
        "res"     => "[unathorized] Unable to saving progress",
        "id"      => null  
    ]);
}

add_action('wp_ajax_proqyz-save-quiz-progress', 'proqyz_ajax_save_quiz_progress');
add_action('wp_ajax_nopriv_proqyz-save-quiz-progress', 'proqyz_ajax_save_quiz_progress_unauthorize');

/**
 * restart
 * status: completed (testing required)
 */

function proqyz_ajax_quiz_progress_restart(){
    global $wpdb, $table_proqyz_v3_progress_submissions;

    if(is_user_logged_in()){
        $student_id = get_current_user_id();
        $req_data   = isset($_POST['data'])? (object) $_POST['data'] : null;

        if( !$req_data ){
            wp_send_json([
                "success" => false,
                "res"     => "saving failed due to required fields missing"
            ]);
        }


        $json_request = isset($req_data->json)? (object) $req_data->json : null;
        if( !$json_request ){
            wp_send_json([
                "success" => false,
                "res"     => "[JSON] Restart failed due to required fields missing"
            ]);
        }

        # report session details
        $session = isset($json_request->session)? (object) $json_request->session : null;
        # session_category :- single,course
        

        if( class_exists('Progress') ) {
            $progress_report = new Progress((object) $session);
            $session_report  = (object) $progress_report->check_session();
            $session_details = (object) $progress_report->get_session();

            if(!$session_report && !$session_details) {
                wp_send_json([
                    "success" => false,
                    "res"       => "could not restart the session report due to some reasons",
                    "report"    => $session_report
                ]);
            } 

            if(isset($session_report->status)) {
                $session_type       = isset($session_report->session_type)? $session_report->session_type : null;
                $session_category   = isset($session_report->session_category)? $session_report->session_category : null;
                $session_logic      = isset($session_report->logic)? $session_report->logic : null;
                $session_id         = isset($session_report->resume_id)? $session_report->resume_id : null;


                if($session_type !== null && $session_category !== null && $session_logic !== null){

                    if( $session_logic == "update" ) {

                        proqyz_utils_remove_all_submissions_meta($session_id);
                        $remove_session = $wpdb->delete($table_proqyz_v3_progress_submissions, [
                            "user_id"               => $student_id,
                            "ID"                    => $session_id
                        ]);

                        

                        if( $remove_session ) {
                            
                            wp_send_json([
                                "success"           => true,
                                "res"               => "Restarting"     
                            ]);
                        } else {
                            wp_send_json([
                                "success"           => false,
                                "res"               => "Unable to restart , 500 error",
                                "error"             => $wpdb->last_error
                            ]);
                        }

                    }

                } else {
                    wp_send_json([
                        "success" => false,
                        "res"       => "could not restart the session report due to some reasons",
                        "report"    => $session_report
                    ]);
                }
                


            } else {
                wp_send_json([
                    "success" => false,
                    "res"       => "could not restart the session report due to some reasons",
                    "report"    => $session_report
                ]);
            }

        } else {
            wp_send_json([
                "success" => false,
                "res"     => "Class progress not found"    
            ]);
        }
    }
}

add_action('wp_ajax_proqyz-quiz-progress-restart', 'proqyz_ajax_quiz_progress_restart');


/**
 * speaking
 * status: completed (testing required)
 */
function proqyz_speaking_quiz_submit() {
    global $wpdb, 
	$table_proqyz_v3_progress_submissions, 
    $table_proqyz_v3_progress_submissions_meta,
	$table_proqyz_v3_progress_meta_submissions, 
    $table_proqyz_fullmock_tests_progress;

    if(!is_user_logged_in()){
        wp_send_json([
            "success" => false,
            "res"     => "user not logged in"
        ]);
        return;
    }

    
    $student_id             = get_current_user_id();
    $section_id             = $_POST['passage_id'];
    $section_key            = $_POST['passage_key'];
        
    $date                   = date("U");
    $intervals              = $_POST['intervals'];
    $total_parts            = $_POST['total_parts'];
    $question_ids           = $_POST['question_ids'];
    $question_ids_txt       = $question_ids;
    $question_intervals_txt = $intervals;
    $files                  = $_FILES;
    $filename               = $_POST['name'];

    $finish = 0;
    if( (int) $total_parts == ( (int) $section_key + 1) ) {
        $finish = 1;
    }

    $json_request = isset($_POST['json'])? $_POST['json'] : null;
    $json_request = (object) json_decode(stripslashes($json_request));
    $json_quiz    = isset($_POST['quiz'])? (object) json_decode(stripslashes($_POST['quiz'])) : null;

    if( !$json_request ){
        wp_send_json([
            "success" => false,
            "res"     => "[JSON] saving failed due to required fields missing"
        ]);
    }

    # report session details
    $session = isset($json_request->session)? (object) $json_request->session : null;
    # session_category :- single,course

    if( !class_exists('Progress') ) {
        wp_send_json([
            "success" => false,
            "res"     => "Progress class not found"
        ]);
        return;
    }

    $progress_report = new Progress((object) $session);
    $session_report  = (object) $progress_report->check_session();
    $session_details = (object) $progress_report->get_session();

    // valdiation only
    if(!$session_report && !$session_details) {
        wp_send_json([
            "success" => false,
            "res"       => "could not save the session report due to some reasons",
            "report"    => $session_report
        ]);
    } 

    if(!isset($session_report->status)) {
        wp_send_json([
            "success" => false,
            "res"       => "could not save the session report due to some reasons",
            "report"    => $session_report
        ]);
        return;
    }
    
    // scope all session report details
    $session_type       = isset($session_report->session_type)? $session_report->session_type : null;
    $session_category   = isset($session_report->session_category)? $session_report->session_category : null;
    $session_logic      = isset($session_report->logic)? $session_report->logic : null;
    $session_id         = isset($session_report->resume_id)? $session_report->resume_id : null;
    $quiz_category      = isset($session_details->quiz_category)? $session_details->quiz_category : null;
    $api_id             = isset($session_details->api_id)? $session_details->api_id : null;
    // other details 
    $json_q             = (object) $json_quiz;
    $quiz_j             = isset($json_q->quiz)? (object) $json_q->quiz : null;
    $quiz_slug          = isset($quiz_j->slug)? $quiz_j->slug : null;
    $quiz_title         = isset($quiz_j->title)? $quiz_j->title : '';
    $course_title       = isset($session->course->title)? $session->course->title : '';
    $course_subcategory = isset($session->course->category)? $session->course->category : '';
                

    # sections for speaking/writing quiz type 
    $simplified_sections = array();
    $sections = null;
    $serilized_sections = null;
    if( $session_details->quiz_category === "ielts-speaking" ) {
        $sections = isset($json_q->sections)? (array) $json_q->sections : null;
    } else if( $session_details->quiz_category === "ielts-writing" ) {
        $sections = isset($json_q->sections)? (array) $json_q->sections : null;
    }

    if( $sections ) {
        foreach ($sections as $section) {
            if (is_object($section)) {
                $simplified_section = new stdClass();      
                // Extract only the required fields
                if (isset($section->_id)) {
                    $simplified_section->_id = $section->_id;
                }
                if (isset($section->title)) {
                    $simplified_section->title = $section->title;
                }
                if (isset($section->order)) {
                    $simplified_section->order = $section->order;
                }
                            
                $simplified_sections[] = $simplified_section;
            }
        }
                    
        // Serialize and store the simplified sections array
        if (!empty($simplified_sections)) {
            $serilized_sections = serialize($simplified_sections);
        }
    }

    if(
        $session_type !== null && 
        $session_category !== null && 
        $session_logic !== null
    ){
        // insert and get session id or if sesion found then update session date
        $query_ok = 0;
        if( $session_logic == "insert" ) {

            $report_data = [
                "user_id"               => $student_id,
                "quiz_category"         => $session_details->quiz_category,
                "session_type"          => $session_details->session_type,
                "session_category"      => $session_details->session_category,
                "session_status"        => $session_details->session_status,
                "course_category"       => $session_details->course_category,
                "course_id"             => $session_details->course_id,
                "topic_id"              => $session_details->topic_id,
                "lesson_id"             => $session_details->lesson_id,
                "api_id"                => $session_details->api_id,
                "date_created"          => date("U"),
                "status"                => 1
            ];

            $insert_session = $wpdb->insert($table_proqyz_v3_progress_submissions, $report_data);
            if( $insert_session ) {
                $session_id = $wpdb->insert_id;
                $query_ok = 1;
            } else {
                wp_send_json([
                    "status"           => false,
                    "res"               => "Unable to save into database"     
                ]);
            }

        } else if( $session_logic == "update" ) {
            $query_ok = 1;
            $wpdb->update($table_proqyz_v3_progress_submissions, [
                "date_modified"    => date("U")
            ], [
                "ID"      => $session_id
            ]);
        }

        # IF QUERY IS OK
        if($query_ok === 1) {
            // update session meta by using session_id
            // v2.1.0 meta updater function
            proqyz_utils_submisstion_meta_updater($session_id, [
                'quiz'                  => $json_q,
                'quiz_title'            => $quiz_title,
                'quiz_slug'             => $quiz_slug,
                'session_detail'        => $session,
                'score'                 => '',
                'json'                  => '',
                'session_category'      => $session_category,
                'course_title'          => $course_title,
                'course_subcategory'    => $course_subcategory,
                'sections'              => $serilized_sections
            ], $finish);


            $insert = 0;
            $check_if_done = $wpdb->get_results("SELECT `ID`, `json`, `filename` FROM `$table_proqyz_v3_progress_meta_submissions` WHERE `user_id` = '$student_id' AND `session_type` = '$session_type' AND `session_id` = '$session_id' AND `section_id` = '$section_id' AND `status` = 1 ORDER BY `$table_proqyz_v3_progress_meta_submissions`.`date` DESC LIMIT 1");
            if( count($check_if_done) === 1) {
                foreach( $check_if_done as $skey ) {
                    $set_id = $skey->ID;
                    $json = maybe_unserialize($skey->json);
                    $filename = $skey->filename;
                    
                    # get the file and its storage type from json
                    # remove the file from the storage
                    # if remove is failed then return error
                    # if remove is successful then continue 
                    # remove the meta record row
                    # then $insert = 1 so new row and audio will be saved
                    
                    // Delete the file from storage
                    $delete_result = proqyz_delete_audio_file($json);
                    
                    if (!$delete_result['success']) {
                        // If file deletion failed, return error
                        wp_send_json([
                            "status"    => 0,
                            "res_type"  => "error",
                            "res"       => "Failed to delete previous audio file",
                            "error"     => $delete_result['error']
                        ]);
                        return;
                    }
                    
                    // If file deletion is successful, delete the meta record row
                    $delete_row = $wpdb->delete($table_proqyz_v3_progress_meta_submissions, [
                        "ID" => $set_id
                    ]);
                    
                    if ($delete_row === false) {
                        // If row deletion failed, return error
                        wp_send_json([
                            "status"    => 0,
                            "res_type"  => "error",
                            "res"       => "Failed to delete previous record",
                            "error"     => $wpdb->last_error
                        ]);
                        return;
                    }
                    
                    // Set insert flag to 1 so new row and audio will be saved
                    $insert = 1;
                }
            } else {
                $insert = 1;
            }
            
            // lets work with storage
            if( $insert === 1 ) {
                if(defined('IELTS_STORAGE')){
                    if(IELTS_STORAGE == "cpanel") {
                        $storage_response = Ielts_store_speaking_media_in_cpanel((object) [
                            "session_type"      => $session_type,
                            "session_category"  => $session_category,
                            "student_id"        => $student_id,
                            "session_id"        => $session_id,
                            "section_id"        => $section_id,
                            "files"             => $files        
                        ]);
                    } else if(IELTS_STORAGE == "AWS-S3") { 
                        $storage_response = (object) AWS_s3_upload_object((object) [
                            "session_type"      => $session_type,
                            "session_category"  => $session_category,
                            "student_id"        => $student_id,
                            "session_id"        => $session_id,
                            "section_id"        => $section_id,
                            "files"             => $files            
                        ]);
                    } else {
                        $storage_response = (object) Ielts_store_speaking_media_in_cpanel((object) [
                            "session_type"      => $session_type,
                            "session_category"  => $session_category,
                            "student_id"        => $student_id,
                            "session_id"        => $session_id,
                            "section_id"        => $section_id,
                            "files"             => $files            
                        ]);
                    }
                } else {
                    // default storage unit is cpanel
                    $storage_response = (object) Ielts_store_speaking_media_in_cpanel((object) [
                        "session_type"      => $session_type,
                        "session_category"  => $session_category,
                        "student_id"        => $student_id,
                        "session_id"        => $session_id,
                        "section_id"        => $section_id,
                        "files"             => $files            
                    ]);
                }
                
                // if storage response is successful then insert section
                if($storage_response->status === 1) {
                    // if storage response is successful then insert section progress meta - speaking
                    $insert_section = $wpdb->insert($table_proqyz_v3_progress_meta_submissions ,[
                        "user_id"               => $student_id, 
                        "session_type"          => $session_type, 
                        "session_id"            => $session_id, 
                        "quiz_id"               => $api_id,
                        "section_id"            => $section_id, 
                        "question_ids"          => $question_ids_txt, 
                        "question_intervals"    => $question_intervals_txt,    
                        "json"                  => serialize($storage_response->json), 
                        "filename"              => ($storage_response->filename), 
                        "completed"             => 1, 
                        "status"                => 1, 
                        "date"                  => date("U")
                    ]);
                    
                    // if section progress meta is inserted successfully then update session status to completed
                    if( $insert_section ) {

                        // if finish is 1 then which mean its the last section then update session status to completed
                        if($finish == 1) {
                            $wpdb->update($table_proqyz_v3_progress_submissions, [
                                "session_status"    => 3,
                                "date_modified"     => date("U")
                            ], [
                                "ID"                => $session_id
                            ]);
                            
                            $result_url = st_proqyz_get_result_url( $quiz_category, $quiz_slug, $api_id, $session_id );
                            // update session meta by using session_id
                            $pre_post_result_url = st_proqyz_get_result_analyze_url($quiz_category, $quiz_slug, $api_id, $session_id);
                            # FINISHED session

                            // apply filter to full mock test here
                            if( $session_category === "fullmock-test" ) {
                                $mock_test__course_id = $session_details->course_id; // directly from session_details
                                $mock_test__lesson_id = $session_details->lesson_id; // directly from session_details
                                $mock_test__quiz_category = $quiz_category;
                                $mock_test__step = "speaking-completed--finish-test";
                                
                                $meta_to_add_or_update = array(
                                    "user_id"               => $student_id,
                                    "course_id"             => $mock_test__course_id,
                                    "lesson_id"             => $mock_test__lesson_id,
                                    "date"                  => date("U"),
                                    "speaking"              => $session_id,
                                    "status"                => 1,
                                    "course_meta"           => serialize($session) 
                                );

                                update_user_meta(
                                    $student_id,
                                    "proqyz__full-mock-test--{$mock_test__course_id}-{$mock_test__lesson_id}",
                                    [
                                        'status' => $mock_test__step,
                                        'date'   => current_time('mysql'),
                                        'next'   => "speaking-completed--finish-test"    
                                    ]
                                );

                                // update 
                                $is_valid_mocktest_submitted = false;
                                $get_fullmock_test_session = $wpdb->get_row("SELECT * FROM {$table_proqyz_fullmock_tests_progress} WHERE `user_id` = '$student_id' AND `course_id` = '$mock_test__course_id' AND `lesson_id` = '$mock_test__lesson_id' ");
                                if( !$get_fullmock_test_session ) {
                                    $is_valid_mocktest_submitted = $wpdb->insert($table_proqyz_fullmock_tests_progress, $meta_to_add_or_update);
                                } else {
                                    $is_valid_mocktest_submitted = $wpdb->update($table_proqyz_fullmock_tests_progress, $meta_to_add_or_update, [
                                        "user_id"               => $student_id,
                                        "course_id"             => $mock_test__course_id,
                                        "lesson_id"             => $mock_test__lesson_id,
                                    ]);
                                }

                                if($is_valid_mocktest_submitted) {
                                    
                                    $is_complete_fullmock_test = complete_fullmock_test_handler($mock_test__course_id, $mock_test__lesson_id, $student_id);
                                    if($is_complete_fullmock_test){
                                        wp_send_json([
                                            "status"           => 1,
                                            "res"               => "Quiz completed successfully",
                                            "res_type"          => "success",
                                            "redirect"          => true,
                                            "result"            => 1,
                                            "url"               => st_proqyz_get_mock_test_url( $mock_test__course_id, $mock_test__lesson_id , "result"),
                                            "result_id"         => $session_id    
                                        ]);
                                    } else {
                                        wp_send_json([
                                            "status"           => 0,
                                            "res"               => "Cannot complete fullmock test",
                                            "res_type"          => "error",
                                            "redirect"          => true,
                                            "result"            => 1,
                                        ]);
                                    }
                                } else {
                                    # update - slug
                                    wp_send_json([
                                        "status"           => 0,
                                        "res"               => "Cannot submit mock test report, contact to site support team",
                                        "res_type"          => "error",
                                        "redirect"          => true,
                                        "result"            => 1,
                                        "url"               => st_proqyz_get_mock_test_url( $mock_test__course_id, $mock_test__lesson_id , "result"),
                                        "result_id"         => $session_id    
                                    ]);
                                }

                            }

                            // if not fullmock test then send success 
                            wp_send_json([
                                "status"    => 1,
                                "res_type"  => "success",
                                "res"       => "quiz completed successfully",
                                "result"    => 1,
                                "redirect"          => ($quiz_slug == null)? false : true,
                                "url"               => $pre_post_result_url
                            ]);


                        }

                        wp_send_json([
                            "status"    => 1,
                            "res_type"  => "success",
                            "res"       => "Next section"
                        ]);

                    } else {
                        wp_send_json([
                            "status"    => 0,
                            "res_type"  => "danger",
                            "res"       => "Failed to add speaking section",
                            "error"     => "why"
                        ]);
                    }
                
                } else {
                    // if storage response is not successful then send error
                    if(defined('IELTS_STORAGE')) {
                        $storage_unit = IELTS_STORAGE;
                    } else {
                        $storage_unit = 'cpanel';
                    }


                    $storage_response = (object) [
                        "status"    => 0,
                        "res_typr"  => "warning",
                        "res"       => "no storage unit set",
                        "category"  => "media",
                        "unit"      => $storage_unit     
                    ];
                    wp_send_json($storage_response);
                }
                                                
            } else {
                wp_send_json([
                    "status"    => 0,
                    "res_type"  => "danger",
                    "res"       => "Failed to add speaking section"
                ]);
            }

        } else {
            wp_send_json([
                "status"    => 0,
                "res_type"  => "danger",
                "res"       => "Could not start session, session not found",
                "category"  => "503",
                "error"     => "not found"    
            ]);
        }

    } else {
        wp_send_json([
            "success" => false,
            "res"       => "could not save the session report due to some reasons",
            "report"    => $session_report
        ]);
    }
                
            
}

function Ielts_store_speaking_media_in_cpanel($parms = []) {
    $files              = (array) $parms->files;
    $session_type       = $parms->session_type;
    $session_category   = $parms->session_category;
    $student_id         = $parms->student_id;
    $session_key        = $parms->session_key;
    $section_id         = $parms->section_id;

    if (count($files) === 1) {
        $file = $files["file2upload"]['tmp_name'];
        # Check and create directory
        $upload_dir = Ielts_speaking_dir_check($student_id);
        
        if ($upload_dir) {
            $rename_file = "speaking_" . date("Y") ."-".date("m")."-".date("d")."-".date("U") . "_" . $session_category . "_" . $session_type . "_part_" . $section_id . ".wav";
            $upload_file = $upload_dir . "/" . $rename_file;

            if (move_uploaded_file($file, $upload_file)) {
                return (object) [
                    "status"        => 1,
                    "storage_type"  => "cpanel",
                    "res_type"      => "success",
                    "category"      => "media",
                    "res"           => "Media uploaded successfully",
                    "dir"           => $upload_dir,
                    "filename"      => $rename_file,
                    "json"          => (object) [
                        "type"      => "cpanel",
                        "location"      => "wp-content/uploads/proqyz/ielts/results/speaking/" .date("Y")."-".date("m"). "/" . $student_id,
                        "filename"      => $rename_file,
                        "year"          => date("Y"),
                        "month"         => date("m"),
                        "student_id"    => $student_id
                    ]
                ];
            } else {
                return (object) [
                    "status"    => 0,
                    "res_type"  => "error",
                    "category"  => "media",
                    "res"       => "Failed to upload media"
                ];
            }
        } else {
            return (object) [
                "status"    => 0,
                "res_type"  => "error",
                "category"  => "media",
                "res"       => "Failed to create directory"
            ];
        }
    } else {
        return (object) [
            "status"    => 0,
            "res_type"  => "danger",
            "category"  => "media",
            "res"       => "No media found OR more than 1 media found",
            "files"     => $parms
        ];
    }
}


function Ielts_speaking_dir_check($student_id) {
    $upload_dir = wp_upload_dir();

    // Get the path to the uploads directory
    $uploads_path = $upload_dir['basedir'];

    // Define the directory path
    $speaking_dir = $uploads_path . "/proqyz/ielts/results/speaking";

    // Create the directory if it doesn't exist
    if (!is_dir($speaking_dir)) {
        mkdir($speaking_dir, 0755, true); // Recursive directory creation
    }

    // Append student-specific directory
    $student_dir = $speaking_dir . "/" . date("Y") . "-" . date("m") . "/" . $student_id;

    // Create the student-specific directory if it doesn't exist
    if (!is_dir($student_dir)) {
        mkdir($student_dir, 0755, true); // Recursive directory creation
    }

    // Return the directory path
    return $student_dir;
}

/**
 * Delete audio file from storage based on storage type
 * 
 * @param object|array $json_data The JSON data containing storage information
 * @return array Returns ['success' => bool, 'error' => string|null]
 */
function proqyz_delete_audio_file($json_data) {
    // Convert to object if array
    if (is_array($json_data)) {
        $json_data = (object) $json_data;
    }
    
    // Check if json_data is valid
    if (!is_object($json_data) || !isset($json_data->type)) {
        return [
            'success' => false,
            'error' => 'Invalid JSON data structure'
        ];
    }
    
    $storage_type = $json_data->type;
    
    // Handle cpanel storage
    if ($storage_type === 'cpanel') {
        if (!isset($json_data->location) || !isset($json_data->filename)) {
            return [
                'success' => false,
                'error' => 'Missing location or filename in JSON data'
            ];
        }
        
        $file_path = ABSPATH . ltrim($json_data->location, '/') . '/' . $json_data->filename;
        
        if (file_exists($file_path)) {
            if (@unlink($file_path)) {
                return ['success' => true, 'error' => null];
            } else {
                return [
                    'success' => false,
                    'error' => 'Failed to delete file from cpanel storage'
                ];
            }
        } else {
            // File doesn't exist, consider it already deleted
            return ['success' => true, 'error' => null];
        }
    }
    
    // Handle AWS S3 storage
    if ($storage_type === 'aws-s3') {
        if (!isset($json_data->bucket) || !isset($json_data->url)) {
            return [
                'success' => false,
                'error' => 'Missing bucket or url in JSON data'
            ];
        }
        
        // Extract key from URL
        // URL formats from getObjectUrl():
        // - https://s3.ap-south-1.amazonaws.com/{bucket}/{keyName}
        // - https://{bucket}.s3.ap-south-1.amazonaws.com/{keyName}
        $url = $json_data->url;
        $bucket = $json_data->bucket;
        
        // Try to extract key from URL by removing the base URL patterns
        $keyName = null;
        $base_url_patterns = [
            'https://s3.ap-south-1.amazonaws.com/' . $bucket . '/',
            'https://' . $bucket . '.s3.ap-south-1.amazonaws.com/',
            'http://s3.ap-south-1.amazonaws.com/' . $bucket . '/',
            'http://' . $bucket . '.s3.ap-south-1.amazonaws.com/',
        ];
        
        foreach ($base_url_patterns as $pattern) {
            if (strpos($url, $pattern) !== false) {
                $keyName = substr($url, strpos($url, $pattern) + strlen($pattern));
                // Remove any query parameters or fragments
                $keyName = strtok($keyName, '?#');
                break;
            }
        }
        
        // Fallback: try parsing URL path
        if (empty($keyName)) {
            $url_parts = parse_url($url);
            if (isset($url_parts['path'])) {
                $path = ltrim($url_parts['path'], '/');
                // Check if bucket is in hostname (format: bucket.s3.region.amazonaws.com)
                $host_has_bucket = isset($url_parts['host']) && strpos($url_parts['host'], $bucket . '.s3.') === 0;
                
                if ($host_has_bucket) {
                    // Bucket is in hostname, so path is the key
                    $keyName = $path;
                } else if (strpos($path, $bucket . '/') === 0) {
                    // Bucket is in path (format: /bucket/key)
                    $keyName = substr($path, strlen($bucket) + 1);
                } else {
                    // Path might be the key
                    $keyName = $path;
                }
            }
        }
        
        if (empty($keyName)) {
            return [
                'success' => false,
                'error' => 'Cannot determine S3 key from JSON data. URL: ' . $url
            ];
        }
        
        // AWS Info
        if (!defined('AWS_S3_BUCKET') || !defined('AWS_IAM_KEY') || !defined('AWS_IAM_SECRET')) {
            return [
                'success' => false,
                'error' => 'AWS S3 credentials not configured'
            ];
        }
        
        $IAM_KEY = AWS_IAM_KEY;
        $IAM_SECRET = AWS_IAM_SECRET;
        
        try {
            $s3 = S3Client::factory(
                array(
                    'credentials' => array(
                        'key'       => $IAM_KEY,
                        'secret'    => $IAM_SECRET
                    ),
                    'version' => 'latest',
                    'region'  => 'ap-south-1'
                )
            );
            
            // Delete object from S3
            $result = $s3->deleteObject([
                'Bucket' => $bucket,
                'Key'    => $keyName
            ]);
            
            return ['success' => true, 'error' => null];
            
        } catch (S3Exception $e) {
            return [
                'success' => false,
                'error' => 'AWS S3 deletion error: ' . $e->getMessage()
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'AWS S3 connection error: ' . $e->getMessage()
            ];
        }
    }
    
    // Unknown storage type
    return [
        'success' => false,
        'error' => 'Unknown storage type: ' . $storage_type
    ];
}

function AWS_s3_upload_object($parms = []){
    $files              = (array) $parms->files;
    $session_type       = $parms->session_type;
    $session_category   = $parms->session_category;
    $student_id         = $parms->student_id;
    $session_key        = $parms->session_key;
    $section_id         = $parms->section_id;

    if(count($files) === 1) {
        $file = $files["file2upload"]['tmp_name'];
        $upload_file = $file;
        $rename_file = "speaking_" . date("Y") ."-".date("m")."-".date("d")."-".date("U") . "_" . $session_category . "_" . $session_type . "_part_" . $section_id . ".wav";
            
        
        // AWS Info
        $bucketName = AWS_S3_BUCKET;
        $IAM_KEY = AWS_IAM_KEY;
        $IAM_SECRET = AWS_IAM_SECRET;
        
        # Connect to AWS
        try {
            // You may need to change the region. It will say in the URL when the bucket is open
            // and on creation.
            $s3 = S3Client::factory(
                array(
                    'credentials' => array(
                        'key'       => $IAM_KEY,
                        'secret'    => $IAM_SECRET
                    ),
                    'version' => 'latest',
                    'region'  => 'ap-south-1'
                )
            );
        } catch (Exception $e) {
            // We use a die, so if this fails. It stops here. Typically this is a REST call so this would
            // return a json object.
            wp_send_json([
                "status"    => 0,
                "res_type"  => "danger",
                "res"       => "AWS S3 ERROR",
                "error"     => $e->getMessage()    
            ]);
        }

        // For this, I would generate a unqiue random string for the key name. But you can do whatever.
        $keyName = parse_url( get_site_url(), PHP_URL_HOST ).'/proqyz/ielts/results/speakings/'.date("Y") . "-" .date("m"). "/" . $student_id. "/" . $rename_file;
        $pathInS3 = 'https://s3.ap-south-1.amazonaws.com/' . $bucketName . '/' . $keyName;

        // Add it to S3
        try {
            // Uploaded:
            
            $uploaded = $s3->putObject(
                array(
                    'Bucket'        =>  $bucketName,
                    'Key'           =>  $keyName,
                    'SourceFile'    =>  $file,
                    'StorageClass'  => 'REDUCED_REDUNDANCY'
                )
            );

            if($uploaded) {
                $audio_url = $s3->getObjectUrl($bucketName, $keyName);
                return (object) [
                    "status"        => 1,
                    "storage_type"  => "aws-s3",
                    "res_type"      => "success",
                    "category"      => "media",
                    "res"           => "Media uploaded successfully",
                    "filename"      => $audio_url,
                    "json"          => (object) [
                        "type"              => "aws-s3",
                        "bucket"            => $bucketName,
                        "filename"          => $rename_file,
                        "url"               => $audio_url
                    ]
                ];
            } else {
                wp_send_json([
                    "status"    => 0,
                    "res_type"  => "warning",
                    "res"       => "failed to upload file",
                    "error"     => "AWS s3 object upload filed"   
                ]);
            }

        } catch (S3Exception $e) {
            wp_send_json([
                "status"    => 0,
                "res_type"  => "danger",
                "res"       => "AWS S3 Upload ERROR",
                "error"     => $e->getMessage()    
            ]);
        }

    } else {
        return (object) [
            "status"    => 0,
            "res_type"  => "danger",
            "category"  => "media",
            "res"       => "No media found OR more then 1 media found",
            "files"     => $parms
        ];
    }
    

}


add_action('wp_ajax_proqyz-save-speaking-progress', 'proqyz_speaking_quiz_submit');
add_action('wp_ajax_nopriv_proqyz-save-speaking-progress', 'proqyz_ajax_save_quiz_progress_unauthorize');


add_action('wp_ajax_proqyz-save-question-report', 'proqyz_save_question_report_callback');
function proqyz_save_question_report_callback() {
    include_once ST_PROQYZ_LIBS_DIR . '/class-st-proqyz-oauth.php'; 
    if(!class_exists('ST_ProQyz_Oauth')) {
        wp_send_json([
            'error' => (object) [
                'message' => 'No image data received.'
            ]
        ]);
        return;
    }
    
    /*
    // Get the image data
    $image_data = $_POST['image'];

    if (empty($image_data)) {
        wp_send_json([
            'error' => (object) [
                'message' => 'No image data received.'
            ]
        ]);
        return;
    }

    // Decode the Base64 image
    $image_data = explode(',', $image_data)[1]; // Strip metadata
    $decoded_image = base64_decode($image_data);

    if (!$decoded_image) {
        wp_send_json([
            'error' => (object) [
                'message' => 'Invalid Image data.'
            ]
        ]);
        return;
    }

    // Prepare file name and path
    $upload_dir = wp_upload_dir();
    $category_dir = $upload_dir['basedir'] . '/question-reports';
    if (!file_exists($category_dir)) {
        wp_mkdir_p($category_dir);
    }

    $filename = 'report-' . time() . '.png';
    $file_path = $category_dir . '/' . $filename;

    // Save the file
    if (file_put_contents($file_path, $decoded_image) === false) {
        wp_send_json([
            'error' => (object) [
                'message' => 'Failed to save screenshot.'
            ]
        ]);
        return;
    }

    // Get the public URL of the image
    $file_url           = $upload_dir['baseurl'] . '/question-reports/' . $filename;
    
    */
    
    $file_url           = '';
    $question_id        = $_POST['question_id'];
    $post_id            = $_POST['post_id'];
    //$result_url         = $_POST['result_url'];
    //$result_id          = $_POST['result_id'];
    $quiz_id            = $_POST['quiz_id'];
    $quiz_category      = $_POST['category'];
    $question_number    = $_POST['question_number'];
    $message            = $_POST['message'];

    // current user id 
    $user_id            = get_current_user_id();
    // current user email
    $user_data          = get_userdata($user_id);
    $user_email = $user_data->user_email; // User email
    $display_name = $user_data->display_name; // Display name
    $username = $user_data->user_login; // User name


    $response = (object) ST_ProQyz_Oauth::rest_post_request("/report/quiz/".$quiz_id, (object) [
        'report' => (object) [
            // '_wp_resultId'      => $result_id,
            // '_wp_resultUrl'     => $result_url,
            '_questionNumber'   => $question_number,
            'screenshotUrl'     => $file_url,
            'message'           => $message
        ],
        'wp_user' => (object) [
            'user_id'       => $user_id,
            'user_email'    => $user_email,
            'avatar_url'       => get_avatar_url($user_id),
            'username'          => $username,
            'display_name'      => $display_name
        ],
        'filters' => (object) [
            '_category' => $quiz_category,
            '_quizId'           => $quiz_id,
            '_postId'           => $post_id,
            '_questionId'       => $question_id,
        ]
    ]);
    if (!isset($response->error)) {
        if(isset($response->success)) {
            $success = (object) $response->success;
            wp_send_json([
                "success" => (object) [
                    "message" => $success->message?  $success->message : "Thank you for your feedback, we will investigate and resolve the issue",
                ]
            ]);
        } else {
            wp_send_json([
                "success" => (object) [
                    "message" => "Thank you for your feedback, we will investigate and resolve the issue",
                ]
            ]);
        }
    } else {
        $error = (object) $response->error;
        if(isset($error->message)){ 
            $proqyz_response = $error->message;
        } else {
            $proqyz_response = "Unknown Error";
        }

        wp_send_json([
            "error" => (object) [
                "message" => $proqyz_response
            ]
        ]);
    }
    // Send response
    
}


/**
 * proqyz_basic-check-auth
 */
add_action('wp_ajax_nopriv_proqyz_basic-check-auth', 'proqyz_basic_check_auth_callback');
add_action('wp_ajax_proqyz_basic-check-auth', 'proqyz_basic_check_auth_callback');
function proqyz_basic_check_auth_callback(){
    if(is_user_logged_in()){
        wp_send_json([
            "success" => true
        ]);
    } else {
        wp_send_json([
            "error" => true
        ]);
    }
}


/**
 * complete fullmock test handler
 */
function complete_fullmock_test_handler($course_id, $lesson_id, $student_id){
    global $wpdb, $table_proqyz_fullmock_tests_progress, $table_proqyz_v3_progress_submissions;
    // fetch all the fullmock test submissions using course_id, lesson_id, student_id and session_category = 'fullmock-test'
    $get_submissions = $wpdb->get_results($wpdb->prepare("
        SELECT * FROM {$table_proqyz_v3_progress_submissions}
        WHERE course_category = 'proqyz-course' AND course_id = %s AND lesson_id = %s AND user_id = %s AND session_category = 'fullmock-test' AND session_status = 3 AND status = 1
    ", $course_id, $lesson_id, $student_id));
    # update all submission session_status to 1 
    $ok = true;
    if(count($get_submissions) > 0){
        foreach($get_submissions as $submission){
            $is_updated = $wpdb->update($table_proqyz_v3_progress_submissions, [
                "session_status" => 1
            ], [
                "ID" => $submission->ID
            ]);
            if(!$is_updated){
                $ok = false;
            }
        }
    } else {
        $ok = false;
    }
    if($ok){
        return true;
    } else {
        return false;
    }
}