<?php
/**
 * LearnDash LMS integration.
 *
 * Handles programmatic creation of LearnDash quizzes and questions
 * using the WpProQuiz model layer and LearnDash helper functions.
 *
 * @package MasterQuiz
 * @since   1.0.0
 */

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

/**
 * Class MasterQuiz_Learndash
 *
 * Creates fully functional LearnDash quizzes from AI-generated quiz data.
 * Manages dual storage: WpProQuiz database records + WordPress CPT posts.
 *
 * @since 1.0.0
 */
class MasterQuiz_Learndash {

	/**
	 * Check if LearnDash is active.
	 *
	 * @since 1.0.0
	 *
	 * @return bool True if LearnDash is installed and active.
	 */
	public static function is_active() {
		return class_exists( 'SFWD_LMS' ) && defined( 'LEARNDASH_VERSION' );
	}

	/**
	 * Create a LearnDash quiz from generated quiz data.
	 *
	 * @since 1.0.0
	 *
	 * @param array $quiz_data The generated quiz data with 'title' and 'questions' keys.
	 * @param array $args      Additional arguments:
	 *                         - course_id   (int)    Optional course to assign quiz to.
	 *                         - lesson_id   (int)    Optional lesson to assign quiz to.
	 *                         - passing_pct (int)    Passing percentage (default 80).
	 * @return array|WP_Error Array with quiz_post_id, pro_quiz_id, question_count on success.
	 */
	public function create_quiz( $quiz_data, $args = array() ) {
		if ( ! self::is_active() ) {
			return new WP_Error( 'learndash_inactive', esc_html__( 'LearnDash is not active.', 'masterquiz-ai' ) );
		}

		$questions = isset( $quiz_data['questions'] ) ? $quiz_data['questions'] : array();
		if ( empty( $questions ) ) {
			return new WP_Error( 'no_questions', esc_html__( 'No questions found in quiz data.', 'masterquiz-ai' ) );
		}

		$raw_title   = isset( $quiz_data['quiz_title'] ) ? $quiz_data['quiz_title'] : ( isset( $quiz_data['title'] ) ? $quiz_data['title'] : '' );
		$title       = ! empty( $raw_title ) ? sanitize_text_field( $raw_title ) : __( 'Generated Quiz', 'masterquiz-ai' );
		$course_id   = isset( $args['course_id'] ) ? absint( $args['course_id'] ) : 0;
		$lesson_id   = isset( $args['lesson_id'] ) ? absint( $args['lesson_id'] ) : 0;
		$passing_pct = isset( $args['passing_pct'] ) ? absint( $args['passing_pct'] ) : 80;

		// Step 1: Create WpProQuiz quiz record.
		$pro_quiz_id = $this->create_pro_quiz( $title, $passing_pct );
		if ( is_wp_error( $pro_quiz_id ) ) {
			return $pro_quiz_id;
		}

		// Step 2: Create sfwd-quiz WordPress post.
		$quiz_post_id = $this->create_quiz_post( $title, $pro_quiz_id, $course_id, $lesson_id, $passing_pct );
		if ( is_wp_error( $quiz_post_id ) ) {
			return $quiz_post_id;
		}

		// Step 3: Update WpProQuiz record with post ID reference.
		$this->link_pro_quiz_to_post( $pro_quiz_id, $quiz_post_id );

		// Step 4: Create each question.
		$question_map   = array();
		$question_count = 0;
		$sort_order     = 1;

		foreach ( $questions as $q_data ) {
			$result = $this->create_question( $q_data, $pro_quiz_id, $quiz_post_id, $sort_order );

			if ( is_wp_error( $result ) ) {
				MasterQuiz_Logger::warning(
					'Failed to create LearnDash question.',
					array(
						'error' => $result->get_error_message(),
						'sort'  => $sort_order,
					)
				);
				continue;
			}

			$question_map[ $result['question_post_id'] ] = $result['pro_question_id'];
			++$question_count;
			++$sort_order;
		}

		if ( 0 === $question_count ) {
			// Clean up quiz post and pro quiz if no questions were created.
			wp_delete_post( $quiz_post_id, true );
			$this->delete_pro_quiz( $pro_quiz_id );

			return new WP_Error( 'no_questions_created', esc_html__( 'Failed to create any LearnDash questions.', 'masterquiz-ai' ) );
		}

		// Step 5: Update ld_quiz_questions meta.
		update_post_meta( $quiz_post_id, 'ld_quiz_questions', $question_map );

		// Step 6: Dirty quiz questions cache so LearnDash rebuilds it.
		if ( function_exists( 'learndash_set_quiz_questions_dirty' ) ) {
			learndash_set_quiz_questions_dirty( $quiz_post_id );
		}

		MasterQuiz_Logger::info(
			'LearnDash quiz created.',
			array(
				'quiz_post_id'   => $quiz_post_id,
				'pro_quiz_id'    => $pro_quiz_id,
				'question_count' => $question_count,
			)
		);

		return array(
			'quiz_post_id'   => $quiz_post_id,
			'pro_quiz_id'    => $pro_quiz_id,
			'question_count' => $question_count,
			'edit_url'       => get_edit_post_link( $quiz_post_id, 'raw' ),
		);
	}

