<?php

defined( 'ABSPATH' ) || exit;

use Masteriyo\Addons\GroupCourses\Models\Setting;
use Masteriyo\Enums\OrderStatus;
use Masteriyo\Enums\PostStatus;

if ( ! function_exists( 'masteriyo_create_group_object' ) ) {
	/**
	 * Create instance of group model.
	 *
	 * @since 1.9.0
	 *
	 * @return \Masteriyo\Addons\GroupCourses\Models\Group
	 */
	function masteriyo_create_group_object() {
		return masteriyo( 'group-courses' );
	}
}

if ( ! function_exists( 'masteriyo_create_group_store' ) ) {
	/**
	 * Create instance of group repository.
	 *
	 * @since 1.9.0
	 *
	 * @return \Masteriyo\Addons\GroupCourses\Repository\GroupRepository
	 */
	function masteriyo_create_group_store() {
		return masteriyo( 'group-courses.store' );
	}
}

if ( ! function_exists( 'masteriyo_get_group' ) ) {
	/**
	 * Get group.
	 *
	 * @since 1.9.0
	 *
	 * @param int|\Masteriyo\Addons\GroupCourses\Models\Group|\WP_Post $group Group id or Group Model or Post.
	 *
	 * @return \Masteriyo\Addons\GroupCourses\Models\Group|null
	 */
	function masteriyo_get_group( $group ) {
		/** @var \Masteriyo\Addons\GroupCourses\Models\Group */
		$group_obj = masteriyo( 'group-courses' );
		/** @var \Masteriyo\Addons\GroupCourses\Repository\GroupRepository */
		$group_store = masteriyo( 'group-courses.store' );

		if ( is_a( $group, 'Masteriyo\Addons\GroupCourses\Models\Group' ) ) {
			$id = $group->get_id();
		} elseif ( is_a( $group, 'WP_Post' ) ) {
			$id = $group->ID;
		} else {
			$id = absint( $group );
		}

		try {
			$id = absint( $id );
			$group_obj->set_id( $id );
			$group_store->read( $group_obj );
		} catch ( \Exception $e ) {
			return null;
		}

		/**
		 * Filters group object.
		 *
		 * @since 1.9.0
		 *
		 * @param \Masteriyo\Addons\GroupCourses\Models\Group $group_obj Group object.
		 * @param int|\Masteriyo\Addons\GroupCourses\Models\Group|WP_Post $group Group id or Group Model or Post.
		 */
		return apply_filters( 'masteriyo_get_group', $group_obj, $group );
	}
}

if ( ! function_exists( 'masteriyo_get_group_price' ) ) {
	/**
	 * Retrieves the group price for a specified course.
	 *
	 * This function fetches the group price set for a course using its course ID. If a group price
	 * exists and is greater than 0, it formats the price using the `masteriyo_price` function
	 * and returns it. Otherwise, it returns false.
	 *
	 * @since 1.9.0
	 *
	 * @param int $course_id The ID of the course for which to retrieve the group price.
	 *
	 * @return mixed The formatted group price if it exists and is greater than 0, otherwise false.
	 */
	function masteriyo_get_group_price( $course_id ) {
		$group_price = floatval( get_post_meta( $course_id, '_group_courses_group_price', true ) );

		if ( $group_price > 0 ) {
			return masteriyo_price( $group_price );
		}

		return false;
	}
}

if ( ! function_exists( 'masteriyo_get_groups' ) ) {
	/**
	 * Retrieves the group objects for the given group IDs.
	 *
	 * This function iterates through an array of group IDs, retrieves each group object
	 * using the `masteriyo_get_group` function, and collects them into an array. If a group
	 * is successfully retrieved, it is added to the array; otherwise, it is skipped.
	 *
	 * @since 1.9.0
	 *
	 * @param array $group_ids An array of group IDs to retrieve.
	 *
	 * @return array An array of group objects.
	 */
	function masteriyo_get_groups( $group_ids ) {
		$groups = array();

		foreach ( $group_ids as $group_id ) {
			$group = masteriyo_get_group( $group_id );

			if ( $group ) {
				$groups[] = $group;
			}
		}

		return $groups;
	}
}

