<?php
/**
 * Masteriyo Pro class.
 *
 * @since 2.0.0
 * @since 1.6.11
 * @package Masteriyo\Pro
 */

namespace Masteriyo\Pro;

defined( 'ABSPATH' ) || exit;


use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use Masteriyo\AjaxHandlers\CourseFilterAndSortingAjaxHandler;
use Masteriyo\Enums\CourseFlow;
use Masteriyo\Enums\VideoSource;
use Masteriyo\Pro\Enums\SubscriptionStatus;
use Masteriyo\Enums\CourseChildrenPostType;
use Masteriyo\Query\CourseProgressItemQuery;
use Masteriyo\PostType\Subscription;
use Masteriyo\Pro\Controllers\LicenseControllers;

/**
 * Masteriyo pro class.
 *
 * @since 1.6.11
*/
class Pro {

	/**
	 *
	 * Instance of addons class.
	 *
	 * @since 2.2.0
	 *
	 * @var \Masteriyo\Pro\Addons
	 * @since 1.6.11
	 *
	 * @var Masteriyo\Addons
	 *
	 */
	public $addons;

	/**
	 *
	 * Instance of license class.
	 *
	 * @since 2.5.0
	 *
	 * @var \Masteriyo\Pro\License
	 *
	 */
	public $license;

	/**
	 * Constructor.
	 *
	 * @since 2.2.0
	 * @since 2.5.0 Added $license parameter.
	 *
	 * @param \Masteriyo\Pro\Addons $addons
	 * @param \Masteriyo\Pro\License $license
	 */
	public function __construct( Addons $addons, License $license ) {
		$this->addons  = $addons;
		$this->license = $license;
	}

	/**
	 * Initialize.
	 *
	 * @since 2.0.0
	 * @since 1.6.11
	 */
	public function init() {
		$this->init_hooks();
	}

	/**
	 * Initialize hooks.
	 *
	 * @since 2.0.0
	 * @since 1.6.11
	 */
	public function init_hooks() {
		add_filter( 'masteriyo_localized_admin_scripts', array( $this, 'localize_addons_data' ) );
		add_filter( 'masteriyo_localized_public_scripts', array( $this, 'localize_public_scripts' ) );
		add_filter( 'masteriyo_admin_submenus', array( $this, 'register_submenus' ) );
		add_filter( 'masteriyo_pro_addon_activation_requirements', array( $this, 'validate_license_before_addon_activation' ) );
		add_filter( 'masteriyo_pro_addon_activation_requirements', array( $this, 'validate_license_plan_before_addon_activation' ), 10, 4 );
		add_filter( 'masteriyo_course_progress_item_data', array( $this, 'add_locked_status_to_course_progress_item' ), 10, 3 );
		add_filter( 'masteriyo_ajax_handlers', array( $this, 'add_ajax_handlers' ) );
		add_filter( 'masteriyo_lesson_video_sources', array( $this, 'add_external_video_source_type' ) );
		add_filter( 'masteriyo_course_featured_video_embed_url', array( $this, 'filter_course_external_featured_video_embed_url' ), 10, 2 );
		add_action( 'init', array( $this, 'register_subscription_status' ), 0 );
		add_filter( 'masteriyo_register_post_types', array( $this, 'register_subscription_post_type' ) );
	}

	/**
	 * Register subscription post type.
	 *
	 * @since 2.6.10
	 *
	 * @param \Masteriyo\PostType\PostType[] $post_types
	 * @return \Masteriyo\PostType\PostType[]
	 */
	public function register_subscription_post_type( $post_types ) {
		$post_types[] = Subscription::class;

		return $post_types;
	}

	/**
	 * Register subscription status.
	 *
	 * @since 2.6.10
	 */
	public function register_subscription_status() {
		foreach ( SubscriptionStatus::list() as $subscription_status => $values ) {
			register_post_status( $subscription_status, $values );
		}
	}

	/**
	 * Return error if the license is not activated.
	 *
	 * @since 2.5.0
	 *
	 * @param boolean|WP_Error $result
	 * @return boolean|WP_Error
	 */
	public function validate_license_before_addon_activation( $result ) {
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		if ( 'active' !== $this->license->get_license_status() ) {
			return new WP_Error(
				'masteriyo_pro_license_not_activated',
				esc_html__( 'License key is not activated.', 'learning-management-system' ),
				400
			);
		}

		return $result;
	}

