<?php
/**
 * Class LP_Course_Post_Type
 *
 * @author  ThimPress
 * @package LearnPress/Classes
 * @version 3.0.2
 */

use LearnPress\Models\CourseModel;
use LearnPress\Models\CoursePostModel;
use LearnPress\Models\WPTables\CoursesTable;

defined( 'ABSPATH' ) || exit();

if ( ! class_exists( 'LP_Course_Post_Type' ) ) {

	/**
	 * Class LP_Course_Post_Type
	 */
	final class LP_Course_Post_Type extends LP_Abstract_Post_Type {
		/**
		 * @var null
		 */
		protected static $_instance = null;
		protected $_post_type       = LP_COURSE_CPT;
		protected $_screen_list     = 'edit-' . LP_COURSE_CPT;

		/**
		 * Constructor
		 */
		public function __construct() {
			parent::__construct();

			add_action( 'init', array( $this, 'register_taxonomy' ) );
			add_filter( 'posts_where_paged', array( $this, '_posts_where_paged_course_items' ), 10 );
			add_filter( 'posts_join_paged', array( $this, '_posts_join_paged_course_items' ), 10 );
		}

		/**
		 * Register course post type.
		 */
		public function args_register_post_type(): array {
			// Support Quick Edit multiple courses change author
			add_post_type_support( LP_COURSE_CPT, 'author' );

			$labels           = array(
				'name'               => _x( 'Courses', 'Post Type General Name', 'learnpress' ),
				'singular_name'      => _x( 'Course', 'Post Type Singular Name', 'learnpress' ),
				'menu_name'          => __( 'Courses', 'learnpress' ),
				'parent_item_colon'  => __( 'Parent Item:', 'learnpress' ),
				'all_items'          => __( 'Courses', 'learnpress' ),
				'view_item'          => __( 'View Course', 'learnpress' ),
				'add_new_item'       => __( 'Add a New Course', 'learnpress' ),
				'add_new'            => __( 'Add New', 'learnpress' ),
				'edit_item'          => __( 'Edit Course', 'learnpress' ),
				'update_item'        => __( 'Update Course', 'learnpress' ),
				'search_items'       => __( 'Search Courses', 'learnpress' ),
				'not_found'          => sprintf(
					__( 'You have not had any courses yet. Click <a href="%s">Add new</a> to start', 'learnpress' ),
					admin_url( 'post-new.php?post_type=lp_course' )
				),
				'not_found_in_trash' => __( 'There was no course found in the trash', 'learnpress' ),
			);
			$course_base      = LP_Settings::get_option( 'course_base', 'courses' );
			$course_permalink = empty( $course_base ) ? 'courses' : $course_base;

			// Set to $has_archive return link to courses page, is_archive will check is true
			$courses_page_id = learn_press_get_page_id( 'courses' );
			$has_archive     = $courses_page_id ? urldecode( get_page_uri( $courses_page_id ) ) : 'courses';

			$args = array(
				'labels'             => $labels,
				'public'             => true,
				'query_var'          => true,
				'publicly_queryable' => true,
				'show_ui'            => true,
				'has_archive'        => $has_archive,
				'capability_type'    => $this->_post_type,
				'map_meta_cap'       => true,
				'show_in_menu'       => 'learn_press',
				'show_in_admin_bar'  => true,
				'show_in_nav_menus'  => true,
				'show_in_rest'       => true,
				'taxonomies'         => array( 'course_category', 'course_tag' ),
				'supports'           => array( 'title', 'editor', 'thumbnail', 'revisions', 'comments', 'excerpt' ),
				'hierarchical'       => false,
				'rewrite'            => ! empty( $course_permalink ) ? array(
					'slug'       => untrailingslashit( $course_permalink ),
					'with_front' => false,
				) : false,
			);

			return $args;
		}

		/**
		 * Register course taxonomy.
		 */
		public function register_taxonomy() {
			$category_base = LP_Settings::get_option( 'course_category_base' );
			register_taxonomy(
				'course_category',
				array( LP_COURSE_CPT ),
				array(
					'label'             => __( 'Course Categories', 'learnpress' ),
					'labels'            => array(
						'name'          => __( 'Course Categories', 'learnpress' ),
						'menu_name'     => __( 'Course Category', 'learnpress' ),
						'singular_name' => __( 'Category', 'learnpress' ),
						'add_new_item'  => __( 'Add A New Course Category', 'learnpress' ),
						'all_items'     => __( 'All Categories', 'learnpress' ),
					),
					'query_var'         => true,
					'public'            => true,
					'hierarchical'      => true,
					'show_ui'           => true,
					'show_in_menu'      => 'learn_press',
					'show_admin_column' => true,
					'show_in_admin_bar' => true,
					'show_in_nav_menus' => true,
					'show_in_rest'      => true,
					'rewrite'           => array(
						'slug'         => empty( $category_base ) ? 'course-category' : $category_base,
						'hierarchical' => true,
						'with_front'   => false,
					),
				)
			);

			$tag_base = LP_Settings::get_option( 'course_tag_base' );
			register_taxonomy(
				'course_tag',
				array( LP_COURSE_CPT ),
				array(
					'labels'                => array(
						'name'                       => __( 'Course Tags', 'learnpress' ),
						'singular_name'              => __( 'Tag', 'learnpress' ),
						'search_items'               => __( 'Search Course Tags', 'learnpress' ),
						'popular_items'              => __( 'Popular Course Tags', 'learnpress' ),
						'all_items'                  => __( 'All Course Tags', 'learnpress' ),
						'parent_item'                => null,
						'parent_item_colon'          => null,
						'edit_item'                  => __( 'Edit Course Tag', 'learnpress' ),
						'update_item'                => __( 'Update Course Tag', 'learnpress' ),
						'add_new_item'               => __( 'Add A New Course Tag', 'learnpress' ),
						'new_item_name'              => __( 'New Course Tag Name', 'learnpress' ),
						'separate_items_with_commas' => __( 'Separate tags with commas', 'learnpress' ),
						'add_or_remove_items'        => __( 'Add or remove tags', 'learnpress' ),
						'choose_from_most_used'      => __( 'Choose from the most used tags', 'learnpress' ),
						'menu_name'                  => __( 'Course Tags', 'learnpress' ),
					),
					'public'                => true,
					'hierarchical'          => false,
					'show_ui'               => true,
					'show_in_menu'          => 'learn_press',
					'update_count_callback' => '_update_post_term_count',
					'query_var'             => true,
					'show_in_rest'          => true,
					'rewrite'               => array(
						'slug'       => empty( $tag_base ) ? 'course-tag' : $tag_base,
						'with_front' => false,
					),
				)
			);
		}

		/**
		 * Declare class name of table list courses.
		 *
		 * @param string $class_name
		 * @param array  $args
		 *
		 * @return string
		 * @since 4.2.9.5
		 */
		public function wp_list_table_class_name( $class_name, $args ) {
			if ( $this->check_class_name_handle_table( $args['screen'] ) ) {
				$class_name = CoursesTable::class;
			}

			return $class_name;
		}

		/**
		 * Delete course sections before delete course.
		 *
		 * @param int $post_id
		 *
		 * @throws Exception
		 * @since modify 4.0.9
		 * @since 3.0.0
		 * @editor tungnx
		 */
		public function before_delete( int $post_id ) {
			// Delete course from table learnpress_courses
			$courseModel = CourseModel::find( $post_id, true );
			if ( $courseModel ) {
				$courseModel->delete();
			}

			$course = learn_press_get_course( $post_id );
			if ( ! $course ) {
				return;
			}
			$course->delete_relate_data_when_delete_course();
		}

		/**
		 * @param string $fields
		 *
		 * @return string
		 */
		public function posts_fields( $fields ): string {
			if ( ! $this->is_page_list_posts_on_backend() ) {
				return $fields;
			}

			$fields = ' DISTINCT ' . $fields;
			if ( $this->get_order_by() == 'price' ) {
				$fields .= ', pm_price.meta_value as course_price';
			}

			return $fields;
		}

		public function _posts_join_paged_course_items( $join ) {
			global $wpdb;

			$course_id = $this->_filter_items_by_course();
			if ( $course_id || LP_Request::get_param( 'orderby' ) === 'course-name' ) {
				$join .= " LEFT JOIN {$wpdb->prefix}learnpress_section_items si ON {$wpdb->posts}.ID = si.item_id";
				$join .= " LEFT JOIN {$wpdb->prefix}learnpress_sections s ON s.section_id = si.section_id";
				$join .= " LEFT JOIN {$wpdb->posts} c ON c.ID = s.section_course_id";
			}

			return $join;
		}

		public function _posts_where_paged_course_items( $where ) {
			global $wpdb;

			$course_id = $this->_filter_items_by_course();
			if ( $course_id ) {
				$where .= $wpdb->prepare( ' AND (c.ID = %d)', $course_id );
				$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_status = %s", 'publish' );
			}

			return $where;
		}

		/**
		 * @param $join
		 *
		 * @return string
		 */
		public function posts_join_paged( $join ) {
			global $wpdb;

			if ( ! $this->is_page_list_posts_on_backend() ) {
				return $join;
			}

			if ( ! isset( $_GET['orderby'] ) || $_GET['orderby'] !== 'price' ) {
				return $join;
			}

			$join .= " LEFT JOIN {$wpdb->postmeta} pm_price ON pm_price.post_id = {$wpdb->posts}.ID AND pm_price.meta_key = '_lp_price'";

			return $join;
		}

		/**
		 * @param $where
		 *
		 * @return mixed|string
		 */
		public function posts_where_paged( $where ) {
			global $wpdb;

			if ( ! $this->is_page_list_posts_on_backend() ) {
				return $where;
			}

			$filter_price = LP_Helper::sanitize_params_submitted( $_REQUEST['filter_price'] ?? 0 );

			if ( array_key_exists( 'filter_price', $_REQUEST ) ) {
				if ( $filter_price == 0 ) {
					$where .= ' AND ( pm_price.meta_value IS NULL || pm_price.meta_value = 0 )';
				} else {
					$where .= $wpdb->prepare( ' AND ( pm_price.meta_value = %s )', $filter_price );
				}
			}

			/*$not_in = $wpdb->prepare(
				"
				SELECT ID
				FROM {$wpdb->posts} p
				INNER JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID AND pm.meta_key = %s
				WHERE pm.meta_value = %s
				",
				'_lp_preview_course',
				'yes'
			);

			$where .= " AND {$wpdb->posts}.ID NOT IN( {$not_in} )";*/

			return $where;
		}

		/**
		 * @param $orderby
		 *
		 * @return string
		 */
		public function posts_orderby( $orderby ) {
			if ( ! $this->is_page_list_posts_on_backend() ) {
				return $orderby;
			}

			$order = $this->get_order_sort();
			switch ( $this->get_order_by() ) {
				case 'price':
					$orderby = "CAST(pm_price.meta_value AS UNSIGNED) {$order}";
			}

			return $orderby;
		}

		/**
		 * Save course post
		 *
		 * @param int $post_id
		 * @param WP_Post|null $post
		 * @param bool $is_update
		 *
		 * @since 4.2.6.9
		 * @version 1.0.2
		 */
		public function save_post( int $post_id, ?WP_Post $post = null, bool $is_update = false ) {
			try {
				$wp_screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
				// Save to table learnpress_courses
				LP_Install::instance()->create_table_courses();
				if ( empty( $post ) ) {
					$post = get_post( $post_id );
				}

				/*if ( $post->post_status === 'auto-draft' ) {
					return;
				}*/

				$courseModel = CourseModel::find( $post_id, true );
				if ( ! $courseModel ) {
					$courseModel = new CourseModel( $post );
				}

				// Merge object post and courseModel
				$new_obj     = (array) $post;
				$old_obj     = (array) $courseModel;
				$old_now     = array_merge( $old_obj, $new_obj );
				$courseModel = new CourseModel( $old_now );

				// Get all metadata of course
				if ( $is_update && empty( $wp_screen ) ) {
					$coursePost = new CoursePostModel( $courseModel );
					$coursePost->get_all_metadata();
					// Temporary unset _elementor_page_assets of El, reason by method get_all_metadata get not use maybe_unserialize, make save invalid serialize
					$coursePost->meta_data->_elementor_page_assets = [];

					$courseModel->meta_data = $coursePost->meta_data;
				}

				// Save option single course
				include_once LP_PLUGIN_PATH . 'inc/admin/class-lp-admin.php';
				$lp_meta_box_course = new LP_Meta_Box_Course();
				$ground_fields      = $lp_meta_box_course->metabox( $courseModel->ID );
				// Save meta fields
				foreach ( $ground_fields as $fields ) {
					if ( ! isset( $fields['content'] ) ) {
						continue;
					}
					foreach ( $fields['content'] as $meta_key => $option ) {
						$option->id = $meta_key;
						if ( ! $option instanceof LP_Meta_Box_Field ) {
							continue;
						}

						if ( isset( $_POST[ $meta_key ] ) && ! empty( $wp_screen ) && LP_COURSE_CPT === $wp_screen->id ) {
							$value_saved = $option->save( $courseModel->ID );
							if ( ! empty( $value_saved ) ) {
								$courseModel->meta_data->{$meta_key} = $value_saved;
							} else {
								$courseModel->meta_data->{$meta_key} = maybe_unserialize(
									get_post_meta( $courseModel->ID, $meta_key, true )
								);
							}
						} elseif ( ! $is_update ) {
							$courseModel->meta_data->{$meta_key} = $option->default ?? '';
						} elseif ( ! empty( $wp_screen ) && LP_COURSE_CPT === $wp_screen->id ) {
							$value_saved                         = $option->save( $courseModel->ID );
							$courseModel->meta_data->{$meta_key} = $value_saved;
						}
					}
				}

				// For case bulk edit multiple courses change author
				$bulk_edit = LP_Request::get_param( 'bulk_edit', false );
				if ( ! empty( $bulk_edit ) ) {
					$post_author = LP_Request::get_param( 'post_author', 0, 'int' );
					if ( $post_author != -1 ) { // -1 is for no change author
						$courseModel->post_author = $post_author;
					}
				} elseif ( ! empty( $_REQUEST['_post_author'] ) ) {
					// Not use key 'post_author' on single edit course, it special key of WP, Gutenberg save will not submit this key.
					$courseModel->post_author = LP_Request::get_param( '_post_author', 0, 'int' );
					/**
					 * Save author to post table
					 * Not use PostModel::save() or CoursePostModel::save() here
					 * because it calls wp_update_post(), has hook 'save_post', it will cause infinite loop
					 */
					$lp_db                     = LP_Database::getInstance();
					$filter_update             = new LP_Post_Type_Filter();
					$filter_update->collection = $lp_db->tb_posts;
					$filter_update->set[]      = "post_author = {$courseModel->post_author}";
					$filter_update->where[]    = $lp_db->wpdb->prepare( 'AND ID = %d', $courseModel->ID );
					$lp_db->update_execute( $filter_update );
					clean_post_cache( $post->ID );
				} elseif ( isset( $_POST['post_author'] ) && isset( $_POST['screen'] ) && $_POST['screen'] === 'edit-' . LP_COURSE_CPT ) {
					// For case quick edit change author.
					$courseModel->post_author = LP_Request::get_param( 'post_author', 0, 'int' );
				}

				$this->save_price( $courseModel );
				$courseModel->save();
				// End save to table learnpress_courses

				// Save extra info course
				// Save in background.
				$bg = LP_Background_Single_Course::instance();
				$bg->data(
					array(
						'handle_name' => 'save_post',
						'course_id'   => $post_id,
						'data'        => $_POST ?? [],
					)
				)->dispatch();
			} catch ( Throwable $e ) {
				LP_Debug::error_log( $e );
			}
		}

		/**
		 * Save price course
		 *
		 * @return void
		 * @throws Exception
		 */
		protected function save_price( CourseModel &$courseObj ) {
			$coursePost = new CoursePostModel( $courseObj );

			$regular_price = $courseObj->get_regular_price();
			$sale_price    = $courseObj->get_sale_price();
			if ( (float) $regular_price < 0 ) {
				$courseObj->meta_data->{CoursePostModel::META_KEY_REGULAR_PRICE} = '';
				$regular_price = $courseObj->get_regular_price();
			}

			if ( $sale_price !== '' && (float) $sale_price > (float) $regular_price ) {
				$courseObj->meta_data->{CoursePostModel::META_KEY_SALE_PRICE} = '';
				$sale_price = $courseObj->get_sale_price();
			}

			// Save sale regular price and sale price to table postmeta
			$coursePost->save_meta_value_by_key( CoursePostModel::META_KEY_REGULAR_PRICE, $regular_price );
			$coursePost->save_meta_value_by_key( CoursePostModel::META_KEY_SALE_PRICE, $sale_price );

			$has_sale = $courseObj->has_sale_price();
			if ( $has_sale ) {
				$courseObj->is_sale = 1;
				$coursePost->save_meta_value_by_key( CoursePostModel::META_KEY_IS_SALE, 1 );
			} else {
				$courseObj->is_sale = 0;
				delete_post_meta( $courseObj->get_id(), CoursePostModel::META_KEY_IS_SALE );
			}

			// Set price to sort on lists.
			$courseObj->price_to_sort = $courseObj->get_price();
			$coursePost->save_meta_value_by_key( CoursePostModel::META_KEY_PRICE, $courseObj->price_to_sort );
		}

		/**
		 * Instance LP_Course_Post_Type.
		 *
		 * @return LP_Course_Post_Type|null
		 */
		public static function instance() {
			if ( ! self::$_instance ) {
				self::$_instance = new self();
			}

			return self::$_instance;
		}
	}

	$course_post_type = LP_Course_Post_Type::instance();
}
