<?php
/**
 * Masteriyo Prerequisites setup.
 *
 * @package Masteriyo\Prerequisites
 *
 * @since 2.3.2
 */

namespace Masteriyo\Addons\Prerequisites;

use Masteriyo\Constants;
use Masteriyo\Addons\Prerequisites\Helper;
use Masteriyo\Enums\CourseAccessMode;

defined( 'ABSPATH' ) || exit;

/**
 * Main Masteriyo Prerequisites class.
 *
 * @class Masteriyo\Addons\Prerequisites\PrerequisitesAddon
 */

class PrerequisitesAddon {
	/**
	 * Initialize the application.
	 *
	 * @since 2.3.2
	 */
	public function init() {
		$this->init_hooks();
	}

	/**
	 * Initialize hooks.
	 *
	 * @since 2.3.2
	 */
	public function init_hooks() {
		add_filter( 'masteriyo_rest_course_schema', array( $this, 'add_prerequisites_schema' ) );
		add_action( 'masteriyo_new_course', array( $this, 'save_prerequisites_data' ), 10, 2 );
		add_action( 'masteriyo_update_course', array( $this, 'save_prerequisites_data' ), 10, 2 );
		add_filter( 'masteriyo_rest_response_course_data', array( $this, 'append_prerequisites_data_in_response' ), 10, 4 );
		add_action( 'masteriyo_single_course_sidebar_content', array( $this, 'render_prerequisites_sidebar_content' ), 15 );
		add_action( 'masteriyo_layout_1_single_course_aside_items', array( $this, 'render_prerequisites_sidebar_content' ), 10 );
		add_filter( 'masteriyo_get_template', array( $this, 'change_template_for_prerequisites' ), 10, 5 );
		add_action( 'masteriyo_after_learn_page_process', array( $this, 'redirect' ) );
		add_filter( 'masteriyo_single_course_start_text', array( $this, 'prepped_lock_sign' ), 10, 2 );
		add_filter( 'masteriyo_single_course_add_to_cart_text', array( $this, 'prepped_lock_sign' ), 10, 2 );
		add_filter( 'masteriyo_single_course_continue_text', array( $this, 'prepped_lock_sign' ), 10, 2 );
		add_filter( 'masteriyo_single_course_completed_text', array( $this, 'prepped_lock_sign' ), 10, 2 );
		add_filter( 'masteriyo_enroll_button_class', array( $this, 'disable_enroll_button' ), 10, 3 );
		add_filter( 'masteriyo_start_course_url', array( $this, 'update_start_course_url' ), 10, 3 );
		add_filter( 'masteriyo_continue_course_url', array( $this, 'update_start_course_url' ), 10, 3 );

		add_filter( 'masteriyo_course_add_to_cart_text', array( $this, 'prepped_lock_sign' ), 10, 2 );
		add_filter( 'masteriyo_course_add_to_cart_url', array( $this, 'update_add_to_cart_course_url' ), 10, 2 );

		add_action( 'masteriyo_elementor_course_prerequisites_widget', array( $this, 'render_prerequisites_sidebar_content' ), 10, 1 );
		add_filter( 'elementor_course_widgets', array( $this, 'append_custom_course_widgets' ), 10 );
	}

	/**
	 * Add course prerequisites elementor widget.
	 *
	 * @since 2.12.2
	 *
	 * @param array $widgets
	 * @return array
	 */
	public function append_custom_course_widgets( $widgets ) {
		$widgets[] = new CoursePrerequisitesMetaWidget();
		return $widgets;
	}