	/**
	 * Return error if the license plan doesn't match with the addon plan.
	 *
	 * @since 2.5.0
	 *
	 * @param boolean|WP_Error $result
	 * @param string $slug Addon slug.
	 * @param \WP_Rest_Response $response Response object.
	 * @param WP_Rest_Request $request Request object.
	 * @param \Masteriyo\RestApi\Controllers\Version1\AddonsController $this Addons controller object.

	 * @return boolean|WP_Error
	 */
	public function validate_license_plan_before_addon_activation( $result, $slug, $request, $controller ) {
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		$addon = $this->addons->get_data( $slug );

		if ( empty( $addon ) ) {
			return $result;
		}

		$user_plan = $this->license->get_variant_name();

		if ( empty( $user_plan ) ) {
			return new WP_Error(
				'masteriyo_pro_license_plan_not_found',
				esc_html__( 'Addon cannot be activated. Please, deactivate and activate your license..', 'learning-management-system' ),
				400
			);
		}

		if ( ! $this->addons->is_allowed( $slug ) ) {
			return new WP_Error(
				'masteriyo_pro_license_plan_mismatch',
				esc_html__( 'Addon is not in your plan.', 'learning-management-system' ),
				400
			);
		}

		return $result;
	}

	/**
	 * Localize addons data.
	 *
	 * @since 2.2.0
	 * @since 1.6.11
	 *
	 * @param array $data Localized data.
	 */
	public function localize_addons_data( $data ) {
		$addons_data = array_map(
			function( $slug ) {
				return $this->addons->get_data( $slug, true );
			},
			array_keys( $this->addons->get_all_addons() )
		);

		$addons_data = array_map(
			function( $addon ) {
				$addon_plan      = masteriyo_array_get( $addon, 'plan', '' );
				$locked          = empty( $addon ) ? false : ! $this->addons->is_allowed( masteriyo_array_get( $addon, 'slug' ) );
				$addon['locked'] = $locked;

				return $addon;
			},
			$addons_data
		);

		$addons_keys = wp_list_pluck( $addons_data, 'slug' );
		$addons_data = array_combine( $addons_keys, $addons_data );

		// Move content drip addon to the end of the array.
		// TODO Remove after number of addons are introduced.
		$addons_data += array_splice( $addons_data, array_search( 'content-drip', array_keys( $addons_data ), true ), 1 );
		$addons_data  = array_values( $addons_data );

		$active_integration_addons = array_filter(
			$addons_data,
			function( $addon ) {
				return $addon['active'] && 'integration' === $addon['addon_type'];
			}
		);

		if ( isset( $data['backend'] ) ) {
			$data['backend']['data']['addons']       = $addons_data;
			$data['backend']['data']['integrations'] = masteriyo_bool_to_string( ! empty( $active_integration_addons ) );
			$data['backend']['data']['license']      = array(
				'license_key' => $this->license->get_license_key(),
				'status'      => $this->license->get_license_status(),
				'data'        => $this->license->get_activation_data(),
			);
		}

		return $data;
	}

	/**
	 * Localize public scripts
	 *
	 * @since 2.3.5
	 * @since 1.6.11
	 *
	 * @param array $data Localized data.
	 */
	public function localize_public_scripts( $data ) {
		$addons_data = array_map(
			function( $slug ) {
				return $this->addons->get_data( $slug, true );
			},
			array_keys( $this->addons->get_all_addons() )
		);

		$active_integration_addons = array_filter(
			$addons_data,
			function( $addon ) {
				return $addon['active'] && 'integration' === $addon['addon_type'];
			}
		);

		$subscription_enabled = $this->license->is_license_active();

		$data = masteriyo_parse_args(
			$data,
			array(
				'learn'   => array(
					'data' => array(
						'addons'       => $addons_data,
						'integrations' => masteriyo_bool_to_string( ! empty( $active_integration_addons ) ),
					),
				),
				'account' => array(
					'data' => array(
						'addons'               => $addons_data,
						'integrations'         => masteriyo_bool_to_string( ! empty( $active_integration_addons ) ),
						'subscription_enabled' => masteriyo_bool_to_string( $subscription_enabled ),
					),
				),
			)
		);

		return $data;
	}

