<?php
/**
 * Masteriyo EDD Integration setup.
 *
 * @package Masteriyo\EDDIntegration
 *
 * @since 2.6.8
 */


namespace Masteriyo\Addons\EDDIntegration;

defined( 'ABSPATH' ) || exit;

use Masteriyo\Constants;
use Masteriyo\Enums\OrderStatus;
use Masteriyo\Models\UserCourse;
use Masteriyo\PostType\PostType;
use Masteriyo\Taxonomy\Taxonomy;
use Masteriyo\Query\UserCourseQuery;
use Masteriyo\Enums\CourseAccessMode;
use Masteriyo\Enums\UserCourseStatus;
use Masteriyo\Addons\EDDIntegration\Setting;

/**
 * Main Masteriyo EDD integration class.
 *
 * @since 2.6.8
 */class EDDIntegrationAddon {

	/**
	 * Instance of Setting class.
	 *
	 * @since 2.6.8
	 *
	 * @var \Masteriyo\Addons\WcIntegration\Setting
	 */
	private $setting = null;

	/**
	 * The single instance of the class.
	 *
	 * @since 2.6.8
	 *
	 * @var \Masteriyo\Addons\EDDIntegration\EDDIntegrationAddon
	 */
	private static $instance = null;

	/**
	 * Constructor.
	 *
	 * @since 2.6.8
	 *
	 * @return \Masteriyo\Addons\EDDIntegration\EDDIntegrationAddon
	 */
	public static function instance() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}
		return self::$instance;
	}


	/**
	 * Constructor.
	 *
	 * @since 2.6.8
	 */
	private function __construct() {}

	/**
	 * Prevent cloning.
	 *
	 * @since 2.6.8
	 */
	public function __clone() {}

	/**
	 * Prevent unserializing.
	 *
	 * @since 2.6.8
	 */
	public function __wakeup() {}

	/**
	 * Initialize.
	 *
	 * @since 2.6.8
	 */
	public function init() {
		$this->setting = new Setting();
		$this->setting->init();

		$this->init_hooks();
	}


	/**
	 * Init hooks.
	 *
	 * @since 2.6.8
	 */
	private function init_hooks() {
		add_filter( 'masteriyo_can_start_course', array( $this, 'update_can_start_course' ), 10, 3 );
		add_filter( 'masteriyo_ajax_handlers', array( $this, 'register_ajax_handlers' ) );
		add_filter( 'masteriyo_course_add_to_cart_url', array( $this, 'change_add_to_cart_url' ), 10, 2 );

		// Handle EDD order events.
		add_action( 'edd_order_added', array( $this, 'create_user_course' ) );
		add_action( 'edd_order_updated', array( $this, 'create_user_course' ) );
		add_action( 'edd_update_payment_status', array( $this, 'change_order_status' ), 10, 3 );

		add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ), 1 );
		add_action( 'edd_save_download', array( $this, 'save_meta_box_data' ), 1 );

		add_action( 'profile_update', array( $this, 'add_student_role_to_edd_customer' ) );
		add_action( 'user_register', array( $this, 'add_student_role_to_edd_customer' ) );

		add_action( 'admin_head', array( $this, 'print_inline_script_style' ), 99 );
	}

	/**
	 * Add inline script.
	 *
	 * @since 2.6.8
	 */
	public function print_inline_script_style() {
		if ( ! $this->is_edd_download_editor() ) {
			return;
		}

		$id                  = get_the_ID();
		$is_masteriyo_course = get_post_meta( $id, '_is_masteriyo_course', true );

		if ( 'yes' === $is_masteriyo_course ) {
			echo '<style>#edd_variable_pricing_control,#edd_product_files {display: none;}</style>';
		}

		$js = "
			function masteriyo_handle_course_input_change(event){
				const that = jQuery(event.target);
				const select = that.closest('.edd-form-group').find('.edd-form-group__control').eq(1);
				const variable_pricing =jQuery('#edd_variable_pricing_control');
				const product_files = jQuery('#edd_product_files');
				if (that.prop('checked')) {
					variable_pricing.hide();
					product_files.hide();
					select.show();
				} else {
					select.hide();
					variable_pricing.show();
					product_files.show();
				}
			}
			";

		wp_print_inline_script_tag( $js );
	}

	/**
	 * Is EDD download editor.
	 *
	 * @since 2.6.8
	 * @return boolean
	 */
	public function is_edd_download_editor() {
		global $pagenow, $typenow;
		return in_array( $pagenow, array( 'post.php', 'post-new.php' ), true ) && 'download' === $typenow;
	}

	/**
	 * Register ajax handlers.
	 *
	 * @since 2.6.8
	 *
	 * @param array $handlers Array of ajax handlers.
	 * @return array
	 */
	public function register_ajax_handlers( $handlers ) {
		$handlers[] = SearchCourseAjaxHandler::class;
		return $handlers;
	}

	/**
	 * Change to EDD Add to checkout URL.
	 *
	 * @since 2.6.8
	 *
	 * @param string $url Add to cart url.
	 * @param \Masteriyo\Models\Course $course
	 *
	 * @return string
	 */
	public function change_add_to_cart_url( $url, $course ) {
		// Bail early if EDD is not active.
		if ( ! function_exists( 'edd_get_download' ) ) {
			return $url;
		}

		$download_id = get_post_meta( $course->get_id(), '_edd_download_id', true );

		if ( ! $download_id ) {
			return $url;
		}

		$download = edd_get_download( $download_id );

		if ( ! $download ) {
			return $url;
		}

		$base_url = get_permalink( $download->get_ID() );

		if ( edd_get_option( 'redirect_on_add', false ) ) {
			$base_url = edd_get_checkout_uri();
		}

		if ( $base_url ) {
			$url = add_query_arg(
				array(
					'edd_action'  => 'add_to_cart',
					'download_id' => $download->get_ID(),
					'price'       => $download->get_price(),
				),
				$base_url
			);
		}

		return $url;
	}

	/**
	 * Update user course status according to EDD order status.
	 *
	 * @since 2.6.8
	 *
	 * @param int $edd_order_id EDD order ID.
	 * @param string $from EDD order from status.
	 * @param string $to EDD order to status.
	 */
	public function change_order_status( $edd_order_id, $to, $from ) {
		if ( $from === $to ) {
			return;
		}

		$order_items = edd_get_order_items(
			array(
				'order_id' => $edd_order_id,
				'number'   => -1,
			)
		);

		foreach ( $order_items as $order_item ) {
			$course = masteriyo_get_course( edd_get_order_item_meta( $order_item->id, '_masteriyo_course_id', true ) );

			if ( ! $course ) {
				continue;
			}

			$query = new UserCourseQuery(
				array(
					'course_id' => $course->get_id(),
					'user_id'   => $order_item->customer_id,
				)
			);

			$user_course = current( $query->get_user_courses() );

			if ( empty( $user_course ) ) {
				continue;
			}

			$unenrollment_statuses = array_map(
				function( $status ) {
					return $status['value'];
				},
				$this->setting->get( 'unenrollment_status', array() )
			);

			if ( OrderStatus::COMPLETED === $to ) {
				$user_course->set_status( UserCourseStatus::ACTIVE );
			} elseif ( in_array( $to, $unenrollment_statuses, true ) ) {
				$user_course->set_status( UserCourseStatus::INACTIVE );
			}

			$user_course->save();
		}
	}

	/**
	 * Create Masteriyo order when EDD order is created.
	 *
	 * @since 2.6.8
	 *
	 * @param int $order_id Edd order id.
	 */
	public function create_user_course( $order_id ) {
		if ( ! function_exists( 'edd_get_order_items' ) || ! function_exists( 'edd_get_download' ) ) {
			return;
		}

		$order       = edd_get_order( $order_id );
		$order_items = edd_get_order_items(
			array(
				'order_id' => $order_id,
				'number'   => -1,
			)
		);

		foreach ( $order_items as $order_item ) {
			$download = edd_get_download( $order_item->product_id );

			if ( ! $download ) {
				continue;
			}

			$is_masteriyo_course = get_post_meta( $download->ID, '_is_masteriyo_course', true );

			if ( 'yes' !== $is_masteriyo_course ) {
				continue;
			}

			$course = masteriyo_get_course( get_post_meta( $download->ID, '_masteriyo_course_id', true ) );

			if ( ! $course ) {
				continue;
			}

			edd_update_order_item_meta( $order_item->id, '_masteriyo_course_id', $course->get_id() );

			$query = new UserCourseQuery(
				array(
					'course_id' => $course->get_id(),
					'user_id'   => $order->user_id,
				)
			);

			$user_courses = $query->get_user_courses();
			/**
			 * @var UserCourse $user_course
			 */
			$user_course = empty( $user_courses ) ? masteriyo( 'user-course' ) : current( $user_courses );

			$user_course->set_course_id( $course->get_id() );
			$user_course->set_user_id( $order->user_id );
			$user_course->set_price( $download->get_price() );

			if ( OrderStatus::COMPLETED === $order->status ) {
				$user_course->set_status( UserCourseStatus::ACTIVE );
				$user_course->set_date_start( current_time( 'mysql', true ) );
			} elseif ( in_array( $order->status, $this->setting->get( 'unenrollment_status' ), true ) ) {
				$user_course->set_status( UserCourseStatus::INACTIVE );
				$user_course->set_date_start( null );
				$user_course->set_date_modified( null );
				$user_course->set_date_end( null );
			}

			$user_course->save();

			if ( $user_course->get_id() ) {
				$user_course->update_meta_data( '_edd_order_id', $order_id );
				$user_course->save_meta_data();
			}
		}
	}

	/**
	 * Update masteriyo_can_start_course() for course connected with EDD download.
	 *
	 * @since 2.6.8
	 *
	 * @param bool $can_start_course Whether user can start the course.
	 * @param \Masteriyo\Models\Course $course Course object.
	 * @param \Masteriyo\Models\User $user User object.
	 * @return boolean
	 */
	public function update_can_start_course( $can_start_course, $course, $user ) {
		if ( ! $course || ! function_exists( 'edd_get_download' ) || ! function_exists( 'edd_get_order' ) ) {
			return $can_start_course;
		}

		$download = edd_get_download( $course->get_meta( '_edd_download_id' ) );

		if ( ! $download ) {
			return $can_start_course;
		}

		// Bail early if the course is open.
		if ( CourseAccessMode::OPEN === $course->get_access_mode() ) {
			return $can_start_course;
		}

		// Bail early iif the user is not logged in.
		if ( ! is_user_logged_in() ) {
			return $can_start_course;
		}

		$query = new UserCourseQuery(
			array(
				'course_id' => $course->get_id(),
				'user_id'   => $user->get_id(),
				'per_page'  => 1,
			)
		);

		$user_course = current( $query->get_user_courses() );

		if ( empty( $user_course ) ) {
			return $can_start_course;
		}

		$edd_order_id = $user_course->get_meta( '_edd_order_id' );
		$edd_order    = edd_get_order( $edd_order_id );

		if ( ! $edd_order ) {
			return $can_start_course;
		}

		$can_start_course = 'complete' === $edd_order->status;

		return $can_start_course;
	}

	/**
	 * Add student role to edd customer.
	 *
	 * @since 2.6.8
	 *
	 * @param int $user_id User ID.
	 */
	public function add_student_role_to_edd_customer( $user_id ) {
		if ( ! function_exists( 'edd_has_purchases' ) || ! edd_has_purchases( $user_id ) ) {
			return;
		}

		remove_action( 'profile_update', array( $this, 'add_student_role_to_edd_customer' ) );
		remove_action( 'user_register', array( $this, 'add_student_role_to_edd_customer' ) );

		try {
			$user  = masteriyo( 'user' );
			$store = masteriyo( 'user.store' );

			$user->set_id( $user_id );
			$store->read( $user );

			if ( ! $user->has_role( 'masteriyo_student' ) ) {
				$user->add_role( 'masteriyo_student' );
				$user->save();
			}
		} catch ( \Exception $e ) {
			error_log( $e->getMessage() );
		}

		add_action( 'profile_update', array( $this, 'add_student_role_to_edd_customer' ) );
		add_action( 'user_register', array( $this, 'add_student_role_to_edd_customer' ) );
	}

	/**
	 * Add meta box fields to save.
	 *
	 * @since 2.6.8
	 *
	 * @param int $id Field names.
	 */
	public function save_meta_box_data( $id ) {
		if (
			! isset( $_POST['_masteriyo_edd_integration_nonce'] ) ||
			! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_masteriyo_edd_integration_nonce'] ) ), 'masteriyo_edd_integration' )
		) {
			return;
		}

		$is_masteriyo_course = ! empty( $_POST['_is_masteriyo_course'] ) ? sanitize_text_field( wp_unslash( $_POST['_is_masteriyo_course'] ) ) : '';
		$masteriyo_course_id = ! empty( $_POST['_masteriyo_course_id'] ) ? absint( wp_unslash( $_POST['_masteriyo_course_id'] ) ) : '';

		if ( 'yes' !== $is_masteriyo_course || ! $masteriyo_course_id ) {
			return;
		}

		$course = get_post( $masteriyo_course_id );

		if ( $course ) {
			update_post_meta( $course->ID, '_edd_download_id', $id );
			update_post_meta( $id, '_is_masteriyo_course', $is_masteriyo_course );
			update_post_meta( $id, '_masteriyo_course_id', $masteriyo_course_id );
		}
	}

	/**
	 * Add meta box.
	 *
	 * @since 2.6.8
	 */
	public function add_meta_box() {
		add_meta_box( 'masteriyo_edd_integration', __( 'Masteriyo', 'learning-management-system' ), array( $this, 'render_meta_box' ), 'download', 'side', 'high' );
	}

	/**
	 * Render meta box.
	 *
	 * @since 2.6.8
	 */
	public function render_meta_box() {
		$id                  = get_the_ID();
		$is_masteriyo_course = get_post_meta( $id, '_is_masteriyo_course', true );
		$masteriyo_course_id = get_post_meta( $id, '_masteriyo_course_id', true );

		$courses = get_posts(
			array(
				'post_type' => PostType::COURSE,
				'tax_query' => array(
					array(
						'taxonomy' => Taxonomy::COURSE_VISIBILITY,
						'field'    => 'slug',
						'terms'    => 'paid',
					),
				),
			)
		);

		$courses = array_reduce(
			$courses,
			function ( $acc, $curr ) {
				$acc[ $curr->ID ] = $curr->post_title;
				return $acc;
			},
			array(
				0 => __( 'Select Course', 'learning-management-system' ),
			)
		);

		if ( ! empty( $masteriyo_course_id ) && ! isset( $courses[ $masteriyo_course_id ] ) ) {
			$course                 = get_post( $masteriyo_course_id );
			$courses[ $course->ID ] = $course->post_title;
		}

		$data = array(
			'id'                  => $id,
			'is_masteriyo_course' => $is_masteriyo_course,
			'masteriyo_course_id' => $masteriyo_course_id,
			'courses'             => $courses,
		);

		wp_nonce_field( 'masteriyo_edd_integration', '_masteriyo_edd_integration_nonce' );

		require trailingslashit( Constants::get( 'MASTERIYO_EDD_INTEGRATION_TEMPLATES' ) ) . 'meta-box/meta-box.php';
	}
}
