<?php
namespace QuizPress\Ajax;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use QuizPress\Classes\AbstractAjaxHandler;
use QuizPress\Classes\Sanitizer;
use QuizPress\API\Query\Attempts as Query;
use QuizPress\API\Query\Questions as Questions;
use QuizPress\API\Query\Answers as Answers;


class Frontend extends AbstractAjaxHandler {
	protected $namespace = 'quizpress/frontend';
	protected array $capability;
	public function __construct() {
		 $this->capability = \QuizPress\Helper::get_settings( 'is_enable_guest_user_attempt', false )
		? [ 'allow_visitor_action' => true ]
		: [ 'capability' => 'read' ];
		$this->actions = [
			'get_quiz_questions_for_attempt' => array_merge(
				[ 'callback' => array( $this, 'get_quiz_questions_for_attempt' ) ],
				$this->capability
			),
			'insert_quiz_answer' => array_merge(
				[ 'callback' => array( $this, 'insert_quiz_answer' ) ],
				$this->capability
			),
			'get_user_attempt_answer_details' => array_merge(
				[ 'callback' => array( $this, 'get_user_attempt_answer_details' ) ],
				$this->capability
			),
			'get_user_attempt_by_quiz' => array_merge(
				[ 'callback' => array( $this, 'get_user_attempt_by_quiz' ) ],
				$this->capability
			),
			'get_user_attempt_feedback' => array_merge(
				[ 'callback' => array( $this, 'get_user_attempt_feedback' ) ],
				$this->capability
			),
		];
	}

	public function get_quiz_questions_for_attempt( $payload_data ) {
		$payload = Sanitizer::sanitize_payload([
			'quiz_id' => 'integer',
		], $payload_data);

		$quiz_id = $payload['quiz_id'] ?? 0;
		$questions = get_post_meta( $quiz_id, 'quizpress_quiz_questions', true );
		$question_limit = (int) get_post_meta( $quiz_id, 'quizpress_quiz_max_questions_for_answer', true );
		$question_ids = array_column( (array) $questions, 'id' );

		if ( ! empty( $question_ids ) ) {
			// If limit is 0 or unset, randomize the full question set
			if ( empty( $question_limit ) || $question_limit === 0 ) {
				$question_limit = count( $question_ids );
			}
			shuffle( $question_ids );
			// Limit questions to the specified number
			$limit = min( $question_limit, count( $question_ids ) );
			$random_keys = (array) array_rand( $question_ids, $limit );
			$question_ids = array_intersect_key( $question_ids, array_flip( $random_keys ) );
		}

		// Get questions data in a single query
		$questions_data = Questions::get_questions_by_ids( $question_ids, true );
		if ( $questions_data ) {
			foreach ( $questions_data as &$question_data ) {
				$question_data->question_settings = json_decode( $question_data->question_settings, true );
				$question_data->answers = Answers::get_question_answers_by_question_id( $question_data->question_id );
				if ( $question_data->question_settings['random_answer'] ) {
					shuffle( $question_data->answers );
				}

				foreach ( $question_data->answers as &$answer ) {
					$answer = \QuizPress\API\Controller\Answers::prepare_answer_for_response( $answer );
				}
			}
			unset( $question_data ); // break reference
		}

		wp_send_json_success([
			'render_question_ids' => $question_ids,
			'questions' => $questions_data,
		]);
	}


