<?php
/**
 * Handle ChatGPT course creation.
 *
 * @package TutorPro\TutorAI
 * @author Themeum <support@themeum.com>
 * @link https://themeum.com
 * @since 3.0.0
 */

namespace TutorPro\TutorAI;

use Throwable;
use TUTOR\Course;
use Tutor\Helpers\HttpHelper;
use Tutor\Helpers\ValidationHelper;
use TUTOR\Input;
use Tutor\Models\CourseModel;
use TUTOR\Quiz;
use TUTOR\QuizBuilder;
use Tutor\Traits\JsonResponse;

/**
 * AiCourseCreator Class.
 *
 * @since 3.0.0
 */
class CourseCreatorController {
	use JsonResponse;

	/**
	 * Topic menu order.
	 *
	 * @since 3.0.0
	 *
	 * @var integer
	 */
	private $topic_order = 0;

	/**
	 * Course content menu order.
	 *
	 * @since 3.0.0
	 *
	 * @var integer
	 */
	private $content_order = 0;

	/**
	 * Register hooks.
	 *
	 * @since 3.0.0
	 *
	 * @return void
	 */
	public function __construct() {
		/**
		 * Handle AJAX request for creating course contents generated by AI.
		 *
		 * @since 3.0.0
		 */
		add_action( 'wp_ajax_tutor_pro_ai_course_create', array( $this, 'ajax_ai_course_create' ) );

		/**
		 * Add a filter hook for course details response.
		 *
		 * @since 3.0.0
		 */
		add_filter( 'tutor_course_details_response', array( $this, 'extend_course_details_response' ) );
	}

	/**
	 * Validate payload.
	 *
	 * @since 3.0.0
	 *
	 * @param array $payload payload.
	 *
	 * @return object consist success, errors.
	 */
	public function validate_payload( $payload ) {
		$errors  = array();
		$success = true;

		if ( ! is_array( $payload ) ) {
			$success           = false;
			$errors['payload'] = __( 'Invalid payload', 'tutor-pro' );
		}

		$rules = array(
			'title'       => 'required',
			'description' => 'if_input|string',
			'topics'      => 'required|is_array',
		);

		$validation = ValidationHelper::validate(
			$rules,
			$payload
		);

		if ( ! $validation->success ) {
			$success = false;
			$errors  = array_merge( $errors, $validation->errors );
		}

		return (object) array(
			'success' => $success,
			'errors'  => $errors,
		);
	}

	/**
	 * Add topic.
	 *
	 * @since 3.0.0
	 *
	 * @param int    $course_id course id.
	 * @param string $title title.
	 * @param string $description description (optional).
	 *
	 * @return int|false
	 */
	private function add_topic( $course_id, $title, $description = '' ) {
		$data = array(
			'post_title'   => $title,
			'post_content' => $description,
			'post_type'    => tutor()->topics_post_type,
			'post_parent'  => $course_id,
			'post_status'  => 'publish',
			'menu_order'   => $this->topic_order,
		);

		$topic_id = wp_insert_post( $data );

		if ( ! $topic_id ) {
			return false;
		}

		return $topic_id;
	}

	/**
	 * Add lesson.
	 *
	 * @since 3.0.0
	 *
	 * @param int    $topic_id topic id.
	 * @param string $title title.
	 * @param string $description description (optional).
	 *
	 * @return void
	 */
	private function add_lesson( $topic_id, $title, $description = '' ) {
		$data = array(
			'post_title'   => $title,
			'post_content' => $description,
			'post_type'    => tutor()->lesson_post_type,
			'post_parent'  => $topic_id,
			'post_status'  => 'publish',
			'menu_order'   => $this->content_order,
		);

		wp_insert_post( $data );
	}

	/**
	 * Check assignment addon active.
	 *
	 * @since 3.0.0
	 *
	 * @return boolean
	 */
	private function is_assignment_addon_active() {
		$basename = plugin_basename( TUTOR_ASSIGNMENTS_FILE );
		return tutor_utils()->is_addon_enabled( $basename );
	}

