<?php
/**
 * Core Quiz Handler
 * Handles:
 *   - Shortcode rendering
 *   - AJAX endpoints for fetching questions and processing stages
 *   - Adaptive level logic (dropping-down/up based on correct answers)
 *   - Final summary generation
 *   - Email report sending
 */
class SEA_Quiz_Handler {

    /** @var self */
    private static $instance = null;

    public static function instance() {
        if ( ! isset( self::$instance ) ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        // AJAX endpoints
        add_action( 'wp_ajax_sea_fetch_questions',      [ $this, 'ajax_fetch_questions' ] );
        add_action( 'wp_ajax_nopriv_sea_fetch_questions',[ $this, 'ajax_fetch_questions' ] );
        add_action( 'wp_ajax_sea_process_stage',      [ $this, 'ajax_process_stage' ] );
        add_action( 'wp_ajax_nopriv_sea_process_stage',[ $this, 'ajax_process_stage' ] );

        // Session handling for multi-stage flow
        add_action( 'init', [ $this, 'init_session_handling' ] );
    }

    /**
     * Set up session-based storage for quiz progress.
     */
    private function init_session_handling() {
        // Start session for storing state between requests
        if ( ! session_id() ) {
            session_start();
        }
    }

    /**
     * Render the main shortcode output.
     *
     * @param array $atts Shortcode attributes.
     * @return string HTML output.
     */
    public function render_shortcode( $atts ) {
        // Buffer output
        ob_start();
        // Include the template file for the assessment UI
        include SEA_PLUGIN_DIR . 'templates/shortcode-assessment.php';
        // Return the captured output
        return ob_get_clean();
    }

    /**
     * Enqueue CSS and JS assets for the front-end assessment.
     */
    public function enqueue_assets() {
        // Enqueue stylesheet
        wp_enqueue_style(
            'sea-assessment-css',
            SEA_PLUGIN_URL . 'assets/css/assess.css',
            [],
            SEA_VERSION
        );

        // Enqueue JavaScript
        wp_enqueue_script(
            'sea-assess-js',
            SEA_PLUGIN_URL . 'assets/js/assess.js',
            [ 'jquery' ],
            SEA_VERSION,
            true
        );

        // Pass AJAX URL and nonce to JS
        wp_localize_script(
            'sea-assess-js',
            'SEA_Ajax',
            [
                'ajax_url' => admin_url( 'admin-ajax.php' ),
                'nonce'    => wp_create_nonce( 'sea_ajax_nonce' ),
            ]
        );
    }

    /**
     * AJAX: Fetch the first set of 5 questions based on age.
     */
    public function ajax_fetch_questions() {
        check_ajax_referer( 'sea_ajax_nonce', 'nonce' );

        // Sanitize input.
        $age  = intval( $_POST['age'] ?? 0 );
        $country = sanitize_text_field( $_POST['country'] ?? '' );
        $city  = sanitize_text_field( $_POST['city'] ?? '' );

        // Validate age.
        if ( $age < 4 || $age > 90 ) {
            wp_send_json_error( [
                'message' => __( 'Please enter a valid age between 4 and 90.', 'simply-english-assessment' ),
            ] );
            wp_die();
        }

        // Determine starting CEFR level based on age.
        $base_cefr = $this->determine_starting_cefr( $age );

        // Store session data in a temporary variable.
        $token = wp_generate_uuid4(); // Random token for session tracking.
        $session_data = [
            'age'                => $age,
            'country'            => $country,
            'city'               => $city,
            'current_cefr'       => $base_cefr,
            'stages_done'        => [],
            'answers'            => [],
        ];
        // Store session for later retrieval.
        set_transient( 'sea_session_' . $token, $session_data, 30 * MINUTE_IN_SECONDS );

        // Retrieve questions based on current CEFR and age-tag.
        $questions = $this->get_questions( $base_cefr, $age, 5 );

        // Return JSON response containing questions.
        wp_send_json_success( [
            'token'      => $token,
            'questions'  => $questions,
            'time_limit' => 15 * 60, // 15 minutes in seconds.
        ] );
    }

    /**
     * AJAX: Process a completed stage of 5 questions.
     *
     * Returns next stage or final report.
     */
    public function ajax_process_stage() {
        check_ajax_referer( 'sea_ajax_nonce', 'nonce' );

        // Sanitize inputs.
        $token     = sanitize_text_field( $_POST['token'] ?? '' );
        $answers   = sanitize_textarea_field( $_POST['answers'] ?? '' );
        $answers   = json_decode( stripslashes( $answers ), true );
        $stage_num = intval( $_POST['stage'] ?? 1 );
        $email     = sanitize_email( $_POST['email'] ?? '' );

        // Retrieve session data using the token.
        $session_data = get_transient( 'sea_session_' . $token );

        if ( ! $session_data ) {
            wp_send_json_error( [
                'message' => __( 'Session expired. Please restart the assessment.', 'simply-english-assessment' ),
            ] );
            wp_die();
        }

        // Store answers for the current stage.
        $session_data['answers'][ $stage_num ] = $answers;

        // Score the stage.
        $score = $this->score_stage( $answers );

        // Determine next CEFR level.
        $next_cefr = $this->next_cefr_level( $session_data['current_cefr'], $score, $stage_num );
        $session_data['current_cefr'] = $next_cefr;

        // Mark stage as completed.
        $session_data['stages_done'][] = $stage_num;

        // If we have reached the maximum number of stages (e.g., 5), finish.
        $max_stages = 5; // Adjust if you want more stages.
        $cron_limit = 5;

        if ( $stage_num >= $max_stages ) {
            // Build final summary and send email if provided.
            $summary = $this->build_summary( $session_data );

            // If the user provided an email address, send a detailed PDF report.
            if ( $email ) {
                $this->email_report( $email, $summary );
            }

            // Delete session transient.
            delete_transient( 'sea_session_' . $token );

            // Return JSON indicating assessment completion.
            wp_send_json_success( [
                'finished'  => true,
                'summary'   => $summary,
            ] );
        } else {
            // Store updated session data.
            set_transient( 'sea_session_' . $token, $session_data, 30 * MINUTE_IN_SECONDS );

            // Retrieve next set of questions.
            $next_questions = $this->get_questions( $next_cefr, $session_data['age'], 5 );

            // Return JSON to continue to the next stage.
            wp_send_json_success( [
                'finished'    => false,
                'next_stage'  => $stage_num + 1,
                'questions'   => $next_questions,
                'next_cefr'   => $next_cefr,
            ] );
        }
    }

    /**
     * Determine starting CEFR level from age (simple mapping).
     *
     * @param int $age Age of the user.
     * @return string CEFR level.
     */
    private function determine_starting_cefr( $age ) {
        if ( $age <= 6 ) {
            return 'A1';
        } elseif ( $age <= 10 ) {
            return 'A2';
        } elseif ( $age <= 13 ) {
            return 'B1';
        } elseif ( $age <= 16 ) {
            return 'B2';
        } else {
            return 'C1';
        }
    }

    /**
     * Retrieve a set of questions from the question repository.
     *
     * @param string $cefr      CEFR level.
     * @param int    $age       User's age.
     * @param int    $limit     Number of questions to fetch.
     * @return array|null Array of questions or null on failure.
     */
    private function get_questions( $cefr, $age, $limit = 5 ) {
        // Determine the age tag based on age.
        $age_tag = $this->age_tag_from_age( $age );

        // Query the database for questions matching this CEFR and age tag.
        $args = [
            'post_type'      => 'assessment_question',
            'posts_per_page' => $limit,
            'meta_query'     => [
                [
                    'key'     => '_sea_cefr',
                    'value'   => $cefr,
                    'compare' => '=',
                ],
                [
                    'key'     => '_sea_age_tag',
                    'value'   => $age_tag,
                    'compare' => '=',
                ],
            ],
            'orderby' => 'rand',
        ];

        $posts = get_posts( $args );

        if ( ! $posts ) {
            return null;
        }

        $questions = [];
        foreach ( $posts as $p ) {
            $options      = json_decode( get_post_meta( $p->ID, '_sea_options', true ), true );
            $options_json = json_encode( $options );
            $questions[] = [
                'id'      => $p->ID,
                'question'=> apply_filters( 'the_content', $p->post_content ),
                'options' => $options,
                'option_strings' => $options,
            ];
        }

        return $questions;
    }

    /**
     * Map age to the age-tag used for question filtering.
     *
     * @param int $age Age of the user.
     * @return string Age tag.
     */
    private function age_tag_from_age( $age ) {
        if ( $age <= 8 ) {
            return 'P1';
        } elseif ( $age <= 11 ) {
            return 'P2';
        } elseif ( $age <= 14 ) {
            return 'P3';
        } elseif ( $age <= 16 ) {
            return 'P4';
        } elseif ( $age <= 18 ) {
            return 'UL1';
        } elseif ( $age <= 20 ) {
            return 'UL2';
        } else {
            return 'DSE';
        }
    }

    /**
     * Score a stage (set of 5 questions) based on selected answers.
     *
     * @param array $answers Array of selected answers.
     * @return int Number of correct answers.
     */
    private function score_stage( $answers ) {
        $correct_count = 0;

        foreach ( $answers as $answer ) {
            // Extract question ID and selected option.
            $question_id  = intval( $answer['qid'] );
            $user_selection = sanitize_text_field( $answer['selected'] );

            // Get the correct answers.
            $correct = sanitize_text_field( get_post_meta( $question_id, '_sea_correct', true ) );

            // Normalize and compare.
            $correct_arr = preg_split( '/,/', $correct );
            $selected_arr = preg_split( '/,/', $user_selection );

            // Trim whitespace and sort.
            $trim_and_sort = function ( $arr ) {
                $trimmed = array_map( 'trim', $arr );
                sort( $trimmed );
                return $trimmed;
            };

            $correct_sorted = trim_and_sort( $correct_arr );
            $selected_sorted = trim_and_sort( $selected_arr );

            // If arrays are identical, increment correct count.
            if ( $correct_sorted === $selected_sorted ) {
                $correct_count++;
            }
        }

        return $correct_count;
    }

    /**
     * Determine the next CEFR level based on score and stage number.
     *
     * Stage 2 logic: if all 5 questions are correct, move up a level.
     *
     * @param string $current_level Current CEFR level.
     * @param int    $score       Number of correct answers (0‑5).
     * @param int    $stage_num   Stage number (1‑based).
     * @return string Next CEFR level.
     */
    private function next_cefr_level( $current_level, $score, $stage_num ) {
        $levels = [ 'A1', 'A2', 'B1', 'B2', 'C1', 'C2' ];
        $idx    = array_search( $current_level, $levels, true );

        if ( false === $idx ) {
            return 'C1';
        }

        // Drop logic
        if ( $score === 0 ) {
            $idx = max( 0, $idx - 2 );
        } elseif ( $score >= 1 && $score <= 3 ) {
            $idx = max( 0, $idx - 1 );
        } elseif ( $score >= 4 ) {
            // Stage‑2 upward move allowed
            $can_move_up = ( $stage_num === 2 && $score === 5 );
            if ( $can_move_up ) {
                $idx = min( count( $levels ) - 1, $idx + 1 );
            }
        }

        return $levels[ $idx ];
    }

    /**
     * Create a final summary of the completed assessment.
     *
     * @param array $session Assessed user data.
     * @return array HTML summary, plain‑text feedback, and final CEFR level.
     */
    public function build_summary( $session ) {
        $total_correct   = 0;
        $total_questions = 0;

        foreach ( $session['answers'] as $stage => $answers ) {
            $total_correct   += $this->score_stage( $answers );
            $total_questions += count( $answers );
        }

        $percentage = $total_questions ? round( ( $total_correct / $total_questions ) * 100 ) : 0;

        // Simple bucket threshold mapping
        if ( $percentage < 20 ) {
            $final_cefr = 'A1';
        } elseif ( $percentage < 40 ) {
            $final_cefr = 'A2';
        } elseif ( $percentage < 60 ) {
            $final_cefr = 'B1';
        } elseif ( $percentage < 80 ) {
            $final_cefr = 'B2';
        } elseif ( $percentage < 95 ) {
            $final_cefr = 'C1';
        } else {
            $final_cefr = 'C2';
        }

        // Map CEFR to a recommended course.
        $recommendation   = $this->recommend_course( $final_cefr, $session['age'] );
        $location_details = $session['location'] ?? [];
        $location_text    = isset( $location_details['city'] ) && isset( $location_details['country_name'] )
            ? sprintf( '%s, %s', $location_details['city'], $location_details['country_name'] )
            : 'Unknown location';

        // Build HTML summary.
        $html = '<h2>' . esc_html__( 'Assessment Summary', 'simply-english-assessment' ) . '</h2>';
        $html .= '<p><strong>' . esc_html__( 'Age', 'simply-english-assessment' ) . ':</strong> ' . esc_html( $session['age'] ) . '</p>';
        $html .= '<p><strong>' . esc_html__( 'Location', 'simply-english-assessment' ) . ':</strong> ' . esc_html( $location_text ) . '</p>';
        $html .= '<p><strong>' . esc_html__( 'Score', 'simply-english-assessment' ) . ':</strong> ' . $total_correct . ' / ' . $total_questions . ' (' . $percentage . '%)</p>';
        $html .= '<p><strong>' . esc_html__( 'Estimated CEFR Level', 'simply-english-assessment' ) . ':</strong> ' . $final_cefr . '</p>';
        $html .= '<p><strong>' . esc_html__( 'Recommended Course', 'simply-english-assessment' ) . ':</strong> ' . esc_html( $recommendation ) . '</p>';

        // Plain‑text version for email fallback.
        $text = sprintf( __( 'Assessment Summary', 'simply-english-assessment' ) );
        $text .= "\n\n" . sprintf( __( 'Age: %d', 'simply-english-assessment' ), $session['age'] );
        $text .= "\n" . sprintf( __( 'Location: %s', 'simply-english-assessment' ), $text  );
        $text .= "\n" . sprintf( __( 'Score: %d / %d (%d%%)', 'simply-english-assessment' ), $total_correct, $total_questions, $percentage );
        $text .= "\n" . sprintf( __( 'CEFR: %s', 'simply-english-assessment' ), $final_cefr );
        $text .= "\n" . sprintf( __( 'Recommended Course: %s', 'simply-english-assessment' ), $recommendation );

        return [
            'html'   => $html,
            'text'   => $text,
            'cefr'   => $final_cefr,
        ];
    }

    /**
     * Recommend a course based on CEFR level and age.
     *
     * @param string $cefr CEFR level.
     * @param int    $age   User's age.
     * @return string Recommended course name.
     */
    private function recommend_course( $cefr, $age ) {
        $course_map = [
            // Primary levels
            'A1' => 'Phonics Beg – Level 1',
            'A2' => 'Level 2',
            'B1' => 'Level 3',
            'B2' => 'Level 4',
            'C1' => 'Upper Level 1 (S1–S3)',
            'C2' => 'Upper Level 2 (S4–S6)',

            // Fallback
            'default' => 'Contact Admissions',
        };

        return $course_map[ $cefr ] ?? $course_map['default'];
    }

    /**
     * Send the detailed PDF report to the provided email address.
     *
     * @param string $email Recipient email address.
     * @param array  $summary Summary data generated by build_summary().
     */
    public function email_report( $email, $summary ) {
        // Build the HTML version of the summary.
        $html = '

        <h1>' . esc_html__( 'Your Simply English Assessment Report', 'simply-english-assessment' ) . '</h1>
        ' . $summary['html'] . '

        <hr>

        <p>' . esc_html__( 'Thank you for completing the assessment. If you have any questions, please contact us.', 'simply-english-assessment' ) . '</p>
        ';

        // Generate the PDF file from the HTML.
        $pdf_path = SEA_Email::instance()->generate_pdf( $html );

        // Prepare email details.
        $subject = __( 'Your Simply English Assessment Report', 'simply-english-assessment' );
        $message = $summary['text'];

        // Send the email with the PDF attached.
        SEA_Email::instance()->send_report( $email, $subject, $message, $html, $pdf_path );
    }
}