	/**
	 * Create a WpProQuiz quiz record.
	 *
	 * @since 1.0.0
	 *
	 * @param string $title       Quiz title.
	 * @param int    $passing_pct Passing percentage.
	 * @return int|WP_Error Pro quiz ID or error.
	 */
	private function create_pro_quiz( $title, $passing_pct ) {
		if ( ! class_exists( 'WpProQuiz_Model_Quiz' ) || ! class_exists( 'WpProQuiz_Model_QuizMapper' ) ) {
			return new WP_Error( 'missing_class', esc_html__( 'WpProQuiz model classes not available.', 'masterquiz-ai' ) );
		}

		$quiz = new WpProQuiz_Model_Quiz();
		$quiz->setName( $title );
		$quiz->setText(
			/* translators: %s: plugin name */
			sprintf( esc_html__( 'Quiz generated by %s', 'masterquiz-ai' ), 'MasterQuiz AI' )
		);
		$quiz->setShowPoints( true );
		$quiz->setStatisticsOn( true );
		$quiz->setQuizModus( 0 ); // Normal mode.
		$quiz->setShowReviewQuestion( true );
		$quiz->setQuizSummaryHide( false );
		$quiz->setAnswerRandom( true );
		$quiz->setQuestionRandom( false );
		$quiz->setTimeLimit( 0 );
		$quiz->setAutostart( false );
		$quiz->setForcingQuestionSolve( false );
		$quiz->setHideResultCorrectQuestion( false );
		$quiz->setHideResultQuizTime( false );
		$quiz->setHideResultPoints( false );

		// Result text with passing percentage.
		$result_text = array(
			'prozent' => array( 0, $passing_pct ),
			'activ'   => array( 1, 1 ),
			'text'    => array(
				"<p>" . wp_kses_post(
					sprintf(
						/* translators: %d: passing percentage */
						__( 'You did not reach the passing score of %d%%. Please review the material and try again.', 'masterquiz-ai' ),
						$passing_pct
					)
				) . "</p>",
				"<p>" . wp_kses_post( __( 'Congratulations! You passed the quiz.', 'masterquiz-ai' ) ) . "</p>",
			),
		);
		$quiz->setResultText( $result_text );

		$mapper = new WpProQuiz_Model_QuizMapper();
		$saved  = $mapper->save( $quiz );

		// LearnDash versions vary: some return the saved object, others modify $quiz in place.
		// Prefer the returned object if available, otherwise use the original.
		if ( is_object( $saved ) ) {
			$quiz = $saved;
		}

		if ( ! is_object( $quiz ) || ! $quiz->getId() ) {
			return new WP_Error( 'save_failed', esc_html__( 'Failed to save WpProQuiz quiz.', 'masterquiz-ai' ) );
		}

		return $quiz->getId();
	}