	/**
	 * Add assignment.
	 *
	 * @since 3.0.0
	 *
	 * @param int    $topic_id topic id.
	 * @param string $title title.
	 * @param string $description description (optional).
	 *
	 * @return int|false
	 */
	private function add_assignment( $topic_id, $title, $description = '' ) {
		$default_options = array(
			'time_duration'          => array(
				'time'  => 'weeks',
				'value' => 1,
			),
			'total_mark'             => 10,
			'pass_mark'              => 5,
			'upload_files_limit'     => 1,
			'upload_file_size_limit' => 2,
		);

		$data = array(
			'post_title'   => $title,
			'post_content' => $description,
			'post_type'    => tutor()->assignment_post_type,
			'post_parent'  => $topic_id,
			'post_status'  => 'publish',
			'menu_order'   => $this->content_order,
		);

		$assignment_id = wp_insert_post( $data );
		if ( $assignment_id ) {
			update_post_meta( $assignment_id, 'assignment_option', $default_options );
		}

		return $assignment_id ? $assignment_id : false;
	}

	/**
	 * Prepare question.
	 *
	 * @since 3.0.0
	 *
	 * @param array $question question.
	 *
	 * @return array
	 */
	private function prepare_question( $question ) {
		$type = $question['type'] ?? '';

		$arr[ QuizBuilder::TRACKING_KEY ] = QuizBuilder::FLAG_NEW;
		$arr['question_title']            = $question['title'] ?? '';
		$arr['question_description']      = $question['description'] ?? '';
		$arr['question_type']             = $type;
		$arr['question_mark']             = 1;
		$arr['question_settings']         = Quiz::get_default_question_settings( $type );

		$options = $question['options'] ?? array();
		foreach ( $options as $option ) {
			$arr ['question_answers'][] = array(
				QuizBuilder::TRACKING_KEY => QuizBuilder::FLAG_NEW,
				'answer_title'            => $option['name'] ?? '',
				'is_correct'              => $option['is_correct'] ?? 0,
			);
		}

		return $arr;
	}

	/**
	 * Add assignment.
	 *
	 * @since 3.0.0
	 *
	 * @param int    $topic_id topic id.
	 * @param string $title title.
	 * @param string $description description.
	 * @param array  $questions questions.
	 *
	 * @return void
	 */
	private function add_quiz( $topic_id, $title, $description = '', $questions = array() ) {
		$allowed_types      = array( 'true_false', 'multiple_choice', 'open_ended' );
		$prepared_questions = array();

		foreach ( $questions as $question ) {
			$type = $question['type'] ?? '';
			if ( ! in_array( $type, $allowed_types, true ) ) {
				continue;
			}

			$prepared_questions[] = $this->prepare_question( $question );
		}

		$payload = array(
			'post_title'   => $title,
			'post_content' => $description,
			'menu_order'   => $this->content_order,
			'quiz_option'  => Quiz::get_default_quiz_settings(),
			'questions'    => $prepared_questions,
		);

		( new QuizBuilder( false ) )->save_quiz( $topic_id, $payload );
	}

