<?php
/**
 * Manage Lesson
 *
 * @package Tutor
 * @author Themeum <support@themeum.com>
 * @link https://themeum.com
 * @since 1.0.0
 */

namespace TUTOR;

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

use Tutor\Helpers\HttpHelper;
use Tutor\Helpers\ValidationHelper;
use Tutor\Models\LessonModel;
use Tutor\Traits\JsonResponse;

/**
 * Lesson class
 *
 * @since 1.0.0
 */
class Lesson extends Tutor_Base {
	use JsonResponse;

	/**
	 * Register hooks
	 *
	 * @since 1.0.0
	 * @since 3.7.0 param register hook added.
	 *
	 * @param bool $register_hooks register hooks or not.
	 *
	 * @return void
	 */
	public function __construct( $register_hooks = true ) {
		parent::__construct();

		if ( ! $register_hooks ) {
			return;
		}

		add_action( 'save_post_' . $this->lesson_post_type, array( $this, 'save_lesson_meta' ) );

		add_action( 'wp_ajax_tutor_lesson_details', array( $this, 'ajax_lesson_details' ) );
		add_action( 'wp_ajax_tutor_save_lesson', array( $this, 'ajax_save_lesson' ) );
		add_action( 'wp_ajax_tutor_delete_lesson', array( $this, 'ajax_delete_lesson' ) );

		add_filter( 'get_sample_permalink', array( $this, 'change_lesson_permalink' ), 10, 2 );

		/**
		 * Frontend Action
		 */
		add_action( 'template_redirect', array( $this, 'mark_lesson_complete' ) );

		add_action( 'wp_ajax_tutor_render_lesson_content', array( $this, 'tutor_render_lesson_content' ) );

		/**
		 * For public course access
		 */
		add_action( 'wp_ajax_nopriv_tutor_render_lesson_content', array( $this, 'tutor_render_lesson_content' ) );

		/**
		 * Autoplay next video
		 *
		 * @since 1.4.9
		 */
		add_action( 'wp_ajax_autoload_next_course_content', array( $this, 'autoload_next_course_content' ) );

		/**
		 * Load next course item after click complete button
		 *
		 * @since 1.5.3
		 */
		add_action( 'tutor_lesson_completed_after', array( $this, 'tutor_lesson_completed_after' ), 999 );

		/**
		 * Lesson comment & reply ajax handler
		 *
		 * @since 2.0.0
		 */
		add_action( 'wp_ajax_tutor_single_course_lesson_load_more', array( $this, 'tutor_single_course_lesson_load_more' ) );
		add_action( 'wp_ajax_tutor_create_lesson_comment', array( $this, 'tutor_single_course_lesson_load_more' ) );
		add_action( 'wp_ajax_tutor_reply_lesson_comment', array( $this, 'reply_lesson_comment' ) );
	}

	/**
	 * Manage load more & comment create
	 *
	 * @since 2.0.6
	 * @return void  send wp json data
	 */
	public function tutor_single_course_lesson_load_more() {
		tutor_utils()->checking_nonce();
		$comment = Input::post( 'comment', '', Input::TYPE_KSES_POST );
		if ( 'tutor_create_lesson_comment' === Input::post( 'action' ) && strlen( $comment ) > 0 ) {
			$comment_data = array(
				'comment_content' => $comment,
				'comment_post_ID' => Input::post( 'comment_post_ID', 0, Input::TYPE_INT ),
				'comment_parent'  => Input::post( 'comment_parent', 0, Input::TYPE_INT ),
			);
			self::create_comment( $comment_data );
			do_action( 'tutor_new_comment_added', $comment_data );
		}
		ob_start();
		tutor_load_template( 'single.lesson.comment' );
		$html = ob_get_clean();
		wp_send_json_success( array( 'html' => $html ) );
	}