	/**
	 * Update start course/ buy now url.
	 *
	 * @since 2.3.2
	 *
	 * @param string $url Start course URL.
	 * @param Masteriyo\Models\Course $course Course object.
	 * @param boolean $append_first_lesson_or_quiz Whether to append first lesson or quiz or not.
	 * @return string
	 */
	public function update_start_course_url( $url, $course, $append_first_lesson_or_quiz ) {
		if ( is_null( $course ) ) {
			return $url;
		}

		if ( $this->check_course_content_access_for_current_user( $course ) ) {
			return $url;
		}

		if ( ! $this->is_enabled( $course ) ) {
			return $url;
		}

		$satisfied = Helper::prerequisites_satisfied( $course );

		if ( $satisfied ) {
			return $url;
		}

		$courses = Helper::is_prerequisite_course_drafted( $course );

		if ( empty( $courses ) ) {
			return $url;
		}

		return $course->get_permalink();
	}

	/**
	 * Update start course/ buy now url.
	 *
	 * @since 2.11.0
	 *
	 * @param string $url Start course URL.
	 * @param Masteriyo\Models\Course $course Course object.
	 * @param boolean $append_first_lesson_or_quiz Whether to append first lesson or quiz or not.
	 * @return string
	 */
	public function update_add_to_cart_course_url( $url, $course ) {
		if ( is_null( $course ) ) {
			return $url;
		}

		if ( $this->check_course_content_access_for_current_user( $course ) ) {
			return $url;
		}

		if ( ! $this->is_enabled( $course ) ) {
			return $url;
		}

		$satisfied = Helper::prerequisites_satisfied( $course );

		if ( $satisfied ) {
			return $url;
		}

		$courses = Helper::is_prerequisite_course_drafted( $course );

		if ( empty( $courses ) ) {
			return $url;
		}

		if ( CourseAccessMode::NEED_REGISTRATION === $course->get_access_mode() ) {
			return $url;
		}

		return $course->get_permalink();
	}

	/**
	 * Disable enroll button.
	 *
	 * @since 2.3.2
	 *
	 * @param string[] $class An array of class names.
	 * @param \Masteriyo\Models\Course $course Course object.
	 * @param \Masteriyo\Models\CourseProgress $progress Course progress object.
	 *
	 * @return string[]
	 */
	public function disable_enroll_button( $class, $course, $progress ) {
		if ( is_null( $course ) ) {
			return $class;
		}

		if ( $this->check_course_content_access_for_current_user( $course ) ) {
			return $class;
		}

		if ( ! $this->is_enabled( $course ) ) {
			return $class;
		}

		$satisfied = Helper::prerequisites_satisfied( $course );

		if ( $satisfied ) {
			return $class;
		}

		$courses = Helper::is_prerequisite_course_drafted( $course );

		if ( empty( $courses ) ) {
			return $class;
		}

		if ( ! is_user_logged_in() && CourseAccessMode::NEED_REGISTRATION === $course->get_access_mode() ) {
			return $class;
		}

		$class   = array_filter(
			$class,
			function( $c ) {
				return 'masteriyo-btn-primary' !== $c && 'masteriyo-btn' !== $c;
			}
		);
		$class[] = 'masteriyo-btn-disabled';
		$class[] = 'masteriyo-prerequisites-enroll-button';

		return $class;
	}

	/**
	 * Prepend lock sign to enroll button if prerequisites are not met.
	 *
	 * @since 2.3.2
	 *
	 * @return string
	 */
	public function prepped_lock_sign( $text, $course ) {
		if ( is_null( $course ) ) {
			return $text;
		}

		if ( $this->check_course_content_access_for_current_user( $course ) ) {
			return $text;
		}

		if ( ! $this->is_enabled( $course ) ) {
			return $text;
		}

		$satisfied = Helper::prerequisites_satisfied( $course );

		if ( $satisfied ) {
			return $text;
		}

		$courses = Helper::is_prerequisite_course_drafted( $course );

		if ( empty( $courses ) ) {
			return $text;
		}

		if ( ! is_user_logged_in() && CourseAccessMode::NEED_REGISTRATION === $course->get_access_mode() ) {
			return $text;
		}

		return '<span class="dashicons dashicons-lock" style="margin-right: 5px; margin-top: 3px"></span>' . $text;
	}