	/**
	 * Register sub menus.
	 *
	 * @since 2.3.3
	 * @since 1.6.11
	 *
	 * @param array $submenus
	 * @return array
	 */
	public function register_submenus( $submenus ) {
		$submenus['license'] = array(
			'page_title' => esc_html__( 'License', 'learning-management-system' ),
			'menu_title' => esc_html__( 'License', 'learning-management-system' ),
			'position'   => 60,
		);

		$submenus['add-ons'] = array(
			'page_title' => esc_html__( 'Addons', 'learning-management-system' ),
			'menu_title' => esc_html__( 'Addons', 'learning-management-system' ),
			'position'   => 61,
		);

		if ( $this->license->is_license_active() && 'Basic' !== $this->license->get_variant_name()  ) {
			$submenus['subscriptions'] = array(
				'page_title' => __( 'Subscriptions', 'learning-management-system' ),
				'menu_title' => __( 'Subscriptions', 'learning-management-system' ),
				'capability' => 'edit_mto_subscriptions',
				'position'   => 21,
			);
		}

		return $submenus;
	}

	/**
	 * Add locked status to course progress item like (lesson and quiz) for sequential.
	 *
	 * @since 2.5.6
	 *
	 * @param array $data The course progress item data.
	 * @param \Masteriyo\Models\CourseProgressItem $course_progress_item Course progress item object.
	* @param string $context Context.
	 */
	public function add_locked_status_to_course_progress_item( $data, $course_progress_item, $context ) {
		$locked = false;
		$course = masteriyo_get_course( $course_progress_item->get_course_id() );

		if ( $course && CourseFlow::SEQUENTIAL === $course->get_flow() ) {
			$current_index = 0;
			$contents      = masteriyo_get_course_contents( $course );

			$contents = array_values(
				array_filter(
					$contents,
					function( $content ) {
						return CourseChildrenPostType::SECTION !== $content->get_post_type();
					}
				)
			);

			foreach ( $contents as $index => $content ) {
				if ( $content->get_id() === $course_progress_item->get_item_id() ) {
					$current_index = $index;
					break;
				}
			}

			if ( $current_index > 0 ) {
				$previous_content = $contents[ $current_index - 1 ];

				if ( is_user_logged_in() ) {
					$query = new CourseProgressItemQuery(
						array(
							'item_id' => $previous_content->get_id(),
							'user_id' => masteriyo_get_current_user_id(),
							'limit'   => 1,
						)
					);

					$previous_course_progress_item = current( $query->get_course_progress_items() );
				} else {
					$session = masteriyo( 'session' );

					$previous_course_progress_items = $session->get( 'course_progress_items', array() );

					if ( isset( $previous_course_progress_items[ $previous_content->get_id() ] ) ) {
						$previous_course_progress_item = masteriyo( 'course-progress-item' );
						$previous_course_progress_item->set_item_id( $previous_content->get_id() );
						$previous_course_progress_item->set_item_type( str_replace( 'mto-', '', $previous_content->get_post_type() ) );
						$previous_course_progress_item->set_completed( $previous_course_progress_items[ $previous_content->get_id() ]['completed'] );
					}
				}
				$locked = empty( $previous_course_progress_item ) || ( $previous_course_progress_item && ! $previous_course_progress_item->get_completed() );
			}
		}

		$data['locked'] = $locked;

		return $data;
	}

	/**
	 * Add AJAX handlers.
	 *
	 * @since 2.5.18
	 *
	 * @param string[] $handlers
	 *
	 * @return string[]
	 */
	public function add_ajax_handlers( $handlers ) {
		$handlers[] = CourseFilterAndSortingAjaxHandler::class;
		return $handlers;
	}

	/**
	 * Add external video source type.
	 *
	 * @since 2.5.20
	 *
	 * @param string[] $sources
	 *
	 * @return string[]
	 */
	public function add_external_video_source_type( $sources ) {
		$sources[ VideoSource::EXTERNAL ] = __( 'External URL', 'learning-management-system' );
		return $sources;
	}

	/**
	 * Filter external featured video embed URL of a course.
	 *
	 * @since 2.5.20
	 *
	 * @param string $embed_url
	 * @param \Masteriyo\Models\Course $course
	 *
	 * @return string
	 */
	public function filter_course_external_featured_video_embed_url( $embed_url, $course ) {
		if ( VideoSource::EXTERNAL === $course->get_featured_video_source() ) {
			return $course->get_featured_video_url();
		}
		return $embed_url;
	}
}