	/**
	 * Create the sfwd-quiz WordPress post.
	 *
	 * @since 1.0.0
	 *
	 * @param string $title       Quiz title.
	 * @param int    $pro_quiz_id WpProQuiz ID.
	 * @param int    $course_id   Course post ID (0 for none).
	 * @param int    $lesson_id   Lesson post ID (0 for none).
	 * @param int    $passing_pct Passing percentage.
	 * @return int|WP_Error Quiz post ID or error.
	 */
	private function create_quiz_post( $title, $pro_quiz_id, $course_id, $lesson_id, $passing_pct ) {
		$post_data = array(
			'post_type'   => 'sfwd-quiz',
			'post_title'  => $title,
			'post_status' => 'publish',
			'post_author' => get_current_user_id(),
		);

		$quiz_post_id = wp_insert_post( $post_data, true );
		if ( is_wp_error( $quiz_post_id ) ) {
			return $quiz_post_id;
		}

		// Link to WpProQuiz.
		update_post_meta( $quiz_post_id, 'quiz_pro_id', $pro_quiz_id );

		if ( function_exists( 'learndash_update_setting' ) ) {
			learndash_update_setting( $quiz_post_id, 'quiz_pro', $pro_quiz_id );
		}

		// Build _sfwd-quiz settings meta.
		$quiz_settings = array(
			'sfwd-quiz_quiz_pro'                  => $pro_quiz_id,
			'sfwd-quiz_passingpercentage'         => $passing_pct,
			'sfwd-quiz_quiz_materials_enabled'     => '',
			'sfwd-quiz_autostart'                  => '',
			'sfwd-quiz_quiz_time_limit_enabled'    => '',
			'sfwd-quiz_timeLimit'                  => 0,
			'sfwd-quiz_startOnlyRegisteredUser'    => '',
			'sfwd-quiz_prerequisiteList'           => array(),
			'sfwd-quiz_toplistActivated'           => '',
			'sfwd-quiz_certificate'                => 0,
			'sfwd-quiz_threshold'                  => (float) $passing_pct / 100,
		);

		// Course association.
		if ( $course_id > 0 ) {
			$quiz_settings['sfwd-quiz_course'] = $course_id;
			if ( function_exists( 'learndash_update_setting' ) ) {
				learndash_update_setting( $quiz_post_id, 'course', $course_id );
			}
		}

		// Lesson association.
		if ( $lesson_id > 0 ) {
			$quiz_settings['sfwd-quiz_lesson'] = $lesson_id;
			if ( function_exists( 'learndash_update_setting' ) ) {
				learndash_update_setting( $quiz_post_id, 'lesson', $lesson_id );
			}
		}

		update_post_meta( $quiz_post_id, '_sfwd-quiz', $quiz_settings );

		return $quiz_post_id;
	}

	/**
	 * Link WpProQuiz record back to the WP post.
	 *
	 * @since 1.0.0
	 *
	 * @param int $pro_quiz_id  WpProQuiz quiz ID.
	 * @param int $quiz_post_id WordPress quiz post ID.
	 */
	private function link_pro_quiz_to_post( $pro_quiz_id, $quiz_post_id ) {
		if ( ! class_exists( 'WpProQuiz_Model_QuizMapper' ) ) {
			return;
		}

		$mapper = new WpProQuiz_Model_QuizMapper();
		$quiz   = $mapper->fetch( $pro_quiz_id );

		if ( $quiz && method_exists( $quiz, 'setPostId' ) ) {
			$quiz->setPostId( $quiz_post_id );
			$mapper->save( $quiz );
		}
	}