if ( ! function_exists( 'masteriyo_is_course_valid_for_group' ) ) {
	/**
	 * Checks if a course is valid for group pricing.
	 *
	 * Determines whether a given course qualifies for group pricing based on the existence
	 * of a group price for the course. If no course is explicitly provided, the function attempts
	 * to use a global `$course` variable.
	 *
	 * @since 1.9.0
	 *
	 * @param mixed $course Optional. The course object or ID. If not provided, the function tries to use a global variable.
	 *
	 * @return bool True if the course has a valid group price, false otherwise.
	 */
	function masteriyo_is_course_valid_for_group( $course = null ) {
		if ( ! $course ) {
			$course = $GLOBALS['course'];
		}

		$course = masteriyo_get_course( $course );

		if ( ! $course ) {
			return false;
		}
		$group_price = masteriyo_get_group_price( $course->get_id() );

		if ( $group_price ) {
			return true;
		}

		return false;
	}
}

if ( ! function_exists( 'masteriyo_get_group_max_size' ) ) {
	/**
	 * Get the maximum group size for a specific group.
	 *
	 * Note: In the current system, groups are associated with single courses.
	 * However, for backward compatibility with legacy multi-course groups,
	 * we take the first course's limit as the group size constraint.
	 * This ensures consistent behavior across both old and new group structures.
	 *
	 * @since 1.20.0
	 *
	 * @param int $group_id The group ID.
	 * @return int The maximum group size (0 means unlimited).
	 */
	function masteriyo_get_group_max_size( $group_id ) {
		// 1. Try to get purchased seats limit from group meta
		$max_group_size = absint( get_post_meta( $group_id, '_group_seats', true ) );

		if ( $max_group_size > 0 ) {
			return $max_group_size;
		}

		// 2. Fallback to backward compatibility logic: use course's max group size setting
		$course_data = get_post_meta( $group_id, 'masteriyo_course_data', true );

		if ( ! empty( $course_data ) && is_array( $course_data ) ) {
			// For backward compatibility: take the first course's limit
			// - New system: groups have single courses (array with one item)
			// - Legacy system: groups could have multiple courses
			// Using the first course's limit provides a reasonable constraint for both cases
			$first_course_data = reset( $course_data );
			if ( isset( $first_course_data['course_id'] ) ) {
				$course_id      = absint( $first_course_data['course_id'] );
				$max_group_size = absint( get_post_meta( $course_id, '_group_courses_max_group_size', true ) );
			}
		}

		return $max_group_size;
	}
}

if ( ! function_exists( 'masteriyo_validate_groups_for_course' ) ) {
	/**
	 * Validates and filters group IDs for a given course based on certain criteria.
	 *
	 * This function checks each group associated with the provided course ID to ensure
	 * it is not in the Trash status and meets the maximum group size criteria set in the
	 * course's metadata. It filters out any groups that do not meet these criteria.
	 *
	 * @since 1.9.0
	 *
	 * @param \Masteriyo\Models\Course $course The course object for which groups are being validated.
	 *                        Expected to at least have a valid ID.
	 * @param array                    $group_ids An array of group IDs to validate for the course.
	 *                                            Each ID is checked to ensure the corresponding group is valid
	 *                                            and does not exceed the maximum group size associated with the course.
	 *
	 * @return array An array of validated group IDs that are not trashed and do not exceed
	 *               the maximum group size set for the course. If no groups meet the criteria,
	 *               or if invalid parameters are provided, an empty array is returned.
	 */
	function masteriyo_validate_groups_for_course( $course, $group_ids ) {
		if ( ! $course || empty( $group_ids ) ) {
			return array();
		}

		if ( ! $course->is_purchasable() || ! $course->get_price() ) {
			return array();
		}

		$max_group_size = absint( get_post_meta( $course->get_id(), '_group_courses_max_group_size', true ) );

		$valid_group_ids = array();

		foreach ( $group_ids as $group_id ) {
			$group = masteriyo_get_group( $group_id );

			if ( ! $group || PostStatus::PUBLISH !== $group->get_status() ) {
				continue;
			}

			$user_id   = get_current_user_id();
			$author_id = absint( $group->get_author_id() );

			if ( ! ( masteriyo_is_current_user_admin() || masteriyo_is_current_user_manager() ) ) {
				if ( $user_id !== $author_id ) {
					continue;
				}
			}

			$emails     = $group->get_emails();
			$group_size = count( $emails );

			if ( 0 === $max_group_size || $group_size <= $max_group_size ) {
				$valid_group_ids[] = $group_id;
			}
		}

		return $valid_group_ids;
	}
}