	/**
	 * Saving lesson meta and assets
	 *
	 * @since 1.0.0
	 *
	 * @param integer $post_ID post ID.
	 *
	 * @return void
	 */
	public function save_lesson_meta( $post_ID ) {
		$thumbnail_id = Input::post( 'thumbnail_id', 0, Input::TYPE_INT );
		if ( $thumbnail_id ) {
			update_post_meta( $post_ID, '_thumbnail_id', $thumbnail_id );
		} else {
			delete_post_meta( $post_ID, '_thumbnail_id' );
		}

		$video_source = sanitize_text_field( tutor_utils()->array_get( 'video.source', $_POST ) ); //phpcs:ignore
		if ( '-1' === $video_source ) {
			delete_post_meta( $post_ID, '_video' );
		} elseif ( $video_source ) {

			// Sanitize data through helper method.
			$video = Input::sanitize_array(
				$_POST['video'] ?? array(), //phpcs:ignore
				array(
					'source_external_url' => 'esc_url',
					'source_embedded'     => 'wp_kses_post',
				),
				true
			);
			update_post_meta( $post_ID, '_video', $video );
		}

		// Attachments.
		$attachments = array();
		// phpcs:disable WordPress.Security.NonceVerification.Missing
		if ( ! empty( $_POST['tutor_attachments'] ) ) {
			//phpcs:ignore -- data sanitized through helper method.
			$attachments = tutor_utils()->sanitize_array( wp_unslash( $_POST['tutor_attachments'] ) );
			$attachments = array_unique( $attachments );
		}

		/**
		 * If !empty attachment then update meta else
		 * delete meta key to prevent empty data in db
		 *
		 * @since 1.8.9
		*/
		if ( ! empty( $attachments ) ) {
			update_post_meta( $post_ID, '_tutor_attachments', $attachments );
		} else {
			delete_post_meta( $post_ID, '_tutor_attachments' );
		}
	}

	/**
	 * Get lesson details data.
	 *
	 * @since 3.0.0
	 *
	 * @return void
	 */
	public function ajax_lesson_details() {
		if ( ! tutor_utils()->is_nonce_verified() ) {
			$this->json_response( tutor_utils()->error_message( 'nonce' ), null, HttpHelper::STATUS_BAD_REQUEST );
		}

		$topic_id  = Input::post( 'topic_id', 0, Input::TYPE_INT );
		$lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );

		if ( ! tutor_utils()->can_user_manage( 'topic', $topic_id ) ) {
			$this->json_response(
				tutor_utils()->error_message(),
				null,
				HttpHelper::STATUS_FORBIDDEN
			);
		}

		if ( 0 !== $lesson_id ) {
			if ( ! tutor_utils()->can_user_manage( 'lesson', $lesson_id ) ) {
				$this->json_response(
					tutor_utils()->error_message(),
					null,
					HttpHelper::STATUS_FORBIDDEN
				);
			}
		}

		$data = LessonModel::get_lesson_details( $lesson_id );