	/**
	 * Add course contents.
	 *
	 * @since 3.0.0
	 *
	 * @param int   $course_id course id.
	 * @param array $payload payload.
	 *
	 * @return int course id.
	 *
	 * @throws Throwable If fail.
	 */
	private function add_course_contents( $course_id, $payload ) {
		global $wpdb;

		try {
			$wpdb->query( 'START TRANSACTION' );

			$base_slug   = sanitize_title( $payload['title'] );
			$unique_slug = wp_unique_post_slug( $base_slug, $course_id, get_post_status( $course_id ), tutor()->course_post_type, 0 );

			$course_data = array(
				'post_title'   => $payload['title'],
				'post_content' => $payload['description'] ?? '',
				'post_name'    => $unique_slug,
			);

			$wpdb->update( $wpdb->posts, $course_data, array( 'ID' => $course_id ) );

			// Upload featured image add attached with course.
			if ( ! empty( $payload['featured_image'] ) ) {
				$featured_image = tutor_utils()->upload_base64_image( $payload['featured_image'] );
				update_post_meta( $course_id, '_thumbnail_id', $featured_image->id );
			}

			// Backup course authors.
			$course_authors = CourseModel::get_course_instructor_ids( $course_id );

			// Delete all existing topics and it's content.
			( new CourseModel() )->delete_course_data( $course_id );

			// Re-assign course authors.
			foreach ( $course_authors as $author_id ) {
				add_user_meta( $author_id, '_tutor_instructor_course_id', $course_id );
			}

			// Create course contents.
			$topics = $payload['topics'] ?? array();
			foreach ( $topics as $topic ) {
				$topic_id = $this->add_topic( $course_id, $topic['title'] ?? '' );
				$this->topic_order++;

				$topic_contents       = $topic['contents'] ?? array();
				$allowed_content_type = array( 'lesson', 'assignment', 'quiz' );

				foreach ( $topic_contents as $content ) {
					$content_type = $content['type'] ?? '';
					if ( ! in_array( $content_type, $allowed_content_type, true ) ) {
						continue;
					}

					$title       = $content['title'] ?? '';
					$description = $content['description'] ?? '';

					/**
					 * Add lesson
					 */
					if ( 'lesson' === $content_type ) {
						$this->add_lesson( $topic_id, $title, $description );
					}

					/**
					 * Add assignment
					 */
					if ( 'assignment' === $content_type && $this->is_assignment_addon_active() ) {
						$this->add_assignment( $topic_id, $title, $description );
					}

					/**
					 * Add quiz
					 */
					if ( 'quiz' === $content_type ) {
						$questions = $content['questions'] ?? array();
						if ( count( $questions ) > 0 ) {
							$this->add_quiz( $topic_id, $title, $description, $questions );
						}
					}

					$this->content_order++;
				}
			}

			$wpdb->query( 'COMMIT' );
		} catch ( Throwable $error ) {
			$wpdb->query( 'ROLLBACK' );
			throw $error;
		}

		return $course_id;
	}

	/**
	 * Extend course details response
	 *
	 * @since 3.0.0
	 *
	 * @param array $data response data.
	 *
	 * @return array
	 */
	public function extend_course_details_response( array $data ) {
		$course_id = $data['ID'] ?? 0;
		if ( ! $course_id ) {
			return $data;
		}

		$data['total_enrolled_student'] = tutor_utils()->get_total_enrolments( '', '', $course_id );

		return $data;
	}

	/**
	 * Course create with AI
	 *
	 * @since 3.0.0
	 *
	 * @return void
	 */
	public function ajax_ai_course_create() {
		tutor_utils()->check_nonce();

		$course_id  = Input::post( 'course_id', 0, Input::TYPE_INT );
		$course_cls = new Course( false );
		$course_cls->check_access( $course_id );

		$payload    = $_POST['payload'] ?? array(); //phpcs:ignore
		if ( is_string( $payload ) ) {
			$payload = json_decode( wp_unslash( $payload ), true );
		}

		$validation = $this->validate_payload( $payload );

		if ( ! $validation->success ) {
			$this->json_response(
				tutor_utils()->error_message( 'validation_error' ),
				$validation->errors,
				HttpHelper::STATUS_UNPROCESSABLE_ENTITY
			);
		}

		$total_enrollment = tutor_utils()->get_total_enrolments( '', '', $course_id );
		if ( $total_enrollment > 0 ) {
			$this->json_response(
				__( "Re-creation isn't allowed due to enrolled students.", 'tutor-pro' ),
				null,
				HttpHelper::STATUS_BAD_REQUEST
			);
		}

		try {
			$this->add_course_contents( $course_id, $payload );
			$this->json_response(
				__( 'Successfully added', 'tutor-pro' ),
				$total_enrollment
			);
		} catch ( \Throwable $th ) {
			$this->json_response(
				$th->getMessage(),
				null,
				HttpHelper::STATUS_INTERNAL_SERVER_ERROR
			);
		}
	}
}