	public function insert_quiz_answer( $payload_data ) {
		$payload = Sanitizer::sanitize_payload([
			'quiz_id'       => 'integer',
			'question_id'   => 'integer',
			'attempt_id'    => 'integer',
			'given_answers' => 'json',
		], $payload_data );

		$quiz_id       = (int) $payload['quiz_id'];
		$attempt_id    = (int) $payload['attempt_id'];
		$question_id   = (int) $payload['question_id'];
		$given_answers = $payload['given_answers'];
		$user_id       = (int) get_current_user_id();

		if ( empty( $given_answers ) || ! is_array( $given_answers ) ) {
			wp_send_json_error( esc_html__( 'Sorry, something went wrong', 'quizpress' ) );
		}

		$question = Questions::get_question_details_by_question_id( $question_id );

		// Cache values (avoid recalculating inside loop)
		$question_score = (float) $question->question_score;
		$question_type  = (string) $question->question_type;
		$negative_mark  = (float) $question->question_negative_score;

		// Extract IDs once
		$answer_ids = wp_list_pluck( $given_answers, 'answer_id' );

		// Determine correctness once where possible
		$correct_answer = 0;

		switch ( $question_type ) {

			case 'single_choice_horizontal':
			case 'single_choice':
			case 'true_false':
				$correct_answer = (int) Questions::is_quiz_correct_answer( $answer_ids, $question_id );
				break;

			case 'multiple_choice_horizontal':
			case 'multiple_choice':
				$total_correct = Answers::get_quiz_total_correct_answer_by_question_id( $question_id );
				$question_score = ( $question_score > 0 && $total_correct > 0 )
					? $question_score / $total_correct
					: 0;

				$correct_answer = (int) Questions::is_quiz_correct_answer( $answer_ids, $question_id );
				break;

			case 'short_answer':
			case 'paragraph':
			case 'number':
			case 'date':
				$correct_answer = 0;
				break;

			case 'drop_down':
				$correct_answer = apply_filters(
					'quizpress/get_drop_down_question_correct_answer',
					$given_answers,
					$question_id
				);
				break;

			case 'fill_in_the_blanks':
			case 'file_upload':
				// handled per answer below if needed
				break;

			default:
				$correct_answer = (int) Answers::is_quiz_correct_answer( $answer_ids, $question_id );
				break;
		}

		$results = [];

		foreach ( $given_answers as $item ) {

			$answer_id   = $item['answer_id'] ?? '';
			$answer_text = $item['answer'] ?? '';

			// Handle per-answer correctness for specific types
			$current_correct = $correct_answer;

			if ( in_array( $question_type, [ 'fill_in_the_blanks', 'file_upload' ], true ) ) {
				$current_correct = apply_filters(
					'quizpress/get_question_correct_answer',
					$answer_text,
					$question_type,
					$question_id
				);
			}

			// Negative marking (fixed bug: correct order)
			$negative_score = 0;
			if ( ! empty( $answer_text ) && $negative_mark > 0 && ! $current_correct ) {
				$negative_score = -$negative_mark;
			}

			$achieved_mark = $current_correct
				? $question_score
				: $negative_score;

			$results[] = Query::quiz_attempt_answer_insert([
				'user_id'       => $user_id,
				'quiz_id'       => $quiz_id,
				'question_id'   => $question_id,
				'attempt_id'    => $attempt_id,
				'answer_id'     => $answer_id,
				'answer'        => $answer_text,
				'question_mark' => $question_score,
				'achieved_mark' => $achieved_mark,
				'minus_mark'    => '',
				'is_correct'    => $current_correct,
			]);
		}

		wp_send_json_success( $results );
	}

	public function get_user_attempt_answer_details( $payload_data ) {
		$payload = Sanitizer::sanitize_payload(
			[
				'user_id'    => 'integer',
				'attempt_id' => 'integer',
			],
			$payload_data
		);

		if ( ( ! $payload['user_id'] && ! \QuizPress\Helper::get_settings( 'is_enable_guest_user_attempt' ) ) || ! $payload['attempt_id'] ) {
			wp_send_json_error( __( 'Required payload missing.' ) );
		}

		$attempt_id = $payload['attempt_id'];
		$user_id = ( isset( $payload['user_id'] ) ? $payload['user_id'] : 0 );

		$attempt_cache_key = "quizpress_attempt_{$attempt_id}_{$user_id}";

		$attempt_details = wp_cache_get( $attempt_cache_key, 'quizpress' );

		if ( false === $attempt_details ) {
			$attempt_details = Query::get_quiz_attempt_details( $attempt_id, $user_id );
			wp_cache_set( $attempt_cache_key, $attempt_details, 'quizpress', 12 * HOUR_IN_SECONDS );
		}

		if ( empty( $attempt_details ) ) {
			wp_send_json_success( [] );
		}

		$quiz_id = (int) ( $attempt_details[0]->quiz_id ?? 0 );
		$type      = get_post_meta( $quiz_id, 'quizpress_quiz_type', true );
		$is_survey = in_array( $type, [ 'survey', 'poll' ], true );

		$survey_data  = [];
		$answers_map = [];

		if ( $is_survey ) {

			$survey_cache_key = "quizpress_survey_{$quiz_id}";

			$survey_data = wp_cache_get( $survey_cache_key, 'quizpress' );

			if ( false === $survey_data ) {
				$survey_data = \QuizPress\API\Query\Attempts::get_attempt_data_by_quiz_id( $quiz_id );
				wp_cache_set( $survey_cache_key, $survey_data, 'quizpress' );
			}

			$question_ids = wp_list_pluck( $attempt_details, 'question_id' );

			foreach ( array_unique( $question_ids ) as $question_id ) {

				$answers_cache_key = "quizpress_answers_{$question_id}";

				$answers = wp_cache_get( $answers_cache_key, 'quizpress' );

				if ( false === $answers ) {
					$answers = Answers::get_quiz_answers_by_question_id( $question_id );
					wp_cache_set( $answers_cache_key, $answers, 'quizpress' );
				}

				$answers_map[ $question_id ] = ! empty( $answers )
					? wp_list_pluck( $answers, 'answer_title' )
					: [];
			}
		}//end if

		$response = [];

		foreach ( $attempt_details as $attempt_item ) {

			$attempt_item->is_required_manual_review = (
				! $attempt_item->is_manually_reviewed &&
				in_array(
					$attempt_item->question_type,
					[ 'short_answer', 'paragraph', 'number', 'date', 'file_upload' ],
					true
				)
			);

			$given_answer = Answers::prepare_given_answer(
				$attempt_item->question_type,
				$attempt_item
			);

			$question = \QuizPress\API\Query\Questions::get_question_details_by_question_id( $attempt_item->question_id );

			$question_settings = [];
			if ( $question && ! empty( $question->question_settings ) ) {
				$decoded_question_settings = json_decode( $question->question_settings, true );
				if ( is_array( $decoded_question_settings ) ) {
					$question_settings = $decoded_question_settings;
				}
			}

			$attempt_item->is_math_enabled = false;
			if ( isset( $question_settings['enable_math_input'] ) ) {
				$attempt_item->is_math_enabled = filter_var(
					$question_settings['enable_math_input'],
					FILTER_VALIDATE_BOOLEAN
				);
			}

			if ( $question && in_array( $question->answer_type, [ 'image_and_text', 'image' ], true ) ) {
				foreach ( $given_answer as &$answer ) {
					$answer->image_url = wp_get_attachment_image_url( \QuizPress\API\Query\Answers::get_quiz_answer( $answer->answer_id )->image_id );
				}
				unset( $answer );
			}

			$attempt_item->given_answer = $given_answer;
			$attempt_item->correct_answer = Answers::prepare_correct_answer(
				$attempt_item->question_type,
				$attempt_item
			);

			$attempt_item->is_correct      = (int) $attempt_item->is_correct;
			$attempt_item->question_title  = html_entity_decode( $attempt_item->question_title );
			$attempt_item->question_explanation = html_entity_decode( (string) $attempt_item->question_explanation );

			if ( $is_survey ) {

				$question_id = $attempt_item->question_id;

				$all_answers = $answers_map[ $question_id ] ?? [];

				if ( empty( $all_answers ) && ! empty( $survey_data[ $question_id ] ) ) {
					$all_answers = wp_list_pluck(
						$survey_data[ $question_id ],
						'answer'
					);
				}

				$count_map = [];

				if ( ! empty( $survey_data[ $question_id ] ) ) {
					foreach ( $survey_data[ $question_id ] as $row ) {
						if ( isset( $row['answer'], $row['count'] ) ) {
							$count_map[ $row['answer'] ] = (int) $row['count'];
						}
					}
				}

				$attempt_item->survey = [];

				foreach ( $all_answers as $answer_title ) {
					$attempt_item->survey[] = [
						'answer_title' => $answer_title,
						'count'        => $count_map[ $answer_title ] ?? 0,
					];
				}
			}//end if

			$response[] = $attempt_item;
		}//end foreach

		wp_send_json_success( $response );
	}