if ( ! function_exists( 'masteriyo_get_members_emails_from_group' ) ) {
	/**
	 * Retrieves members' emails from group.
	 *
	 * @since 1.9.0
	 *
	 * @param array $group_id Group ID.
	 * @return array An array of members' emails.
	 */
	function masteriyo_get_members_emails_from_group( $group_id ) {
		$group = masteriyo_get_group( $group_id );

		$emails = array();
		if ( $group ) {
			$emails = $group->get_emails();
		}

		return $emails;
	}
}


if ( ! function_exists( 'masteriyo_fetch_group_member_emails' ) ) {
		/**
		 * Fetches the email addresses of all members in the given groups.
		 *
		 * @since 1.9.0
		 *
		 * @param array $group_ids Array of group IDs.
		 * @return array Array of email addresses.
		 */
	function masteriyo_fetch_group_member_emails( $group_ids ) {
		$emails = array();

		foreach ( $group_ids as $group_id ) {
			$group_emails = masteriyo_get_members_emails_from_group( $group_id );
			if ( ! empty( $group_emails ) ) {
				$emails = array_merge( $emails, $group_emails );
			}
		}

		return array_unique( $emails );
	}
}

if ( ! function_exists( 'masteriyo_update_user_enrollments_status' ) ) {
	/**
	 * Updates the enrollment status for users based on their email addresses.
	 *
	 * @since 1.9.0
	 *
	 * @param int    $group_id Group ID. $name
	 * @param array  $emails User email addresses.
	 * @param string $status New status to apply.
	 */
	function masteriyo_update_user_enrollments_status( $group_id, $emails, $status ) {
		global $wpdb;

		if ( ! $wpdb || empty( $emails ) || empty( $status ) ) {
			return;
		}

		$course_ids = masteriyo_get_active_course_ids_for_group( $group_id );

		if ( ! $course_ids ) {
			return;
		}

		foreach ( $emails as $email ) {
			$user = get_user_by( 'email', $email );

			if ( ! $user ) {
				continue;
			}

			foreach ( $course_ids as $course_id ) {
				if ( ! masteriyo_is_user_already_enrolled( $user->ID, $course_id ) ) {
					continue;
				}

				$status_db = masteriyo_get_user_enrollment_status( $user, $course_id );

				if ( $status === $status_db ) {
					continue;
				}

				$result = $wpdb->update(
					"{$wpdb->prefix}masteriyo_user_items",
					array( 'status' => $status ),
					array(
						'user_id'   => $user->ID,
						'item_id'   => $course_id,
						'item_type' => 'user_course',
					),
					array( '%s' ),
					array( '%d', '%d', '%s' )
				);

				if ( false !== $result ) {
					/**
					 * Fires after a user is successfully enrolled into a course as part of a group.
					 *
					 * @since 1.9.0
					 *
					 * @param int     $user_id   The ID of the enrolled user.
					 * @param WP_User $user      The WP_User object of the enrolled user.
					 * @param int     $group_id The ID of the group the user was added to.
					 * @param int     $course_id The ID of the course the user was enrolled into.
					 * @param string  $status The enrollment status of the user.
					 */
					do_action( 'masteriyo_group_enrollment_course_user_added', $user->ID, $user, $group_id, $course_id, $status );
				}
			}
		}
	}
}

