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

namespace TUTOR;

defined( 'ABSPATH' ) || exit;

use TUTOR\Students_List;
use TUTOR\Backend_Page_Trait;
use Tutor\Cache\TutorCache;
use Tutor\Helpers\QueryHelper;

/**
 * Instructors_List class
 *
 * @since 1.0.0
 */
class Instructors_List {

	const INSTRUCTOR_LIST_PAGE       = 'tutor-instructors';
	const INSTRUCTOR_LIST_CACHE_KEY  = 'tutor-instructors-list';
	const INSTRUCTOR_COUNT_CACHE_KEY = 'tutor-instructors-count';

	const STATUS_APPROVED = 'approved';
	const STATUS_PENDING  = 'pending';
	const STATUS_BLOCKED  = 'blocked';

	/**
	 * Trait for utilities
	 *
	 * @var $page_title
	 */

	use Backend_Page_Trait;

	/**
	 * Bulk Action
	 *
	 * @var $bulk_action
	 */
	public $bulk_action = true;

	/**
	 * Constructor
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function __construct() {
		/**
		 * Handle bulk action
		 *
		 * @since 2.0.0
		 */
		add_action( 'wp_ajax_tutor_instructor_bulk_action', array( $this, 'instructor_bulk_action' ) );
	}

	/**
	 * Page title fallback
	 *
	 * @since 3.5.0
	 *
	 * @param string $name Property name.
	 *
	 * @return string
	 */
	public function __get( $name ) {
		if ( 'page_title' === $name ) {
			return esc_html__( 'Instructor', 'tutor' );
		}
	}

	/**
	 * Available tabs that will visible on the right side of page navbar
	 *
	 * @since 2.0.0
	 *
	 * @param string $search instructor search | optional.
	 * @param string $course_id course id that belong to instructor | optional.
	 * @param string $date user registered date | optional.
	 *
	 * @return array
	 */
	public function tabs_key_value( $search = '', $course_id = '', $date = '' ): array {
		$url     = apply_filters( 'tutor_data_tab_base_url', get_pagenum_link() );
		$approve = self::count_total_instructors( array( 'approved' ), $search, $course_id, $date, 'approved' );
		$pending = self::count_total_instructors( array( 'pending' ), $search, $course_id, $date, 'pending' );
		$blocked = self::count_total_instructors( array( 'blocked' ), $search, $course_id, $date, 'blocked' );

		$tabs = array(
			array(
				'key'   => '',
				'title' => __( 'All', 'tutor' ),
				'value' => $approve + $pending + $blocked,
				'url'   => $url . '&data=all',
			),
			array(
				'key'   => 'approved',
				'title' => __( 'Approve', 'tutor' ),
				'value' => $approve,
				'url'   => $url . '&data=approved',
			),
			array(
				'key'   => 'pending',
				'title' => __( 'Pending', 'tutor' ),
				'value' => $pending,
				'url'   => $url . '&data=pending',
			),
			array(
				'key'   => 'blocked',
				'title' => __( 'Block', 'tutor' ),
				'value' => $blocked,
				'url'   => $url . '&data=blocked',
			),
		);
		return $tabs;
	}

	/**
	 * Prepare bulk actions that will show on dropdown options
	 *
	 * @since 2.0.0
	 *
	 * @return array
	 */
	public function prepare_bulk_actions(): array {
		$actions = array(
			$this->bulk_action_default(),
			$this->bulk_action_approved(),
			$this->bulk_action_pending(),
			$this->bulk_action_blocked(),
		);
		return $actions;
	}

	/**
	 * Handle bulk action for instructor delete
	 *
	 * @since 2.0.0
	 * @return string JSON response.
	 */
	public function instructor_bulk_action() {
		tutor_utils()->checking_nonce();

		// Check if user is privileged.
		if ( ! current_user_can( 'administrator' ) ) {
			wp_send_json_error( tutor_utils()->error_message() );
		}

		$action   = Input::post( 'bulk-action', '' );
		$bulk_ids = Input::post( 'bulk-ids', '' );

		Input::has( 'bulkIds' ) ? $bulk_ids = Input::post( 'bulkIds' ) : 0;

		if ( '' === $action || '' === $bulk_ids ) {
			return wp_send_json_error();
		}
		if ( 'delete' === $action ) {
			// Delete user from student_list class.
			do_action( 'tutor_before_instructor_delete', $bulk_ids );
			$response = Students_List::delete_students( $bulk_ids );
			do_action( 'tutor_after_instructor_delete', $bulk_ids );
		} else {
			do_action( 'tutor_before_instructor_update', $bulk_ids );
			$response = self::update_instructors( $action, $bulk_ids );
			do_action( 'tutor_after_instructor_delete', $bulk_ids );
		}

		$message = 'Instructor status updated';

		return true === $response ? wp_send_json_success( array( 'status' => $message ) ) : wp_send_json_error();
	}

	/**
	 * Execute bulk action for enrollment list ex: complete | cancel
	 *
	 * @since 2.0.0
	 *
	 * @param string $status hold status for updating.
	 * @param string $user_ids comma seperated user ids.
	 *
	 * @return bool
	 */
	public static function update_instructors( $status, $user_ids ): bool {
		global $wpdb;
		$status           = sanitize_text_field( $status );
		$instructor_table = $wpdb->usermeta;

		$ids       = array_map( 'intval', explode( ',', $user_ids ) );
		$in_clause = QueryHelper::prepare_in_clause( $ids );

		//phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$update = $wpdb->query(
			$wpdb->prepare(
				"UPDATE {$instructor_table} SET meta_value = %s 
				WHERE user_id IN ($in_clause) 
				AND meta_key = %s",
				$status,
				'_tutor_instructor_status'
			)
		);
		//phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared

		// Remove role.
		if ( 'pending' === $status || 'blocked' === $status ) {
			$arr = explode( ',', $user_ids );
			foreach ( $arr as $instructor_id ) {
				$instructor_id = (int) sanitize_text_field( $instructor_id );
				if ( 'pending' === $status ) {
					self::remove_instructor_role( $instructor_id, $status );
				} else {
					self::instructor_blockage( $instructor_id );
				}
			}
		}
		if ( 'reject' === $status ) {
			$arr = explode( ',', $user_ids );
			foreach ( $arr as $instructor_id ) {
				$instructor_id = (int) sanitize_text_field( $instructor_id );
				self::instructor_rejection( $instructor_id );
			}
		}

		if ( 'approved' === $status ) {
			$arr = explode( ',', $user_ids );
			foreach ( $arr as $instructor_id ) {
				$instructor_id = (int) sanitize_text_field( $instructor_id );
				self::add_instructor_role( $instructor_id, $status );
			}
		}
		return false === $update ? false : true;
	}

	/**
	 * Get total course.
	 *
	 * @since 1.0.0
	 *
	 * @param object $item item.
	 * @return void
	 */
	public function column_total_course( $item ) {
		global $wpdb;
		$course_post_type = tutor()->course_post_type;

		$total_course = (int) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT count(ID) from {$wpdb->posts}
			WHERE post_author=%d AND post_type=%s ",
				$item->ID,
				$course_post_type
			)
		);

		echo esc_html( $total_course );
	}

	/**
	 * Initialize instructor_role to a user
	 *
	 * @since 1.0.0
	 *
	 * @param integer $instructor_id | user id that need to add role.
	 * @param string  $status | status that will added with role (approved).
	 *
	 * @return void
	 */
	protected static function add_instructor_role( int $instructor_id, string $status ) {
		$instructor_id = sanitize_text_field( $instructor_id );
		$status        = sanitize_text_field( $status );

		do_action( 'tutor_before_approved_instructor', $instructor_id );

		update_user_meta( $instructor_id, '_tutor_instructor_status', $status );
		update_user_meta( $instructor_id, '_tutor_instructor_approved', tutor_time() );
		update_user_meta( $instructor_id, User::INSTRUCTOR_APPROVAL_NOTICE_META, true );

		$instructor = new \WP_User( $instructor_id );
		$instructor->add_role( tutor()->instructor_role );

		// TODO: send E-Mail to this user about instructor approval, should via hook.
		do_action( 'tutor_after_approved_instructor', $instructor_id );
	}

	/**
	 * Initialize instructor_role to a user
	 *
	 * @since 1.0.0
	 *
	 * @param int    $instructor_id | user id that need to add role.
	 * @param string $status | status that will added with role (approved).
	 *
	 * @return void
	 */
	protected static function remove_instructor_role( int $instructor_id, string $status ) {
		$instructor_id = sanitize_text_field( $instructor_id );
		$status        = sanitize_text_field( $status );
		update_user_meta( $instructor_id, '_tutor_instructor_status', $status );
		// Set view as student for blocked and pending instructor.
		update_user_meta( $instructor_id, User::VIEW_MODE_USER_META, User::VIEW_AS_STUDENT );
		$instructor = new \WP_User( $instructor_id );
		$instructor->remove_role( tutor()->instructor_role );
	}
	/**
	 * Instructor blocking function
	 *
	 * @since 2.5.0
	 *
	 * @param int $instructor_id | user id that need to add role.
	 * @return void
	 */
	protected static function instructor_blockage( int $instructor_id ) {
		$instructor_id = sanitize_text_field( $instructor_id );
		do_action( 'tutor_before_blocked_instructor', $instructor_id );
		self::remove_instructor_role( $instructor_id, 'blocked' );
		do_action( 'tutor_after_blocked_instructor', $instructor_id );
	}
	/**
	 * Instructor rejection function
	 *
	 * @since 2.5.0
	 *
	 * @param int $instructor_id | user id that need to add role.
	 * @return void
	 */
	protected static function instructor_rejection( int $instructor_id ) {
		$instructor_id = sanitize_text_field( $instructor_id );
		do_action( 'tutor_before_rejected_instructor', $instructor_id );

		/**
		 * Removed tutor_instructor role and set `try_again` status
		 * for apply again as instructor with show message to applier in frontend.
		 */
		self::remove_instructor_role( $instructor_id, 'try_again' );
		delete_user_meta( $instructor_id, '_is_tutor_instructor' );

		do_action( 'tutor_after_rejected_instructor', $instructor_id );
	}

	/**
	 * Get instructors list
	 *
	 * @since 2.1.7
	 *
	 * @param array  $status instructor status: approved, pending, block.
	 * @param int    $offset offset for pagination.
	 * @param int    $per_page per page limit.
	 * @param string $search search keyword.
	 * @param string $course_id course id.
	 * @param string $date instructor registration date.
	 * @param string $order sorting order.
	 *
	 * @return wpdb::results
	 */
	public static function get_instructors( array $status, $offset, $per_page, $search = '', $course_id = '', $date = '', $order = 'DESC' ) {
		global $wpdb;

		$wild = '%';

		$search_clause = $wild . $wpdb->esc_like( $search ) . $wild;
		$course_clause = '';
		if ( '' !== $course_id ) {
			$course_id     = (int) $course_id;
			$course_clause = "AND umeta.meta_value = {$course_id}";
		}

		$order_clause = '';
		if ( '' !== $order ) {
			$is_valid_sql = sanitize_sql_orderby( $order );
			if ( $is_valid_sql ) {
				$order_clause = "ORDER BY user.ID {$order}";
			}
		}

		$date_clause = '' !== $date ? $wpdb->prepare( 'AND DATE(user.user_registered) = %s', $date ) : '';
		$in_clause   = QueryHelper::prepare_in_clause( $status );

		$query  = "SELECT
					DISTINCT user.*,
					ins_status.meta_value AS status,
					(
						SELECT
							COUNT(*)
							FROM {$wpdb->posts}
							WHERE post_author = user.ID
								AND post_type = 'courses'
					) total_courses
					FROM {$wpdb->users} AS user
						
					INNER JOIN {$wpdb->usermeta} AS ins_status
						ON ( user.ID = ins_status.user_id )
						AND ins_status.meta_key = '_tutor_instructor_status'
					LEFT JOIN {$wpdb->usermeta} AS umeta
						ON umeta.user_id = user.ID
						AND umeta.meta_key = '_tutor_instructor_course_id'
					WHERE ins_status.meta_value IN ($in_clause)
						AND (user.user_email LIKE %s OR user.display_name LIKE %s)
						{$course_clause}
						{$date_clause}
					{$order_clause}
					LIMIT %d, %d;
				";
		$result = TutorCache::get( self::INSTRUCTOR_LIST_CACHE_KEY );
		if ( false === $result ) {
			TutorCache::set(
				self::INSTRUCTOR_LIST_CACHE_KEY,
				//phpcs:disable
				$result = $wpdb->get_results(
					$wpdb->prepare(
						$query,
						$search_clause,
						$search_clause,
						$offset,
						$per_page
					)
				)
				//phpcs:enable
			);
		}

		return $result;
	}

	/**
	 * Count total instructors
	 *
	 * @since 2.1.7
	 *
	 * @param array  $status instructor status: approved, pending, block.
	 * @param string $search search keyword.
	 * @param string $course_id course id.
	 * @param string $date instructor registration date.
	 * @param string $unique_cache_key unique key will be append with
	 * self::INSTRUCTOR_COUNT_CACHE_KEY so that multiple count value could be
	 * stored as unique data.
	 *
	 * @return int count value of instructors
	 */
	public static function count_total_instructors( array $status, $search = '', $course_id = '', $date = '', $unique_cache_key = '' ) {
		global $wpdb;

		$wild = '%';

		$search_clause = $wild . $wpdb->esc_like( $search ) . $wild;
		$course_clause = '';
		if ( '' !== $course_id ) {
			$course_id     = (int) $course_id;
			$course_clause = "AND umeta.meta_value = {$course_id}";
		}

		$date_clause = '' !== $date ? $wpdb->prepare( 'AND DATE(user.user_registered) = %s', $date ) : '';
		$in_clause   = QueryHelper::prepare_in_clause( $status );

		$query  = "SELECT
					COUNT(DISTINCT user.ID)
					
					FROM {$wpdb->users} AS user
						
					INNER JOIN {$wpdb->usermeta} AS ins_status
						ON ( user.ID = ins_status.user_id )
						AND ins_status.meta_key = '_tutor_instructor_status'
					LEFT JOIN {$wpdb->usermeta} AS umeta
						ON umeta.user_id = user.ID
						AND umeta.meta_key = '_tutor_instructor_course_id'
					WHERE ins_status.meta_value IN ($in_clause)
						AND (user.user_email LIKE %s OR user.display_name LIKE %s)
						{$course_clause}
						{$date_clause}
				";
		$result = TutorCache::get( self::INSTRUCTOR_COUNT_CACHE_KEY . $unique_cache_key );
		if ( false === $result ) {
			TutorCache::set(
				self::INSTRUCTOR_COUNT_CACHE_KEY,
				//phpcs:disable
				$result = $wpdb->get_var(
					$wpdb->prepare(
						$query,
						$search_clause,
						$search_clause
					)
				)
				//phpcs:enable
			);
		}
		return $result;
	}
}