		$this->json_response(
			__( 'Lesson data fetched successfully', 'tutor' ),
			$data
		);
	}

	/**
	 * Create or update lesson.
	 *
	 * @since 1.0.0
	 * @since 1.5.1 updated
	 * @since 3.0.0 refactor and response updated.
	 *
	 * @return void
	 */
	public function ajax_save_lesson() {
		if ( ! tutor_utils()->is_nonce_verified() ) {
			$this->json_response( tutor_utils()->error_message( 'nonce' ), null, HttpHelper::STATUS_BAD_REQUEST );
		}

		/**
		 * Allow iframe inside lesson content to support
		 * embed video & other stuff
		 *
		 * @since 2.1.6
		 */
		add_filter( 'wp_kses_allowed_html', Input::class . '::allow_iframe', 10, 2 );

		$is_update = false;

		$lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );
		$topic_id  = Input::post( 'topic_id', 0, Input::TYPE_INT );

		if ( $lesson_id ) {
			$is_update = true;
		}

		if ( ! tutor_utils()->can_user_manage( 'topic', $topic_id ) ) {
			$this->json_response(
				tutor_utils()->error_message(),
				null,
				HttpHelper::STATUS_FORBIDDEN
			);
		}

		$title            = Input::post( 'title' );
		$description      = Input::post( 'description', '', Input::TYPE_KSES_POST );
		$is_html_active   = Input::post( 'is_html_active' ) === 'true' ? true : false;
		$raw_html_content = Input::post( 'tutor_lesson_modal_editor', '', Input::TYPE_KSES_POST );
		$post_content     = $is_html_active ? $raw_html_content : $description;

		$rules = array(
			'topic_id'  => 'required|numeric',
			'lesson_id' => 'if_input|numeric',
		);

		//phpcs:ignore WordPress.Security.NonceVerification.Missing
		$params = Input::sanitize_array( $_POST, array( 'description' => 'wp_kses_post' ) );

		$validation = ValidationHelper::validate( $rules, $params );
		if ( ! $validation->success ) {
			$this->json_response(
				__( 'Invalid inputs', 'tutor' ),
				$validation->errors,
				HttpHelper::STATUS_UNPROCESSABLE_ENTITY
			);
		}

		$lesson_data = array(
			'post_type'      => $this->lesson_post_type,
			'post_title'     => wp_slash( $title ), // Note: Added wp_slash to support latex syntaxes.
			'post_name'      => sanitize_title( $title ),
			'post_content'   => wp_slash( $post_content ),
			'post_status'    => 'publish',
			'comment_status' => 'open',
			'post_author'    => get_current_user_id(),
			'post_parent'    => $topic_id,
		);

		if ( ! $is_update ) {
			$lesson_data['menu_order'] = tutor_utils()->get_next_course_content_order_id( $topic_id );
			$lesson_id                 = wp_insert_post( $lesson_data );

			if ( $lesson_id ) {
				do_action( 'tutor/lesson/created', $lesson_id );
			} else {
				$this->json_response(
					tutor_utils()->error_message(),
					null,
					HttpHelper::STATUS_INTERNAL_SERVER_ERROR
				);
			}
		} else {
			$lesson_data['ID'] = $lesson_id;

			if ( ! tutor_utils()->can_user_manage( 'lesson', $lesson_id ) ) {
				$this->json_response(
					tutor_utils()->error_message(),
					null,
					HttpHelper::STATUS_FORBIDDEN
				);
			}

			do_action( 'tutor/lesson_update/before', $lesson_id );
			wp_update_post( $lesson_data );
			do_action( 'tutor/lesson_update/after', $lesson_id );
		}

		if ( $is_update ) {
			$this->json_response(
				__( 'Lesson updated successfully', 'tutor' ),
				$lesson_id
			);
		} else {
			$this->json_response(
				__( 'Lesson created successfully', 'tutor' ),
				$lesson_id,
				HttpHelper::STATUS_CREATED
			);
		}
	}

	/**
	 * Delete Lesson from course builder by ID
	 *
	 * @since 1.0.0
	 * @since 3.0.0 refactor and update response.
	 *
	 * @return void
	 */
	public function ajax_delete_lesson() {
		tutor_utils()->check_nonce();

		$lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );

		if ( ! tutor_utils()->can_user_manage( 'lesson', $lesson_id ) ) {
			$this->json_response(
				tutor_utils()->error_message(),
				null,
				HttpHelper::STATUS_FORBIDDEN
			);
		}

		$content   = __( 'Lesson', 'tutor' );
		$post_type = get_post_type( $lesson_id );
		if ( tutor()->assignment_post_type === $post_type ) {
			$content = __( 'Assignment', 'tutor' );
		}

		do_action( 'tutor_before_delete_course_content', 0, $lesson_id );

		wp_delete_post( $lesson_id, true );
		/* translators: %s refers to the name of the content being deleted */
		$this->json_response( sprintf( __( '%s deleted successfully', 'tutor' ), $content ) );
	}


	/**
	 * Changed the URI based
	 *
	 * @since 1.0.0
	 *
	 * @param string  $uri URI.
	 * @param integer $lesson_id lesson ID.
	 *
	 * @return string
	 */
	public function change_lesson_permalink( $uri, $lesson_id ) {
		$post = get_post( $lesson_id );

		if ( $post && $post->post_type === $this->lesson_post_type ) {
			$uri_base = trailingslashit( site_url() );

			$sample_course = 'sample-course';
			$is_course     = tutor_utils()->get_course_id_by( 'lesson', get_the_ID() );
			if ( $is_course ) {
				$course = get_post( $is_course );
				if ( $course ) {
					$sample_course = $course->post_name;
				}
			}

			$new_course_base = $uri_base . "course/{$sample_course}/lesson/%pagename%/";
			$uri[0]          = $new_course_base;
		}

		return $uri;
	}

	/**
	 * Mark lesson completed
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function mark_lesson_complete() {
		if ( 'tutor_complete_lesson' !== Input::post( 'tutor_action' ) ) {
			return;
		}
		// Checking nonce.
		tutor_utils()->checking_nonce();

		$user_id = get_current_user_id();

		// TODO: need to show view if not signed_in.
		if ( ! $user_id ) {
			die( esc_html__( 'Please Sign-In', 'tutor' ) );
		}

		$lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );

		if ( ! $lesson_id ) {
			return;
		}

		$validated = apply_filters( 'tutor_validate_lesson_complete', true, $user_id, $lesson_id );
		if ( ! $validated ) {
			return;
		}

		do_action( 'tutor_lesson_completed_before', $lesson_id );
		/**
		 * Marking lesson at user meta, meta format, _tutor_completed_lesson_id_{id} and value = tutor_time();
		 */
		LessonModel::mark_lesson_complete( $lesson_id );

		do_action( 'tutor_lesson_completed_email_after', $lesson_id, $user_id );
		do_action( 'tutor_lesson_completed_after', $lesson_id, $user_id );
	}

	/**
	 * Render the lesson content
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function tutor_render_lesson_content() {
		tutor_utils()->checking_nonce();

		$lesson_id = Input::post( 'lesson_id', 0, Input::TYPE_INT );

		$ancestors = get_post_ancestors( $lesson_id );
		$course_id = ! empty( $ancestors ) ? array_pop( $ancestors ) : $lesson_id;

		// Course must be public or current user must be enrolled to access this lesson.
		if ( get_post_meta( $course_id, '_tutor_is_public_course', true ) !== 'yes' && ! tutor_utils()->is_enrolled( $course_id ) ) {

			$is_admin = tutor_utils()->has_user_role( 'administrator' );
			$allowed  = $is_admin ? true : tutor_utils()->is_instructor_of_this_course( get_current_user_id(), $course_id );

			if ( ! $allowed ) {
				http_response_code( 400 );
				exit;
			}
		}

		ob_start();
		global $post;

		$post = get_post( $lesson_id ); //phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
		setup_postdata( $post );
		tutor_lesson_content();
		wp_reset_postdata();

		$html = ob_get_clean();

		wp_send_json_success( array( 'html' => $html ) );
	}

	/**
	 * Load next course item automatically
	 *
	 * @since 1.4.9
	 *
	 * @return void
	 */
	public function autoload_next_course_content() {
		tutor_utils()->checking_nonce();

		$post_id    = Input::post( 'post_id', 0, Input::TYPE_INT );
		$content_id = tutor_utils()->get_post_id( $post_id );
		$contents   = tutor_utils()->get_course_prev_next_contents_by_id( $content_id );

		$autoload_course_content = (bool) get_tutor_option( 'autoload_next_course_content' );
		$next_url                = false;
		if ( $autoload_course_content ) {
			$next_url = get_the_permalink( $contents->next_id );
		}
		wp_send_json_success( array( 'next_url' => $next_url ) );
	}

	/**
	 * Load next course item after click complete button
	 *
	 * @since 1.5.3
	 *
	 * @param integer $content_id content ID.
	 * @return void
	 */
	public function tutor_lesson_completed_after( $content_id ) {
		$contents                = tutor_utils()->get_course_prev_next_contents_by_id( $content_id );
		$autoload_course_content = (bool) get_tutor_option( 'autoload_next_course_content' );
		if ( $autoload_course_content ) {
			wp_safe_redirect( get_the_permalink( $contents->next_id ) );
		} else {
			wp_safe_redirect( get_the_permalink( $content_id ) );
		}
		die();
	}

	/**
	 * Replay lesson comment
	 *
	 * @since 1.0.0
	 *
	 * @return void|null
	 */
	public function reply_lesson_comment() {
		tutor_utils()->checking_nonce();
		$comment = Input::post( 'comment', '', Input::TYPE_KSES_POST );
		if ( 0 === strlen( $comment ) ) {
			wp_send_json_error();
			return;
		}

		$comment_data = array(
			'comment_content' => $comment,
			'comment_post_ID' => Input::post( 'comment_post_ID', 0, Input::TYPE_INT ),
			'comment_parent'  => Input::post( 'comment_parent', 0, Input::TYPE_INT ),
		);
		$comment_id   = self::create_comment( $comment_data );
		if ( false === $comment_id ) {
			wp_send_json_error();
			return;
		}
		$reply = get_comment( $comment_id );
		do_action( 'tutor_reply_lesson_comment_thread', $comment_id, $comment_data );

		ob_start();
		?>
		<div class="tutor-comments-list tutor-child-comment tutor-mt-32" id="lesson-comment-<?php echo esc_attr( $reply->comment_ID ); ?>">
			<div class="comment-avatar">
				<img src="<?php echo esc_url( get_avatar_url( $reply->user_id ) ); ?>" alt="">
			</div>
			<div class="tutor-single-comment">
				<div class="tutor-actual-comment tutor-mb-12">
					<div class="tutor-comment-author">
						<span class="tutor-fs-6 tutor-fw-bold">
							<?php echo esc_html( $reply->comment_author ); ?>
						</span>
						<span class="tutor-fs-7 tutor-ml-0 tutor-ml-sm-10">
							<?php echo esc_html( human_time_diff( strtotime( $reply->comment_date ), tutor_time() ) . __( ' ago', 'tutor' ) ); ?>
						</span>
					</div>
					<div class="tutor-comment-text tutor-fs-6 tutor-mt-4">
						<?php echo esc_html( $reply->comment_content ); ?>
					</div>
				</div>
			</div>
		</div>
		<?php
		$html = ob_get_clean();
		wp_send_json_success( array( 'html' => $html ) );
	}

	/**
	 * Get comments
	 *
	 * @since 2.0.6
	 * @see Checkout arguments details: https://developer.wordpress.org/reference/classes/wp_comment_query/__construct/
	 *
	 * @param array $args arguments.
	 * @return mixed  based on arguments
	 */
	public static function get_comments( array $args ) {
		$args['type'] = 'comment';
		$comments     = get_comments( $args );
		return $comments;
	}

	/**
	 * Create comment
	 *
	 * @since 1.0.0
	 *
	 * @param array $request request.
	 * @return mixed comment id on success, false on failure
	 */
	public static function create_comment( array $request ) {
		$current_user = wp_get_current_user();
		$default_data = array(
			'comment_content'      => '',
			'comment_post_ID'      => '',
			'comment_parent'       => '',
			'user_id'              => $current_user->ID,
			'comment_author'       => $current_user->user_login,
			'comment_author_email' => $current_user->user_email,
			'comment_author_url'   => $current_user->user_url,
			'comment_agent'        => 'Tutor',
		);
		$comment_data = wp_parse_args( $request, $default_data );
		return wp_insert_comment( $comment_data );
	}

	/**
	 * Check if lesson has content
	 *
	 * @since 3.9.0
	 *
	 * @param int $lesson_id Lesson ID.
	 *
	 * @return bool True if lesson has content, false otherwise.
	 */
	public static function has_lesson_content( $lesson_id ) {
		/**
		 * If lesson has no content, lesson tab will be hidden.
		 * To enable elementor and SCORM, only admin can see lesson tab.
		 *
		 * @since 2.2.2
		 */
		return apply_filters(
			'tutor_has_lesson_content',
			User::is_admin() || ! in_array( trim( get_the_content() ), array( null, '', '&nbsp;' ), true ),
			$lesson_id
		);
	}

	/**
	 * Check if lesson has attachments
	 *
	 * @since 3.9.0
	 *
	 * @param int $lesson_id Lesson ID.
	 *
	 * @return bool True if lesson has attachments, false otherwise.
	 */
	public static function has_lesson_attachment( $lesson_id ) {
		return count( tutor_utils()->get_attachments( $lesson_id ) ) > 0;
	}

	/**
	 * Check if comments are enabled for lessons
	 *
	 * @since 3.9.0
	 *
	 * @return bool True if comments are enabled, false otherwise.
	 */
	public static function is_comment_enabled() {
		return tutor_utils()->get_option( 'enable_comment_for_lesson' ) && comments_open() && is_user_logged_in();
	}

	/**
	 * Check if lesson has comments
	 *
	 * @since 3.9.0
	 *
	 * @param int $lesson_id Lesson ID.
	 *
	 * @return int Number of comments for the lesson.
	 */
	public static function has_lesson_comment( $lesson_id ) {
		return (int) get_comments_number( $lesson_id );
	}

	/**
	 * Get navigation items for lesson single page
	 *
	 * @since 3.9.0
	 *
	 * @param int $lesson_id Lesson ID.
	 *
	 * @return array navigation items array
	 */
	public static function get_nav_items( $lesson_id ) {
		$nav_items = array();

		if ( self::has_lesson_content( $lesson_id ) ) {
			$nav_items['overview'] = array(
				'label' => __( 'Overview', 'tutor' ),
				'value' => 'overview',
				'icon'  => 'document-text',
			);
		}

		if ( self::has_lesson_attachment( $lesson_id ) ) {
			$nav_items['files'] = array(
				'label' => __( 'Exercise Files', 'tutor' ),
				'value' => 'files',
				'icon'  => 'paperclip',
			);
		}

		if ( self::is_comment_enabled() ) {
			$nav_items['comments'] = array(
				'label' => __( 'Comments', 'tutor' ),
				'value' => 'comments',
				'icon'  => 'comment',
			);
		}

		$nav_items = apply_filters( 'tutor_lesson_single_nav_items', $nav_items );
		$nav_items = array_values( $nav_items );

		return $nav_items;
	}

	/**
	 * Get navigation contents for lesson single page
	 *
	 * @since 3.9.0
	 *
	 * @param int $lesson_id Lesson ID.
	 *
	 * @return array navigation contents array
	 */
	public static function get_nav_contents( $lesson_id ) {
		$nav_contents = array();

		if ( self::has_lesson_content( $lesson_id ) ) {
			$nav_contents['overview'] = array(
				'label'         => __( 'Overview', 'tutor' ),
				'value'         => 'overview',
				'template_path' => 'single.lesson.parts.overview',
			);
		}

		if ( self::has_lesson_attachment( $lesson_id ) ) {
			$nav_contents['files'] = array(
				'label'         => __( 'Files', 'tutor' ),
				'value'         => 'files',
				'template_path' => 'single.lesson.parts.files',
			);
		}

		if ( self::is_comment_enabled() ) {
			$nav_contents['comments'] = array(
				'label'         => __( 'Comments', 'tutor' ),
				'value'         => 'comments',
				'template_path' => 'single.lesson.parts.comments',
			);
		}

		$nav_contents = apply_filters( 'tutor_lesson_single_nav_contents', $nav_contents );

		return $nav_contents;
	}
}