if ( ! function_exists( 'masteriyo_get_user_enrollment_status' ) ) {
	/**
	 * Retrieves the current enrollment status for a given user and course item type.
	 *
	 * @since 1.9.0
	 *
	 * @param WP_User $user The user object whose enrollment status is to be retrieved.
	 * @param int     $course_id The ID of the course item for which to retrieve the enrollment status.
	 *
	 * @return string|null The current enrollment status of the user, or null if not found.
	 */
	function masteriyo_get_user_enrollment_status( $user, $course_id ) {
		global $wpdb;

		$enrollment_status_db = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT status FROM {$wpdb->prefix}masteriyo_user_items WHERE user_id = %d AND item_id = %d AND item_type = 'user_course'",
				$user->ID,
				absint( $course_id )
			)
		);

		return $enrollment_status_db ? $enrollment_status_db : null;
	}
}


if ( ! function_exists( 'masteriyo_is_user_already_enrolled' ) ) {
	/**
	 * Checks if a user is already enrolled in a course.
	 *
	 * @since 1.9.0
	 *
	 * @param int $user_id   The user ID.
	 * @param int $course_id The course ID.
	 * @return bool True if the user is already enrolled, false otherwise.
	 */
	function masteriyo_is_user_already_enrolled( $user_id, $course_id ) {
		global $wpdb;
		$count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->prefix}masteriyo_user_items WHERE user_id = %d AND item_id = %d AND item_type = 'user_course'",
				$user_id,
				$course_id
			)
		);

		return $count > 0;
	}
}

if ( ! function_exists( 'masteriyo_get_enrolled_group_user_emails' ) ) {
	/**
	 * Get the emails of users enrolled in a course for a specific group.
	 *
	 * @since 1.9.0
	 *
	 * @param \Masteriyo\Addons\GroupCourses\Models\Group $group The group object.
	 * @param int                                         $course_id Course ID.
	 *
	 * @return array An array of user emails not enrolled in the specified course.
	 */
	function masteriyo_get_enrolled_group_user_emails( $group, $course_id ) {
		if ( ! $group ) {
			return array();
		}

		$emails = $group->get_emails();

		if ( empty( $emails ) ) {
			return array();
		}

		$enrolled_emails = array_filter(
			array_map(
				function ( $email ) use ( $course_id ) {
						$user = get_user_by( 'email', $email );

						return ( $user && masteriyo_is_user_already_enrolled( $user->ID, $course_id ) ) ? $email : null;
				},
				$emails
			)
		);

		return array_values( $enrolled_emails );
	}
}

if ( ! function_exists( 'masteriyo_get_active_course_ids_for_group' ) ) {
	/**
	 * Retrieves course IDs for a specified group, optionally filtered by enrollment status.
	 * If no status is provided, all course IDs are returned.
	 *
	 * @since 1.9.0
	 *
	 * @param int    $group_id The group ID to retrieve course IDs for.
	 * @param string $status Optional. The enrollment status to filter by. If empty, all course IDs are returned.
	 *
	 * @return array An array of course IDs for the group, optionally filtered by the specified status.
	 */
	function masteriyo_get_active_course_ids_for_group( $group_id, $status = '' ) {
		$course_data = get_post_meta( $group_id, 'masteriyo_course_data', true );

		$course_ids = array();

		if ( is_array( $course_data ) ) {
			foreach ( $course_data as $data ) {
				if ( empty( $status ) || ( isset( $data['enrolled_status'] ) && $data['enrolled_status'] === $status ) ) {
					$course_ids[] = $data['course_id'];
				}
			}
		}

		return $course_ids;
	}
}