	/**
	 * Create a single LearnDash question (WpProQuiz record + WP post).
	 *
	 * @since 1.0.0
	 *
	 * @param array $q_data       Question data from the quiz generator.
	 * @param int   $pro_quiz_id  WpProQuiz quiz ID.
	 * @param int   $quiz_post_id WordPress quiz post ID.
	 * @param int   $sort_order   Sort position.
	 * @return array|WP_Error Array with question_post_id and pro_question_id.
	 */
	private function create_question( $q_data, $pro_quiz_id, $quiz_post_id, $sort_order ) {
		if ( ! class_exists( 'WpProQuiz_Model_Question' ) || ! class_exists( 'WpProQuiz_Model_QuestionMapper' ) ) {
			return new WP_Error( 'missing_class', esc_html__( 'WpProQuiz question classes not available.', 'masterquiz-ai' ) );
		}

		// Support both key formats: 'question_text' (AI generator) and 'question' (generic).
		$raw_text      = isset( $q_data['question_text'] ) ? $q_data['question_text'] : ( isset( $q_data['question'] ) ? $q_data['question'] : '' );
		$question_text = wp_kses_post( $raw_text );
		$q_type        = isset( $q_data['type'] ) ? sanitize_text_field( $q_data['type'] ) : 'multiple_choice';
		$points        = isset( $q_data['points'] ) ? (float) $q_data['points'] : 1.0;
		$explanation   = isset( $q_data['explanation'] ) ? wp_kses_post( $q_data['explanation'] ) : '';
		$hint          = isset( $q_data['hint'] ) ? wp_kses_post( $q_data['hint'] ) : '';
		$options       = isset( $q_data['options'] ) ? $q_data['options'] : array();

		$ld_answer_type = $this->map_question_type( $q_type, $options );

		// Build WpProQuiz question model.
		$question = new WpProQuiz_Model_Question();
		$question->setQuizId( $pro_quiz_id );
		$question->setTitle( wp_strip_all_tags( $question_text ) );
		$question->setQuestion( '<p>' . $question_text . '</p>' );
		$question->setAnswerType( $ld_answer_type );
		$question->setPoints( $points );
		$question->setSort( $sort_order );
		$question->setOnline( true );
		$question->setShowPointsInBox( true );
		$question->setAnswerPointsActivated( false );
		$question->setCorrectSameText( false );

		if ( ! empty( $explanation ) ) {
			$question->setCorrectMsg( '<p>' . $explanation . '</p>' );
			$question->setIncorrectMsg( '<p>' . $explanation . '</p>' );
			$question->setCorrectSameText( true );
		}

		if ( ! empty( $hint ) ) {
			$question->setTipEnabled( true );
			$question->setTipMsg( '<p>' . $hint . '</p>' );
		}

		// Build answer data.
		$answer_data = $this->build_answer_data( $ld_answer_type, $options, $points );
		$question->setAnswerData( $answer_data );

		// Save to WpProQuiz database.
		$mapper = new WpProQuiz_Model_QuestionMapper();
		$saved  = $mapper->save( $question );

		// LearnDash versions vary: some return the saved object, others modify $question in place.
		if ( is_object( $saved ) ) {
			$question = $saved;
		}

		if ( ! is_object( $question ) || ! $question->getId() ) {
			return new WP_Error( 'save_failed', esc_html__( 'Failed to save WpProQuiz question.', 'masterquiz-ai' ) );
		}

		$pro_question_id = $question->getId();

		// Create sfwd-question WordPress post.
		// post_content must contain the question HTML — LearnDash renders it on the frontend.
		$question_post_id = wp_insert_post(
			array(
				'post_type'    => 'sfwd-question',
				'post_title'   => wp_strip_all_tags( $question_text ),
				'post_content' => '<p>' . $question_text . '</p>',
				'post_status'  => 'publish',
				'post_author'  => get_current_user_id(),
				'menu_order'   => $sort_order,
			),
			true
		);

		if ( is_wp_error( $question_post_id ) ) {
			return $question_post_id;
		}

		// Link question post to WpProQuiz question.
		update_post_meta( $question_post_id, 'question_pro_id', $pro_question_id );
		update_post_meta( $question_post_id, 'quiz_id', $quiz_post_id );

		// Build _sfwd-question settings meta.
		$question_settings = array(
			'sfwd-question_quiz'    => $quiz_post_id,
			'sfwd-question_quiz_id' => $pro_quiz_id,
		);
		update_post_meta( $question_post_id, '_sfwd-question', $question_settings );

		// Update pro question with post ID reference.
		$question->setQuestionPostId( $question_post_id );
		$mapper->save( $question );

		// Sync question fields using LearnDash helper.
		if ( function_exists( 'learndash_proquiz_sync_question_fields' ) ) {
			learndash_proquiz_sync_question_fields( $question_post_id, $pro_question_id );
		}

		// Associate question with quiz via LearnDash setting.
		if ( function_exists( 'learndash_update_setting' ) ) {
			learndash_update_setting( $question_post_id, 'quiz', $quiz_post_id );
		}

		return array(
			'question_post_id' => $question_post_id,
			'pro_question_id'  => $pro_question_id,
		);
	}