	/**
	 * Redirect to single course page when the learn page of course whose prerequisites are not met.
	 *
	 * @param \Masteriyo\Models\Course $course Course object.
	 *
	 * @since 2.3.2
	 */
	public function redirect( $course ) {
		if ( $this->check_course_content_access_for_current_user( $course ) ) {
			return;
		}

		$satisfied = Helper::prerequisites_satisfied( $course );

		if ( ! $this->is_enabled( $course ) ) {
			return;
		}

		if ( masteriyo_is_learn_page() && $satisfied ) {
			return;
		}

		$courses = Helper::is_prerequisite_course_drafted( $course );

		if ( empty( $courses ) ) {
			return;
		}

		wp_safe_redirect( $course->get_permalink() );
		exit();
	}

	/**
	 * Change template for courses template in single course page.
	 *
	 * @since 2.3.2
	 *
	 * @param string $template Template path.
	 * @param string $template_name Template name.
	 * @param array $args Template arguments.
	 * @param string $template_path Template path from function parameter.
	 * @param string $default_path Default templates directory path.
	 *
	 * @return string
	 */
	public function change_template_for_prerequisites( $template, $template_name, $args, $template_path, $default_path ) {
		if ( 'prerequisites/courses.php' !== $template_name ) {
			return $template;
		}

		if ( file_exists( $template ) ) {
			return $template;
		}

		return trailingslashit( Constants::get( 'MASTERIYO_PREREQUISITES_TEMPLATES' ) ) . 'courses.php';
	}

	/**
	 * Render prerequisites sidebar content.
	 *
	 * @since 2.3.2
	 *
	 * @param \Masteriyo\Models\Course $course Course object.
	 * @return void
	 */
	public function render_prerequisites_sidebar_content( $course ) {
		$prerequisites = Helper::get_prerequisites_courses( $course );

		foreach ( $prerequisites as $key => $prerequisite ) {
			if ( 'draft' === $prerequisite['status'] ) {
				unset( $prerequisites[ $key ] );
			}
		}

		if ( ! $this->is_enabled( $course ) ) {
			return;
		}

		if ( $prerequisites ) {
			masteriyo_get_template(
				'prerequisites/courses.php',
				array(
					'course'        => $course,
					'prerequisites' => $prerequisites,
				)
			);
		}
	}

	/**
	 * Add prerequisites fields to course schema.
	 *
	 * @since 2.3.2
	 *
	 * @param array $schema
	 * @return array
	 */
	public function add_prerequisites_schema( $schema ) {
		$schema = masteriyo_parse_args(
			$schema,
			array(
				'prerequisites' => array(
					'description' => __( 'Prerequisites setting', 'learning-management-system' ),
					'type'        => 'object',
					'context'     => array( 'view', 'edit' ),
					'items'       => array(
						'type'       => 'object',
						'properties' => array(
							'enable'  => array(
								'id' => array(
									'description' => __( 'Enable prerequisites', 'learning-management-system' ),
									'type'        => 'boolean',
									'context'     => array( 'view', 'edit' ),
								),
							),
							'courses' => array(
								'description' => __( 'List of courses.', 'learning-management-system' ),
								'type'        => 'array',
								'context'     => array( 'view', 'edit' ),
								'items'       => array(
									'type'       => 'object',
									'properties' => array(
										'id'   => array(
											'description' => __( 'Course ID', 'learning-management-system' ),
											'type'        => 'integer',
											'context'     => array( 'view', 'edit' ),
										),
										'name' => array(
											'description' => __( 'Course name', 'learning-management-system' ),
											'type'        => 'string',
											'context'     => array( 'view', 'edit' ),
											'readonly'    => true,
										),
										'slug' => array(
											'description' => __( 'Course slug', 'learning-management-system' ),
											'type'        => 'string',
											'context'     => array( 'view', 'edit' ),
											'readonly'    => true,
										),
									),
								),
							),
						),
					),
				),
			)
		);

		return $schema;
	}