if ( ! function_exists( 'masteriyo_get_group_display_state' ) ) {
	/**
	 * Compute the frontend display state for a group based on its linked order.
	 *
	 * Returns an array with three keys:
	 *   - display_status  string  'active' | 'pending' | 'inactive'
	 *   - status_reason   string  Human-readable reason key for 'inactive' (empty otherwise).
	 *   - repurchase_url  string  Checkout URL with tier/seats pre-filled (for 'inactive' only, empty otherwise).
	 *
	 * @since x.x.x
	 *
	 * @param \Masteriyo\Addons\GroupCourses\Models\Group $group Group model.
	 *
	 * @return array{ display_status: string, status_reason: string, repurchase_url: string }
	 */
	function masteriyo_get_group_display_state( $group ) {
		static $cache = array();

		$default = array(
			'display_status' => 'inactive',
			'status_reason'  => 'removed',
			'repurchase_url' => '',
		);

		if ( ! $group ) {
			return $default;
		}

		$group_id = $group->get_id();
		if ( isset( $cache[ $group_id ] ) ) {
			return $cache[ $group_id ];
		}

		$course_data = get_post_meta( $group->get_id(), 'masteriyo_course_data', true );
		$order_id    = 0;
		$course_id   = 0;

		if ( is_array( $course_data ) && ! empty( $course_data[0] ) ) {
			$order_id  = isset( $course_data[0]['order_id'] ) ? absint( $course_data[0]['order_id'] ) : 0;
			$course_id = isset( $course_data[0]['course_id'] ) ? absint( $course_data[0]['course_id'] ) : 0;
		}

		if ( ! $order_id ) {
			$result             = masteriyo_build_inactive_display_state( $group, $course_id, 'removed' );
			$cache[ $group_id ] = $result;
			return $result;
		}

		// Use get_post so we can detect trash (masteriyo_get_order ignores trash).
		$order_post = get_post( $order_id );
		if ( ! $order_post || PostStatus::TRASH === $order_post->post_status ) {
			$result             = masteriyo_build_inactive_display_state( $group, $course_id, 'removed' );
			$cache[ $group_id ] = $result;
			return $result;
		}

		$order = masteriyo_get_order( $order_id );
		if ( ! $order ) {
			$result             = masteriyo_build_inactive_display_state( $group, $course_id, 'removed' );
			$cache[ $group_id ] = $result;
			return $result;
		}

		$order_status = $order->get_status();

		if ( OrderStatus::COMPLETED === $order_status ) {
			$result             = array(
				'display_status' => 'active',
				'status_reason'  => '',
				'repurchase_url' => '',
			);
			$cache[ $group_id ] = $result;
			return $result;
		}

		if ( in_array( $order_status, array( OrderStatus::PENDING, OrderStatus::ON_HOLD, OrderStatus::PROCESSING ), true ) ) {
			$result             = array(
				'display_status' => 'pending',
				'status_reason'  => '',
				'repurchase_url' => '',
			);
			$cache[ $group_id ] = $result;
			return $result;
		}

		// failed / cancelled / refunded.
		$reason_map = array(
			OrderStatus::FAILED    => 'failed',
			OrderStatus::CANCELLED => 'cancelled',
			OrderStatus::REFUNDED  => 'refunded',
		);
		$reason     = isset( $reason_map[ $order_status ] ) ? $reason_map[ $order_status ] : 'removed';

		$result             = masteriyo_build_inactive_display_state( $group, $course_id, $reason );
		$cache[ $group_id ] = $result;
		return $result;
	}
}

if ( ! function_exists( 'masteriyo_build_inactive_display_state' ) ) {
	/**
	 * Build the inactive display state array including the repurchase URL.
	 *
	 * @since x.x.x
	 *
	 * @param \Masteriyo\Addons\GroupCourses\Models\Group $group     Group model.
	 * @param int                                         $course_id Course ID (0 if unknown).
	 * @param string                                      $reason    Reason key.
	 *
	 * @return array
	 */
	function masteriyo_build_inactive_display_state( $group, $course_id, $reason ) {
		$repurchase_url = '';

		if ( $course_id ) {
			$tier_id = get_post_meta( $group->get_id(), '_group_tier_id', true );
			$seats   = get_post_meta( $group->get_id(), '_group_seats', true );

			$args = array(
				'add-to-cart'    => $course_id,
				'group_purchase' => 'yes',
			);

			if ( $tier_id ) {
				$args['group_tier_id'] = $tier_id;
			}

			if ( $seats ) {
				$args['group_seats'] = absint( $seats );
			}

			$repurchase_url = add_query_arg( $args, masteriyo_get_page_permalink( 'checkout' ) );
		}

		return array(
			'display_status' => 'inactive',
			'status_reason'  => $reason,
			'repurchase_url' => $repurchase_url,
		);
	}
}