	/**
	 * Build answer data array for a question.
	 *
	 * @since 1.0.0
	 *
	 * @param string $ld_type LearnDash answer type (single, multiple, essay).
	 * @param array  $options Array of option objects with 'text' and 'is_correct' keys.
	 * @param float  $points  Total question points.
	 * @return array Array of WpProQuiz_Model_AnswerTypes objects.
	 */
	private function build_answer_data( $ld_type, $options, $points ) {
		$answers = array();

		if ( 'essay' === $ld_type ) {
			$answer = new WpProQuiz_Model_AnswerTypes();
			$answer->setAnswer( '' );
			$answer->setCorrect( false );
			$answer->setPoints( $points );

			if ( method_exists( $answer, 'setGraded' ) ) {
				$answer->setGraded( true );
			}
			if ( method_exists( $answer, 'setGradedType' ) ) {
				$answer->setGradedType( 'text' );
			}
			if ( method_exists( $answer, 'setGradingProgression' ) ) {
				$answer->setGradingProgression( 'not-graded-none' );
			}

			$answers[] = $answer;
			return $answers;
		}

		// Single / Multiple choice answers.
		// Support both 'correct' (AI generator) and 'is_correct' key formats.
		$correct_count = 0;
		foreach ( $options as $opt ) {
			if ( ! empty( $opt['correct'] ) || ! empty( $opt['is_correct'] ) ) {
				++$correct_count;
			}
		}

		foreach ( $options as $opt ) {
			$answer = new WpProQuiz_Model_AnswerTypes();
			$answer->setAnswer( isset( $opt['text'] ) ? wp_kses_post( $opt['text'] ) : '' );
			$answer->setHtml( false );

			$is_correct = ! empty( $opt['correct'] ) || ! empty( $opt['is_correct'] );
			$answer->setCorrect( $is_correct );

			// Points logic: for single choice, correct answer gets points.
			// For multiple choice, each correct answer gets a share.
			if ( 'multiple' === $ld_type && $correct_count > 0 ) {
				$answer->setPoints( $is_correct ? round( $points / $correct_count, 2 ) : 0 );
			} else {
				$answer->setPoints( $is_correct ? $points : 0 );
			}

			$answers[] = $answer;
		}

		return $answers;
	}

	/**
	 * Map AI question type to LearnDash answer_type.
	 *
	 * @since 1.0.0
	 *
	 * @param string $ai_type AI question type.
	 * @param array  $options Options array to check for multiple correct.
	 * @return string LearnDash answer_type (single, multiple, essay).
	 */
	private function map_question_type( $ai_type, $options = array() ) {
		switch ( $ai_type ) {
			case 'true_false':
				return 'single';

			case 'multiple_choice':
				// Check if multiple correct answers exist.
				$correct_count = 0;
				foreach ( $options as $opt ) {
					if ( ! empty( $opt['correct'] ) || ! empty( $opt['is_correct'] ) ) {
						++$correct_count;
					}
				}
				return $correct_count > 1 ? 'multiple' : 'single';

			case 'analytical_essay':
			case 'comparative_analysis':
				return 'essay';

			default:
				return 'single';
		}
	}

	/**
	 * Delete a WpProQuiz quiz record.
	 *
	 * @since 1.0.0
	 *
	 * @param int $pro_quiz_id WpProQuiz quiz ID.
	 */
	private function delete_pro_quiz( $pro_quiz_id ) {
		if ( class_exists( 'WpProQuiz_Model_QuizMapper' ) ) {
			$mapper = new WpProQuiz_Model_QuizMapper();
			if ( method_exists( $mapper, 'delete' ) ) {
				$mapper->delete( $pro_quiz_id );
			}
		}
	}

	/**
	 * Get available LearnDash courses for the settings dropdown.
	 *
	 * @since 1.0.0
	 *
	 * @return array Associative array of course_id => title.
	 */
	public static function get_courses() {
		if ( ! self::is_active() ) {
			return array();
		}

		$courses = get_posts(
			array(
				'post_type'      => 'sfwd-courses',
				'posts_per_page' => 100,
				'post_status'    => 'publish',
				'orderby'        => 'title',
				'order'          => 'ASC',
				'fields'         => 'ids',
			)
		);

		$list = array();
		foreach ( $courses as $course_id ) {
			$list[ $course_id ] = get_the_title( $course_id );
		}

		return $list;
	}

	/**
	 * Get available lessons for a given course.
	 *
	 * @since 1.0.0
	 *
	 * @param int $course_id Course post ID.
	 * @return array Associative array of lesson_id => title.
	 */
	public static function get_lessons( $course_id ) {
		if ( ! self::is_active() || empty( $course_id ) ) {
			return array();
		}

		$args = array(
			'post_type'      => 'sfwd-lessons',
			'posts_per_page' => 100,
			'post_status'    => 'publish',
			'orderby'        => 'menu_order',
			'order'          => 'ASC',
			'fields'         => 'ids',
			'meta_query'     => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
				array(
					'key'   => 'course_id',
					'value' => absint( $course_id ),
				),
			),
		);

		$lessons = get_posts( $args );

		$list = array();
		foreach ( $lessons as $lesson_id ) {
			$list[ $lesson_id ] = get_the_title( $lesson_id );
		}

		return $list;
	}
}