	/**
	 * Save Prerequisites data.
	 *
	 * @since 2.3.2
	 *
	 * @param integer $id The course ID.
	 * @param \Masteriyo\Models\Course $object The course object.
	 */
	public function save_prerequisites_data( $course_id, $course ) {
		$request = masteriyo_current_http_request();

		if ( null === $request ) {
			return;
		}

		if ( ! isset( $request['prerequisites'] ) ) {
			return;
		}

		if ( isset( $request['prerequisites']['courses'] ) ) {
			$course_ids = wp_list_pluck( $request['prerequisites']['courses'], 'id' );
			$course_ids = array_filter(
				array_map(
					function( $course_id ) {
						return masteriyo_get_course( $course_id ) ? $course_id : null;
					},
					$course_ids
				)
			);

			$set_course_ids = array();

			foreach ( $course_ids as $new_course_id ) {
				$course_data = masteriyo_get_course( $new_course_id );

				if ( 'draft' === $course_data->get_status() ) {
					continue;
				}

				$prerequisites = Helper::get_prerequisites_courses( $course_data );

				if ( ! $prerequisites ) {
					$set_course_ids[] = $new_course_id;
					continue;
				}

				foreach ( $prerequisites as $prerequisite ) {
					$prerequisite_ids[] = $prerequisite['id'];
				}

				if ( in_array( $course->get_id(), $prerequisite_ids, true ) ) {
					continue;
				}

				$set_course_ids[] = $new_course_id;

			}

			$course->update_meta_data( '_prerequisites_courses', $set_course_ids );
		}

		if ( isset( $request['prerequisites']['enable'] ) ) {
			$course->update_meta_data( '_prerequisites_enable', masteriyo_string_to_bool( $request['prerequisites']['enable'] ) );
			$course->save_meta_data();
		}
	}

	/**
	 * Append Prerequisites to course response.
	 *
	 * @since 2.3.2
	 *
	 * @param array $data Course data.
	 * @param \Masteriyo\Models\Course $course Course object.
	 * @param string $context What the value is for. Valid values are view and edit.
	 * @param \Masteriyo\RestApi\Controllers\Version1\CoursesController $controller REST courses controller object.
	 */
	public function append_prerequisites_data_in_response( $data, $course, $context, $controller ) {
		$course_ids = (array) maybe_unserialize( $course->get_meta( '_prerequisites_courses' ) );

		$courses = array_filter( array_map( array( $this, 'get_course_data' ), $course_ids ) );

		foreach ( $courses as $key => $new_course ) {
			if ( 'draft' === $new_course['status'] ) {
				unset( $courses[ $key ] );
			}
		}

		$data['prerequisites'] = array(
			'enable'  => $this->is_enabled( $course ),
			'courses' => $courses,
		);

		return $data;
	}

	/**
	 * Return prerequisites course data.
	 *
	 * @since 2.3.2
	 *
	 * @param int $course_id Course ID.
	 *
	 * @return array|null
	 */
	protected function get_course_data( $course_id ) {
		$course = masteriyo_get_course( $course_id );

		if ( $course ) {
			return array(
				'id'     => $course->get_id(),
				'name'   => $course->get_name(),
				'slug'   => $course->get_slug(),
				'status' => $course->get_status(),
			);
		}

		return null;
	}

	/**
	 * Return if course prerequisites is enabled.
	 *
	 * @since 2.3.2
	 *
	 * @param \Masteriyo\Models\Course $course Course object.
	 * @return boolean
	 */
	public function is_enabled( $course ) {
		return masteriyo_string_to_bool( $course->get_meta( '_prerequisites_enable' ) );
	}

	/**
	 * Return true if current user can access course based on the course-content-access settings. Otherwise returns false.
	 *
	 * @since 2.7.0
	 *
	 * @param \Masteriyo\Models\Course $course Course object.
	 *
	 * @return boolean
	 */
	public function check_course_content_access_for_current_user( $course ) {
		if (
			function_exists( 'masteriyo_check_course_content_access_for_current_user' ) &&
			masteriyo_check_course_content_access_for_current_user( $course )
		) {
			return true;
		}
		return false;
	}
}