	public function get_user_attempt_by_quiz( $payload_data ) {
		$payload = Sanitizer::sanitize_payload( [
			'quiz_id' => 'integer',
		], $payload_data );
		$quiz_id = $payload['quiz_id'] ?? 0;
		$type      = get_post_meta( $quiz_id, 'quizpress_quiz_type', true );
		$user_id = get_current_user_id();
		$all_attempts = \QuizPress\API\Query\Attempts::get_attempts_by_quiz_and_user_id( $quiz_id, $user_id );
		$last_attempt_status = '';
		if ( $all_attempts ) {
			foreach ( $all_attempts as &$attempt ) {
				$info = json_decode( $attempt->attempt_info, true );
				$question_ids = isset( $info[0]['render_question_ids'] ) ? $info[0]['render_question_ids'] : $info['render_question_ids'];
				$attempt->skip_questions = Query::get_skipped_question_count( count( $question_ids ), $attempt->attempt_id );
				$attempt->attempt_info = $info;
			}
			unset( $attempt );
			$last_attempt_status = in_array( $type, [ 'survey', 'poll' ], true ) ? 'passed' : \QuizPress\API\Query\Attempts::get_last_quiz_attempt_status( $quiz_id, $user_id );
		}
		$data = (object) [
			'status' => $last_attempt_status,
			'attempts' => $all_attempts,
		];
		do_action( 'quizpress/get_attempt_status', $last_attempt_status, $quiz_id, $user_id );
		wp_send_json_success( $data );
	}

	public function get_user_attempt_feedback( $payload_data ) {
		$payload = Sanitizer::sanitize_payload([
			'attempt_id' => 'integer',
		], $payload_data );
		$attempt_id = ( isset( $payload['attempt_id'] ) ? $payload['attempt_id'] : 0 );

		$attempt = (object) Query::get_quiz_attempt( $attempt_id );
		$attempt->attempt_info = ! empty( $attempt->attempt_info ) ? json_decode( $attempt->attempt_info ) : '';
		$feedback = isset( $attempt->attempt_info->feedback ) ? $attempt->attempt_info->feedback : '';

		wp_send_json_success( $feedback );
	}
}
