<?php
/**
 * Kurs Post Type and Taxonomy
 *
 * @package KursBooking
 */

declare(strict_types=1);

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class Kurs_Booking_Kurs
 *
 * Handles the 'kurs' custom post type and 'kurs_category' taxonomy.
 */
class Kurs_Booking_Kurs {

	/**
	 * Post type name
	 */
	public const POST_TYPE = 'kurs';

	/**
	 * Taxonomy name
	 */
	public const TAXONOMY = 'kurs_category';

	/**
	 * Meta field prefix
	 */
	private const META_PREFIX = '_kurs_';

	/**
	 * Initialize hooks
	 */
	public static function init(): void {
		add_action( 'init', array( __CLASS__, 'register_post_type' ) );
		add_action( 'init', array( __CLASS__, 'register_taxonomy' ) );
		add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_boxes' ) );
		add_action( 'save_post_' . self::POST_TYPE, array( __CLASS__, 'save_meta' ), 10, 2 );
	}

	/**
	 * Register the kurs post type
	 */
	public static function register_post_type(): void {
		$labels = array(
			'name'                  => _x( 'Veranstaltungen', 'Post type general name', 'kurs-booking' ),
			'singular_name'         => _x( 'Veranstaltung', 'Post type singular name', 'kurs-booking' ),
			'menu_name'             => _x( 'Veranstaltungen', 'Admin Menu text', 'kurs-booking' ),
			'add_new'               => __( 'Neu erstellen', 'kurs-booking' ),
			'add_new_item'          => __( 'Neue Veranstaltung erstellen', 'kurs-booking' ),
			'edit_item'             => __( 'Veranstaltung bearbeiten', 'kurs-booking' ),
			'new_item'              => __( 'Neue Veranstaltung', 'kurs-booking' ),
			'view_item'             => __( 'Veranstaltung ansehen', 'kurs-booking' ),
			'view_items'            => __( 'Veranstaltungen ansehen', 'kurs-booking' ),
			'search_items'          => __( 'Veranstaltungen suchen', 'kurs-booking' ),
			'not_found'             => __( 'Keine Veranstaltungen gefunden', 'kurs-booking' ),
			'not_found_in_trash'    => __( 'Keine Veranstaltungen im Papierkorb', 'kurs-booking' ),
			'all_items'             => __( 'Alle Veranstaltungen', 'kurs-booking' ),
			'archives'              => __( 'Veranstaltungs-Archiv', 'kurs-booking' ),
			'attributes'            => __( 'Veranstaltungs-Attribute', 'kurs-booking' ),
			'featured_image'        => __( 'Veranstaltungsbild', 'kurs-booking' ),
			'set_featured_image'    => __( 'Veranstaltungsbild festlegen', 'kurs-booking' ),
			'remove_featured_image' => __( 'Veranstaltungsbild entfernen', 'kurs-booking' ),
		);

		$args = array(
			'labels'             => $labels,
			'public'             => true,
			'publicly_queryable' => true,
			'show_ui'            => true,
			'show_in_menu'       => true,
			'query_var'          => true,
			'rewrite'            => array( 'slug' => 'kurs' ),
			'capability_type'    => 'post',
			'has_archive'        => true,
			'hierarchical'       => false,
			'menu_position'      => 5,
			'menu_icon'          => 'dashicons-calendar-alt',
			'supports'           => array( 'title', 'editor', 'thumbnail', 'excerpt' ),
			'show_in_rest'       => true,
		);

		// Force classic editor for this post type (Meta boxes don't work well with Gutenberg).
		add_filter(
			'use_block_editor_for_post_type',
			function ( $use, $post_type ) {
				if ( 'kurs' === $post_type ) {
					return false;
				}
				return $use;
			},
			10,
			2
		);

		// Move Rank Math SEO meta box to bottom (low priority).
		// Remove Slider Revolution meta box.
		add_action(
			'add_meta_boxes',
			function () {
				global $wp_meta_boxes;

				// Move Rank Math to bottom.
				if ( isset( $wp_meta_boxes['kurs']['normal']['high']['rank_math_metabox'] ) ) {
					$rank_math_box = $wp_meta_boxes['kurs']['normal']['high']['rank_math_metabox'];
					unset( $wp_meta_boxes['kurs']['normal']['high']['rank_math_metabox'] );
					// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Required to reorder meta boxes.
					$wp_meta_boxes['kurs']['normal']['low']['rank_math_metabox'] = $rank_math_box;
				}

				// Remove Slider Revolution completely (meta box + screen option).
				remove_meta_box( 'mymetabox_revslider_0', 'kurs', 'normal' );
				remove_meta_box( 'mymetabox_revslider_0', 'kurs', 'side' );
				remove_meta_box( 'rs-addon-typewriter-meta', 'kurs', 'normal' );
				remove_meta_box( 'rs-addon-typewriter-meta', 'kurs', 'side' );

				// Also remove from advanced context.
				remove_meta_box( 'mymetabox_revslider_0', 'kurs', 'advanced' );
			},
			999
		);

		// Prevent Slider Revolution from registering on kurs post type.
		add_filter(
			'revslider_meta_box_post_types',
			function ( $post_types ) {
				return array_diff( $post_types, array( 'kurs' ) );
			},
			999
		);

		register_post_type( self::POST_TYPE, $args );
	}

	/**
	 * Register the kurs_category taxonomy
	 */
	public static function register_taxonomy(): void {
		$labels = array(
			'name'              => _x( 'Kategorien', 'Taxonomy general name', 'kurs-booking' ),
			'singular_name'     => _x( 'Kategorie', 'Taxonomy singular name', 'kurs-booking' ),
			'search_items'      => __( 'Kategorien suchen', 'kurs-booking' ),
			'all_items'         => __( 'Alle Kategorien', 'kurs-booking' ),
			'parent_item'       => __( 'Uebergeordnete Kategorie', 'kurs-booking' ),
			'parent_item_colon' => __( 'Uebergeordnete Kategorie:', 'kurs-booking' ),
			'edit_item'         => __( 'Kategorie bearbeiten', 'kurs-booking' ),
			'update_item'       => __( 'Kategorie aktualisieren', 'kurs-booking' ),
			'add_new_item'      => __( 'Neue Kategorie hinzufuegen', 'kurs-booking' ),
			'new_item_name'     => __( 'Neuer Kategorie-Name', 'kurs-booking' ),
			'menu_name'         => __( 'Kategorien', 'kurs-booking' ),
		);

		$args = array(
			'labels'            => $labels,
			'hierarchical'      => true,
			'public'            => true,
			'show_ui'           => true,
			'show_admin_column' => true,
			'show_in_nav_menus' => true,
			'show_tagcloud'     => false,
			'show_in_rest'      => true,
			'rewrite'           => array( 'slug' => 'veranstaltung-kategorie' ),
		);

		register_taxonomy( self::TAXONOMY, self::POST_TYPE, $args );
	}

	/**
	 * Add meta boxes to kurs post type
	 */
	public static function add_meta_boxes(): void {
		add_meta_box(
			'kurs_details',
			__( 'Veranstaltungs-Details', 'kurs-booking' ),
			array( __CLASS__, 'render_details_meta_box' ),
			self::POST_TYPE,
			'normal',
			'high'
		);

		add_meta_box(
			'kurs_pricing',
			__( 'Preisvarianten', 'kurs-booking' ),
			array( __CLASS__, 'render_pricing_meta_box' ),
			self::POST_TYPE,
			'normal',
			'high'
		);

		add_meta_box(
			'kurs_booking_options',
			__( 'Buchungsoptionen', 'kurs-booking' ),
			array( __CLASS__, 'render_booking_meta_box' ),
			self::POST_TYPE,
			'side',
			'default'
		);

		add_meta_box(
			'kurs_video_zuordnung',
			__( 'Video-Zuordnung', 'kurs-booking' ),
			array( __CLASS__, 'render_video_meta_box' ),
			self::POST_TYPE,
			'normal',
			'high'
		);

		add_meta_box(
			'kurs_related',
			__( 'Ähnliche Kurse', 'kurs-booking' ),
			array( __CLASS__, 'render_related_meta_box' ),
			self::POST_TYPE,
			'normal',
			'low'
		);
	}

	/**
	 * Render the kurs details meta box
	 *
	 * @param WP_Post $post The post object.
	 */
	public static function render_details_meta_box( WP_Post $post ): void {
		wp_nonce_field( 'kurs_booking_save_meta', 'kurs_booking_nonce' );

		// Get current values.
		$produktart   = get_post_meta( $post->ID, self::META_PREFIX . 'produktart', true ) ?: 'kurs';
		$buchungsart  = get_post_meta( $post->ID, self::META_PREFIX . 'buchungsart', true ) ?: 'direkt';
		$start_date   = get_post_meta( $post->ID, self::META_PREFIX . 'start_date', true );
		$end_date     = get_post_meta( $post->ID, self::META_PREFIX . 'end_date', true );
		$start_time   = get_post_meta( $post->ID, self::META_PREFIX . 'start_time', true );
		$end_time     = get_post_meta( $post->ID, self::META_PREFIX . 'end_time', true );
		$kurs_type    = get_post_meta( $post->ID, self::META_PREFIX . 'type', true ) ?: 'vor_ort';
		$location     = get_post_meta( $post->ID, self::META_PREFIX . 'location', true );
		$location_url = get_post_meta( $post->ID, self::META_PREFIX . 'location_url', true );
		$google_maps  = get_post_meta( $post->ID, self::META_PREFIX . 'google_maps', true );
		$zoom_link    = get_post_meta( $post->ID, self::META_PREFIX . 'zoom_link', true );
		$zoom_pass    = get_post_meta( $post->ID, self::META_PREFIX . 'zoom_password', true );
		$instructor   = get_post_meta( $post->ID, self::META_PREFIX . 'instructor', true );
		$horse        = get_post_meta( $post->ID, self::META_PREFIX . 'horse', true );
		$notes        = get_post_meta( $post->ID, self::META_PREFIX . 'notes', true );

		// Load masterdata from settings.
		$instructors_list = get_option( 'kurs_booking_instructors', array() );
		$horses_list      = get_option( 'kurs_booking_horses', array() );
		$locations_list   = get_option( 'kurs_booking_locations', array() );

		if ( ! is_array( $instructors_list ) ) {
			$instructors_list = array();
		}
		if ( ! is_array( $horses_list ) ) {
			$horses_list = array();
		}
		if ( ! is_array( $locations_list ) ) {
			$locations_list = array();
		}

		// Determine if current location is from list or custom.
		$location_is_custom = true;
		$location_selected  = '';
		foreach ( $locations_list as $loc ) {
			if ( isset( $loc['name'] ) && $loc['name'] === $location ) {
				$location_is_custom = false;
				$location_selected  = $location;
				break;
			}
		}

		// Determine if current horse is from list or custom.
		$horse_is_custom = ! empty( $horse ) && ! in_array( $horse, $horses_list, true );
		?>
		<div class="kurs-meta-box">
			<!-- Grundeinstellungen Section -->
			<div class="kb-section">
				<div class="kb-section-header">
					<div class="kb-section-icon">
						<span class="dashicons dashicons-admin-settings"></span>
					</div>
					<h3 class="kb-section-title"><?php esc_html_e( 'Grundeinstellungen', 'kurs-booking' ); ?></h3>
				</div>

				<div class="kb-grid kb-grid-2">
					<div class="kb-row">
						<label for="kurs_produktart"><?php esc_html_e( 'Produktart', 'kurs-booking' ); ?></label>
						<div class="kb-select-wrap">
							<select name="kurs_produktart" id="kurs_produktart">
								<?php
								// Sprint 8.3: Dynamisches Dropdown aus Dienstleistungen.
								$dropdown_options = Kurs_Booking_Dienstleistungen::get_dropdown_options();
								foreach ( $dropdown_options as $value => $label ) :
									?>
									<option value="<?php echo esc_attr( $value ); ?>" <?php selected( $produktart, $value ); ?>>
										<?php echo esc_html( $label ); ?>
									</option>
								<?php endforeach; ?>
							</select>
						</div>
						<span class="kb-hint kb-produktart-hint"></span>
					</div>

					<div class="kb-row">
						<label for="kurs_buchungsart"><?php esc_html_e( 'Buchungsart', 'kurs-booking' ); ?></label>
						<div class="kb-select-wrap">
							<select name="kurs_buchungsart" id="kurs_buchungsart">
								<option value="direkt" <?php selected( $buchungsart, 'direkt' ); ?>><?php esc_html_e( 'Direkte Buchung', 'kurs-booking' ); ?></option>
								<option value="anfrage" <?php selected( $buchungsart, 'anfrage' ); ?>><?php esc_html_e( 'Anfrage (individueller Termin)', 'kurs-booking' ); ?></option>
							</select>
						</div>
						<span class="kb-hint"><?php esc_html_e( 'Anfrage = Kein fester Termin, Terminvereinbarung erforderlich', 'kurs-booking' ); ?></span>
					</div>
				</div>

				<!-- Workshop-Modus (nur bei Typ B Workshop) -->
				<?php
				$workshop_modus = get_post_meta( $post->ID, self::META_PREFIX . 'workshop_modus', true ) ?: 'vor_ort';
				?>
				<div class="kb-row kb-workshop-modus-row" <?php echo 'workshop' !== $produktart ? 'style="display:none;"' : ''; ?>>
					<label class="kb-label"><?php esc_html_e( 'Workshop-Modus', 'kurs-booking' ); ?></label>
					<input type="hidden" name="kurs_workshop_modus" id="kurs_workshop_modus" value="<?php echo esc_attr( $workshop_modus ); ?>">
					<div class="kb-type-toggle kb-workshop-toggle">
						<div class="kb-type-option <?php echo 'vor_ort' === $workshop_modus ? 'active' : ''; ?>" data-modus="vor_ort">
							<span class="dashicons dashicons-building"></span>
							<?php esc_html_e( 'Vor Ort', 'kurs-booking' ); ?>
						</div>
						<div class="kb-type-option <?php echo 'online' === $workshop_modus ? 'active' : ''; ?>" data-modus="online">
							<span class="dashicons dashicons-video-alt2"></span>
							<?php esc_html_e( 'Online', 'kurs-booking' ); ?>
						</div>
						<div class="kb-type-option <?php echo 'hybrid' === $workshop_modus ? 'active' : ''; ?>" data-modus="hybrid">
							<span class="dashicons dashicons-randomize"></span>
							<?php esc_html_e( 'Hybrid', 'kurs-booking' ); ?>
						</div>
					</div>
					<span class="kb-hint"><?php esc_html_e( 'Bestimmt ob Zoom-Felder und/oder Ort-Felder angezeigt werden', 'kurs-booking' ); ?></span>
				</div>
			</div>

			<!-- Datum & Zeit Section -->
			<div class="kb-section">
				<div class="kb-section-header">
					<div class="kb-section-icon">
						<span class="dashicons dashicons-calendar-alt"></span>
					</div>
					<h3 class="kb-section-title"><?php esc_html_e( 'Datum & Zeit', 'kurs-booking' ); ?></h3>
				</div>

				<div class="kb-grid kb-grid-4">
					<div class="kb-row">
						<label for="kurs_start_date"><?php esc_html_e( 'Startdatum', 'kurs-booking' ); ?></label>
						<input type="date" name="kurs_start_date" id="kurs_start_date" value="<?php echo esc_attr( $start_date ); ?>">
					</div>
					<div class="kb-row">
						<label for="kurs_end_date"><?php esc_html_e( 'Enddatum', 'kurs-booking' ); ?></label>
						<input type="date" name="kurs_end_date" id="kurs_end_date" value="<?php echo esc_attr( $end_date ); ?>">
						<span class="kb-hint"><?php esc_html_e( 'Leer = Eintaegig', 'kurs-booking' ); ?></span>
					</div>
					<div class="kb-row">
						<label for="kurs_start_time"><?php esc_html_e( 'Startzeit', 'kurs-booking' ); ?></label>
						<input type="time" name="kurs_start_time" id="kurs_start_time" value="<?php echo esc_attr( $start_time ); ?>">
					</div>
					<div class="kb-row">
						<label for="kurs_end_time"><?php esc_html_e( 'Endzeit', 'kurs-booking' ); ?></label>
						<input type="time" name="kurs_end_time" id="kurs_end_time" value="<?php echo esc_attr( $end_time ); ?>">
					</div>
				</div>
			</div>

			<!-- Durchfuehrungsart Section -->
			<div class="kb-section">
				<div class="kb-section-header">
					<div class="kb-section-icon">
						<span class="dashicons dashicons-location"></span>
					</div>
					<h3 class="kb-section-title"><?php esc_html_e( 'Durchfuehrungsart', 'kurs-booking' ); ?></h3>
				</div>

				<div class="kb-row">
					<label class="kb-label"><?php esc_html_e( 'Kurs-Typ', 'kurs-booking' ); ?></label>
					<input type="hidden" name="kurs_type" value="<?php echo esc_attr( $kurs_type ); ?>">
					<div class="kb-type-toggle">
						<div class="kb-type-option <?php echo 'vor_ort' === $kurs_type ? 'active' : ''; ?>" data-type="vor_ort">
							<span class="dashicons dashicons-building"></span>
							<?php esc_html_e( 'Vor Ort', 'kurs-booking' ); ?>
						</div>
						<div class="kb-type-option <?php echo 'online' === $kurs_type ? 'active' : ''; ?>" data-type="online">
							<span class="dashicons dashicons-video-alt2"></span>
							<?php esc_html_e( 'Online', 'kurs-booking' ); ?>
						</div>
						<div class="kb-type-option <?php echo 'hybrid' === $kurs_type ? 'active' : ''; ?>" data-type="hybrid">
							<span class="dashicons dashicons-randomize"></span>
							<?php esc_html_e( 'Hybrid', 'kurs-booking' ); ?>
						</div>
					</div>
				</div>

				<!-- Location Card (vor_ort, hybrid) -->
				<div class="kb-location-card kb-conditional <?php echo in_array( $kurs_type, array( 'vor_ort', 'hybrid' ), true ) ? 'kb-visible' : 'kb-hidden'; ?>">
					<div class="kb-card-header">
						<span class="kb-card-icon"><span class="dashicons dashicons-location-alt"></span></span>
						<?php esc_html_e( 'Veranstaltungsort', 'kurs-booking' ); ?>
					</div>
					<div class="kb-grid kb-grid-2">
						<div class="kb-row">
							<label for="kurs_location_select"><?php esc_html_e( 'Veranstaltungsort', 'kurs-booking' ); ?></label>
							<select name="kurs_location_select" id="kurs_location_select">
								<option value=""><?php esc_html_e( '-- Bitte auswählen --', 'kurs-booking' ); ?></option>
								<?php foreach ( $locations_list as $loc ) : ?>
									<option value="<?php echo esc_attr( $loc['name'] ); ?>"
											data-url="<?php echo esc_url( $loc['url'] ?? '' ); ?>"
											<?php selected( $location_selected, $loc['name'] ); ?>>
										<?php echo esc_html( $loc['name'] ); ?>
									</option>
								<?php endforeach; ?>
								<option value="__other__" <?php selected( $location_is_custom && ! empty( $location ) ); ?>><?php esc_html_e( 'Andere (manuell eingeben)', 'kurs-booking' ); ?></option>
							</select>
							<?php if ( empty( $locations_list ) ) : ?>
								<span class="kb-hint"><?php esc_html_e( 'Keine Veranstaltungsorte definiert. Bitte unter Einstellungen > Stammdaten anlegen.', 'kurs-booking' ); ?></span>
							<?php endif; ?>
						</div>
						<div class="kb-row">
							<label for="kurs_location_url"><?php esc_html_e( 'Webseite', 'kurs-booking' ); ?></label>
							<input type="url" name="kurs_location_url" id="kurs_location_url" value="<?php echo esc_url( $location_url ); ?>" placeholder="https://">.
							<span class="kb-hint"><?php esc_html_e( 'Wird bei Auswahl automatisch ausgefüllt', 'kurs-booking' ); ?></span>
						</div>
					</div>
					<div class="kb-row kb-location-other-row" style="<?php echo ( ! $location_is_custom || empty( $location ) ) ? 'display:none;' : ''; ?>">
						<label for="kurs_location"><?php esc_html_e( 'Adresse / Name (manuell)', 'kurs-booking' ); ?></label>
						<input type="text" name="kurs_location" id="kurs_location" value="<?php echo esc_attr( $location_is_custom ? $location : '' ); ?>" placeholder="<?php esc_attr_e( 'z.B. Kongresszentrum Wien', 'kurs-booking' ); ?>">
					</div>
					<input type="hidden" name="kurs_location_hidden" id="kurs_location_hidden" value="<?php echo esc_attr( $location ); ?>"><?php // Fallback for non-custom locations. ?>
					<div class="kb-row" style="margin-top: 15px;">
						<label for="kurs_google_maps">
							<span class="dashicons dashicons-location" style="color: #4285F4; margin-right: 4px;"></span>
							<?php esc_html_e( 'Google Maps Link', 'kurs-booking' ); ?>
						</label>
						<div class="kb-google-maps-wrap">
							<input type="url" name="kurs_google_maps" id="kurs_google_maps" value="<?php echo esc_url( $google_maps ); ?>" placeholder="https://www.google.com/maps/search/?api=1&query=..." class="large-text">.
							<button type="button" id="kb-generate-maps-link" class="button button-secondary" title="<?php esc_attr_e( 'Link aus Adresse generieren', 'kurs-booking' ); ?>">
								<span class="dashicons dashicons-update"></span>
							</button>
						</div>
						<p class="description"><?php esc_html_e( 'Wird automatisch aus der Adresse generiert oder manuell eingeben.', 'kurs-booking' ); ?></p>
					</div>
					<!-- Google Maps Preview -->
					<div class="kb-google-maps-preview" id="kb-google-maps-preview">
						<div class="kb-maps-preview-header">
							<span class="dashicons dashicons-location-alt"></span>
							<?php esc_html_e( 'Kartenvorschau', 'kurs-booking' ); ?>
						</div>
						<div class="kb-maps-preview-container">
							<?php if ( ! empty( $location ) ) : ?>
							<iframe
								id="kb-google-maps-iframe"
								src="https://www.google.com/maps?q=<?php echo rawurlencode( $location ); ?>&hl=de&z=14&output=embed".
								width="100%"
								height="250"
								style="border:0;"
								allowfullscreen=""
								loading="lazy"
								referrerpolicy="no-referrer-when-downgrade">
							</iframe>
							<?php else : ?>
							<div id="kb-maps-placeholder" class="kb-maps-placeholder">
								<span class="dashicons dashicons-location"></span>
								<p><?php esc_html_e( 'Kein Google Maps Link vorhanden.', 'kurs-booking' ); ?></p>
								<p class="kb-maps-hint"><?php esc_html_e( 'Bitte Adresse eingeben und die Generierungs-Taste (🔄) drücken.', 'kurs-booking' ); ?></p>
							</div>
							<?php endif; ?>
						</div>
					</div>
				</div>

				<!-- Online Card (online, hybrid) -->
				<div class="kb-online-card kb-conditional <?php echo in_array( $kurs_type, array( 'online', 'hybrid' ), true ) ? 'kb-visible' : 'kb-hidden'; ?>">
					<div class="kb-card-header">
						<span class="kb-card-icon"><span class="dashicons dashicons-video-alt3"></span></span>
						<?php esc_html_e( 'Online-Zugang (Zoom)', 'kurs-booking' ); ?>
					</div>
					<div class="kb-grid kb-grid-2">
						<div class="kb-row">
							<label for="kurs_zoom_link"><?php esc_html_e( 'Zoom Meeting-Link', 'kurs-booking' ); ?></label>
							<input type="url" name="kurs_zoom_link" id="kurs_zoom_link" value="<?php echo esc_url( $zoom_link ); ?>" placeholder="https://zoom.us/j/...">.
						</div>
						<div class="kb-row">
							<label for="kurs_zoom_password"><?php esc_html_e( 'Zoom-Passwort', 'kurs-booking' ); ?></label>
							<input type="text" name="kurs_zoom_password" id="kurs_zoom_password" value="<?php echo esc_attr( $zoom_pass ); ?>" placeholder="<?php esc_attr_e( 'Optional', 'kurs-booking' ); ?>">
						</div>
					</div>
					<div class="kb-info-box">
						<span class="dashicons dashicons-info"></span>
						<p><?php esc_html_e( 'Der Zoom-Link wird erst nach Buchungsbestaetigung an die Teilnehmer gesendet.', 'kurs-booking' ); ?></p>
					</div>
				</div>
			</div>

			<!-- Kursleitung Section -->
			<div class="kb-section">
				<div class="kb-section-header">
					<div class="kb-section-icon">
						<span class="dashicons dashicons-businessperson"></span>
					</div>
					<h3 class="kb-section-title"><?php esc_html_e( 'Kursleitung & Details', 'kurs-booking' ); ?></h3>
				</div>

				<div class="kb-grid kb-grid-2">
					<div class="kb-row">
						<label for="kurs_instructor"><?php esc_html_e( 'Reitlehrer/in', 'kurs-booking' ); ?></label>
						<select name="kurs_instructor" id="kurs_instructor">
							<option value=""><?php esc_html_e( '-- Bitte auswählen --', 'kurs-booking' ); ?></option>
							<?php foreach ( $instructors_list as $instr ) : ?>
								<option value="<?php echo esc_attr( $instr ); ?>" <?php selected( $instructor, $instr ); ?>>
									<?php echo esc_html( $instr ); ?>
								</option>
							<?php endforeach; ?>
						</select>
						<?php if ( empty( $instructors_list ) ) : ?>
							<span class="kb-hint"><?php esc_html_e( 'Keine Reitlehrer definiert. Bitte unter Einstellungen > Stammdaten anlegen.', 'kurs-booking' ); ?></span>
						<?php else : ?>
							<span class="kb-hint"><?php esc_html_e( 'Wird in der Buchungsbestätigung angezeigt', 'kurs-booking' ); ?></span>
						<?php endif; ?>
					</div>
					<div class="kb-row">
						<label for="kurs_horse_select"><?php esc_html_e( 'Zugeteiltes Pferd', 'kurs-booking' ); ?></label>
						<select name="kurs_horse_select" id="kurs_horse_select">
							<option value=""><?php esc_html_e( '-- Kein Pferd --', 'kurs-booking' ); ?></option>
							<?php foreach ( $horses_list as $h ) : ?>
								<option value="<?php echo esc_attr( $h ); ?>" <?php selected( $horse, $h ); ?>>
									<?php echo esc_html( $h ); ?>
								</option>
							<?php endforeach; ?>
							<option value="__other__" <?php selected( $horse_is_custom ); ?>><?php esc_html_e( 'Andere (manuell eingeben)', 'kurs-booking' ); ?></option>
						</select>
						<?php if ( empty( $horses_list ) ) : ?>
							<span class="kb-hint"><?php esc_html_e( 'Keine Pferde definiert. Bitte unter Einstellungen > Stammdaten anlegen.', 'kurs-booking' ); ?></span>
						<?php else : ?>
							<span class="kb-hint"><?php esc_html_e( 'Nur relevant für Einzelcoaching', 'kurs-booking' ); ?></span>
						<?php endif; ?>
					</div>
				</div>
				<div class="kb-row kb-horse-other-row" style="<?php echo ! $horse_is_custom ? 'display:none;' : ''; ?>">
					<label for="kurs_horse"><?php esc_html_e( 'Pferd (manuell)', 'kurs-booking' ); ?></label>
					<input type="text" name="kurs_horse" id="kurs_horse" value="<?php echo esc_attr( $horse_is_custom ? $horse : '' ); ?>" placeholder="<?php esc_attr_e( 'z.B. Stute Bella', 'kurs-booking' ); ?>">
				</div>
				<input type="hidden" name="kurs_horse_hidden" id="kurs_horse_hidden" value="<?php echo esc_attr( $horse ); ?>"><?php // Fallback. ?>

				<div class="kb-row" style="margin-top: 15px;">
					<label for="kurs_notes"><?php esc_html_e( 'Wichtige Hinweise', 'kurs-booking' ); ?></label>
					<textarea name="kurs_notes" id="kurs_notes" rows="4" class="large-text" placeholder="<?php esc_attr_e( 'Kurs-spezifische Hinweise fuer die E-Mail...', 'kurs-booking' ); ?>"><?php echo esc_textarea( $notes ); ?></textarea>
					<span class="kb-hint"><?php esc_html_e( 'Diese Hinweise werden in der Buchungsbestaetigung angezeigt (zusaetzlich zu den Standard-Hinweisen aus den Einstellungen)', 'kurs-booking' ); ?></span>
				</div>
			</div>
		</div>
		<?php
	}

	/**
	 * Render the pricing meta box
	 *
	 * @param WP_Post $post The post object.
	 */
	public static function render_pricing_meta_box( WP_Post $post ): void {
		$varianten = get_post_meta( $post->ID, self::META_PREFIX . 'varianten', true );

		// Handle different data formats.
		if ( empty( $varianten ) ) {
			$varianten = array();
		} elseif ( is_string( $varianten ) ) {
			$decoded   = json_decode( $varianten, true );
			$varianten = is_array( $decoded ) ? $decoded : array();
		} elseif ( ! is_array( $varianten ) ) {
			$varianten = array();
		}

		$max_participants = (int) get_post_meta( $post->ID, self::META_PREFIX . 'max_participants', true );

		// Default variant if empty.
		if ( empty( $varianten ) ) {
			$varianten = array(
				array(
					'id'           => 1,
					'name'         => __( 'Standardticket', 'kurs-booking' ),
					'preis'        => 0,
					'limit'        => 0,
					'per_day'      => false,
					'auto_invoice' => true,
					'hinweis'      => '',
				),
			);
		}
		?>
		<div class="kurs-meta-box">
			<!-- Tickets Section -->
			<div class="kb-section">
				<div class="kb-section-header">
					<div class="kb-section-icon">
						<span class="dashicons dashicons-tickets-alt"></span>
					</div>
					<h3 class="kb-section-title"><?php esc_html_e( 'Ticket-Varianten', 'kurs-booking' ); ?></h3>
				</div>

				<div class="kb-variants-container" id="kb-variants-container">
					<?php foreach ( $varianten as $index => $variante ) : ?>
					<div class="kb-variant" data-index="<?php echo esc_attr( (string) $index ); ?>">
						<div class="kb-variant-header">
							<div class="kb-variant-handle">
								<span class="dashicons dashicons-move"></span>
								<span class="kb-variant-number"><?php echo esc_html( (string) ( $index + 1 ) ); ?></span>
								<span class="kb-variant-title"><?php echo esc_html( $variante['name'] ?? __( 'Ticket', 'kurs-booking' ) ); ?></span>
							</div>
							<?php if ( Kurs_Booking_Settings::is_module_active( 'preisvarianten' ) ) : ?>
							<button type="button" class="kb-variant-remove">
								<span class="dashicons dashicons-trash"></span>
								<?php esc_html_e( 'Entfernen', 'kurs-booking' ); ?>
							</button>
							<?php endif; ?>
						</div>
						<div class="kb-variant-body">
							<input type="hidden" name="kurs_varianten[<?php echo esc_attr( $index ); ?>][id]" value="<?php echo esc_attr( $variante['id'] ?? $index + 1 ); ?>">
							<div class="kb-variant-grid">
								<div class="kb-field">
									<label><?php esc_html_e( 'Ticket-Name', 'kurs-booking' ); ?></label>
									<input type="text"
										   name="kurs_varianten[<?php echo esc_attr( $index ); ?>][name]"
										   class="kb-variant-name"
										   value="<?php echo esc_attr( $variante['name'] ?? '' ); ?>"
										   placeholder="<?php esc_attr_e( 'z.B. Standardticket, Fruehbucher', 'kurs-booking' ); ?>">
								</div>
								<div class="kb-field kb-price-input">
									<label><?php esc_html_e( 'Preis', 'kurs-booking' ); ?></label>
									<input type="number"
										   name="kurs_varianten[<?php echo esc_attr( $index ); ?>][preis]"
										   value="<?php echo esc_attr( $variante['preis'] ?? 0 ); ?>"
										   min="0"
										   step="0.01"
										   placeholder="0,00">
								</div>
								<div class="kb-field">
									<label><?php esc_html_e( 'Limit', 'kurs-booking' ); ?></label>
									<input type="number"
										   name="kurs_varianten[<?php echo esc_attr( $index ); ?>][limit]"
										   value="<?php echo esc_attr( $variante['limit'] ?? 0 ); ?>"
										   min="0"
										   placeholder="0">
									<span class="kb-hint"><?php esc_html_e( '0 = unbegrenzt', 'kurs-booking' ); ?></span>
								</div>
							</div>
							<div class="kb-variant-options">
								<label class="kb-checkbox-label">
									<input type="checkbox"
										   name="kurs_varianten[<?php echo esc_attr( $index ); ?>][per_day]"
										   value="1"
										   <?php checked( ! empty( $variante['per_day'] ) ); ?>>
									<?php esc_html_e( 'Pro Tag berechnen', 'kurs-booking' ); ?>
									<span class="kb-hint-inline"><?php esc_html_e( '(Preis × Kurstage)', 'kurs-booking' ); ?></span>
								</label>
								<label class="kb-checkbox-label">
									<input type="checkbox"
										   name="kurs_varianten[<?php echo esc_attr( $index ); ?>][auto_invoice]"
										   value="1"
										   <?php checked( ( $variante['auto_invoice'] ?? true ) !== false ); ?>>
									<?php esc_html_e( 'Automatisch verrechnen', 'kurs-booking' ); ?>
									<span class="kb-hint-inline"><?php esc_html_e( '(sevDesk Rechnung)', 'kurs-booking' ); ?></span>
								</label>
							</div>
							<div class="kb-variant-hint-row" style="<?php echo ( $variante['auto_invoice'] ?? true ) !== false ? 'display:none;' : ''; ?>">
								<label><?php esc_html_e( 'Hinweis', 'kurs-booking' ); ?></label>
								<input type="text"
									   name="kurs_varianten[<?php echo esc_attr( $index ); ?>][hinweis]"
									   value="<?php echo esc_attr( $variante['hinweis'] ?? '' ); ?>"
									   placeholder="<?php echo esc_attr( get_option( 'kurs_booking_manual_payment_hint', 'Wird vor Ort verrechnet' ) ); ?>"
									   class="regular-text">
								<span class="kb-hint"><?php esc_html_e( 'Leer = globaler Standard aus Einstellungen', 'kurs-booking' ); ?></span>
							</div>
							<?php
							// Sprint 4.11: Extra field UI (modular, conditional on varianten_zusatz module).
							if ( class_exists( 'Kurs_Booking_Custom_Fields' ) && Kurs_Booking_Settings::is_module_active( 'varianten_zusatz' ) ) {
								Kurs_Booking_Custom_Fields::render_variant_extra_field_ui( $variante, $index );
							}
							?>
						</div>
					</div>
					<?php endforeach; ?>
				</div>

				<?php if ( Kurs_Booking_Settings::is_module_active( 'preisvarianten' ) ) : ?>
				<button type="button" class="kb-add-variant" id="kb-add-variant">
					<span class="dashicons dashicons-plus-alt2"></span>
					<?php esc_html_e( 'Ticket-Variante hinzufuegen', 'kurs-booking' ); ?>
				</button>
				<?php endif; ?>
			</div>

			<!-- Kapazitaet Section -->
			<div class="kb-section">
				<div class="kb-section-header">
					<div class="kb-section-icon">
						<span class="dashicons dashicons-groups"></span>
					</div>
					<h3 class="kb-section-title"><?php esc_html_e( 'Kapazitaet', 'kurs-booking' ); ?></h3>
				</div>

				<div class="kb-row">
					<label for="kurs_max_participants"><?php esc_html_e( 'Maximale Teilnehmerzahl', 'kurs-booking' ); ?></label>
					<input type="number"
						   name="kurs_max_participants"
						   id="kurs_max_participants"
						   value="<?php echo esc_attr( (string) $max_participants ); ?>"
						   min="0"
						   placeholder="0"
						   style="width: 100px;">
					<span class="kb-hint"><?php esc_html_e( '0 = unbegrenzt. Ticket-spezifische Limits gelten zusaetzlich.', 'kurs-booking' ); ?></span>
				</div>

				<div class="kb-info-box">
					<span class="dashicons dashicons-info"></span>
					<p><?php esc_html_e( 'Die Gesamtkapazitaet begrenzt alle Buchungen zusammen. Einzelne Ticket-Limits koennen darunter liegen.', 'kurs-booking' ); ?></p>
				</div>
			</div>
		</div>
		<?php
	}

	/**
	 * Render the booking options meta box
	 *
	 * @param WP_Post $post The post object.
	 */
	public static function render_booking_meta_box( WP_Post $post ): void {
		$booking_enabled = get_post_meta( $post->ID, self::META_PREFIX . 'booking_enabled', true );
		$booking_enabled = '' === $booking_enabled ? '1' : $booking_enabled;
		$abrechnung      = get_post_meta( $post->ID, self::META_PREFIX . 'abrechnung', true ) ?: 'eigen';
		$deposit_enabled = get_post_meta( $post->ID, self::META_PREFIX . 'deposit_enabled', true );
		$deposit_percent = get_post_meta( $post->ID, self::META_PREFIX . 'deposit_percent', true ) ?: 30;
		?>
		<div class="kurs-meta-box">
			<!-- Buchung Status -->
			<div class="kb-sidebar-section">
				<label class="kb-toggle" id="kb-booking-toggle">
					<input type="checkbox" name="kurs_booking_enabled" value="1" <?php checked( $booking_enabled, '1' ); ?>>
					<span class="kb-toggle-label">
						<span class="dashicons dashicons-cart"></span>
						<?php esc_html_e( 'Buchung', 'kurs-booking' ); ?>
					</span>
					<span class="kb-toggle-switch"></span>
				</label>
				<div style="text-align: center; margin-top: 12px;">
					<span id="kb-booking-status" class="kb-status <?php echo '1' === $booking_enabled ? 'kb-status-active' : 'kb-status-inactive'; ?>">
						<?php if ( '1' === $booking_enabled ) : ?>
							<span class="dashicons dashicons-yes-alt"></span> <?php esc_html_e( 'Aktiv', 'kurs-booking' ); ?>
						<?php else : ?>
							<span class="dashicons dashicons-minus"></span> <?php esc_html_e( 'Inaktiv', 'kurs-booking' ); ?>
						<?php endif; ?>
					</span>
				</div>
			</div>

			<!-- Abrechnung -->
			<div class="kb-sidebar-section">
				<div class="kb-row">
					<label for="kurs_abrechnung">
						<span class="dashicons dashicons-money-alt" style="color: var(--kb-primary); margin-right: 4px;"></span>
						<?php esc_html_e( 'Abrechnung', 'kurs-booking' ); ?>
					</label>
					<select name="kurs_abrechnung" id="kurs_abrechnung" class="kb-sidebar-select">
						<option value="eigen" <?php selected( $abrechnung, 'eigen' ); ?>><?php esc_html_e( 'Eigene Rechnung', 'kurs-booking' ); ?></option>
						<option value="partner" <?php selected( $abrechnung, 'partner' ); ?>><?php esc_html_e( 'Partner kassiert', 'kurs-booking' ); ?></option>
					</select>
					<span class="kb-hint"><?php esc_html_e( 'Partner = keine Rechnung', 'kurs-booking' ); ?></span>
				</div>
			</div>

			<!-- Anzahlung (nur bei eigen) -->
			<div class="kb-sidebar-section kb-deposit-wrapper" <?php echo 'partner' === $abrechnung ? 'style="display:none;"' : ''; ?>>
				<div class="kb-row">
					<label>
						<input type="checkbox" name="kurs_deposit_enabled" value="1" <?php checked( $deposit_enabled, '1' ); ?> id="kurs_deposit_enabled">
						<span class="dashicons dashicons-bank" style="color: var(--kb-warning); margin-right: 4px;"></span>
						<?php esc_html_e( 'Anzahlung aktivieren', 'kurs-booking' ); ?>
					</label>
				</div>

				<div class="kb-deposit-details" <?php echo '1' !== $deposit_enabled ? 'style="display:none;"' : ''; ?>>
					<div class="kb-deposit-section">
						<div class="kb-deposit-header">
							<span class="dashicons dashicons-info-outline"></span>
							<?php esc_html_e( 'Anzahlung', 'kurs-booking' ); ?>
						</div>
						<div class="kb-deposit-input">
							<input type="number"
								   name="kurs_deposit_percent"
								   id="kurs_deposit_percent"
								   value="<?php echo esc_attr( $deposit_percent ); ?>"
								   min="1"
								   max="100">
							<span>%</span>
						</div>
						<span class="kb-hint" style="display: block; margin-top: 8px;">
							<?php esc_html_e( 'Restzahlung vor Kursbeginn', 'kurs-booking' ); ?>
						</span>
					</div>
				</div>
			</div>

			<!-- Vorlage (conditional module) -->
			<?php if ( Kurs_Booking_Settings::is_module_active( 'kurs_vorlagen' ) ) : ?>
				<?php $is_template = get_post_meta( $post->ID, self::META_PREFIX . 'is_template', true ); ?>
				<div class="kb-sidebar-section" style="border-top: 1px solid #dcdcde; padding-top: 12px; margin-top: 12px;">
					<label class="kb-toggle">
						<input type="checkbox" name="kurs_is_template" value="1" <?php checked( $is_template, '1' ); ?>>
						<span class="kb-toggle-label">
							<span class="dashicons dashicons-clipboard"></span>
							<?php esc_html_e( 'Vorlage', 'kurs-booking' ); ?>
						</span>
						<span class="kb-toggle-switch"></span>
					</label>
					<span class="kb-hint" style="display: block; margin-top: 8px; text-align: center;">
						<?php esc_html_e( 'Als Vorlage für neue Kurse', 'kurs-booking' ); ?>
					</span>
				</div>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Save meta box data
	 *
	 * @param int     $post_id The post ID.
	 * @param WP_Post $post    The post object.
	 */
	public static function save_meta( int $post_id, WP_Post $post ): void {
		// Verify nonce.
		if ( ! isset( $_POST['kurs_booking_nonce'] ) ||
			 ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['kurs_booking_nonce'] ) ), 'kurs_booking_save_meta' ) ) {
			return;
		}

		// Check autosave.
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}

		// Check permissions.
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}

		// Define fields to save.
		$text_fields = array(
			'produktart',
			'buchungsart',
			'workshop_modus',
			'start_date',
			'end_date',
			'start_time',
			'end_time',
			'type',
			'location',
			'zoom_password',
			'abrechnung',
			'instructor',
			'horse',
		);

		$textarea_fields = array(
			'notes',
		);

		$url_fields = array(
			'location_url',
			'google_maps',
			'zoom_link',
		);

		$int_fields = array(
			'max_participants',
			'deposit_percent',
			'video_access_days',
		);

		$checkbox_fields = array(
			'booking_enabled',
			'deposit_enabled',
			'is_template',
		);

		// Save text fields.
		foreach ( $text_fields as $field ) {
			$key   = 'kurs_' . $field;
			$value = isset( $_POST[ $key ] ) ? sanitize_text_field( wp_unslash( $_POST[ $key ] ) ) : '';
			update_post_meta( $post_id, self::META_PREFIX . $field, $value );
		}

		// Special handling for location dropdown.
		if ( isset( $_POST['kurs_location_select'] ) ) {
			$location_select = sanitize_text_field( wp_unslash( $_POST['kurs_location_select'] ) );
			if ( '__other__' === $location_select ) {
				// Use manual input.
				$location = isset( $_POST['kurs_location'] ) ? sanitize_text_field( wp_unslash( $_POST['kurs_location'] ) ) : '';
			} elseif ( ! empty( $location_select ) ) {
				// Use dropdown value.
				$location = $location_select;
			} else {
				$location = '';
			}
			update_post_meta( $post_id, self::META_PREFIX . 'location', $location );
		}

		// Special handling for horse dropdown.
		if ( isset( $_POST['kurs_horse_select'] ) ) {
			$horse_select = sanitize_text_field( wp_unslash( $_POST['kurs_horse_select'] ) );
			if ( '__other__' === $horse_select ) {
				// Use manual input.
				$horse = isset( $_POST['kurs_horse'] ) ? sanitize_text_field( wp_unslash( $_POST['kurs_horse'] ) ) : '';
			} elseif ( ! empty( $horse_select ) ) {
				// Use dropdown value.
				$horse = $horse_select;
			} else {
				$horse = '';
			}
			update_post_meta( $post_id, self::META_PREFIX . 'horse', $horse );
		}

		// Save textarea fields.
		foreach ( $textarea_fields as $field ) {
			$key   = 'kurs_' . $field;
			$value = isset( $_POST[ $key ] ) ? sanitize_textarea_field( wp_unslash( $_POST[ $key ] ) ) : '';
			update_post_meta( $post_id, self::META_PREFIX . $field, $value );
		}

		// Save URL fields.
		foreach ( $url_fields as $field ) {
			$key   = 'kurs_' . $field;
			$value = isset( $_POST[ $key ] ) ? esc_url_raw( wp_unslash( $_POST[ $key ] ) ) : '';
			update_post_meta( $post_id, self::META_PREFIX . $field, $value );
		}

		// Save integer fields.
		foreach ( $int_fields as $field ) {
			$key   = 'kurs_' . $field;
			$value = isset( $_POST[ $key ] ) ? absint( $_POST[ $key ] ) : 0;
			update_post_meta( $post_id, self::META_PREFIX . $field, $value );
		}

		// Save checkbox fields.
		foreach ( $checkbox_fields as $field ) {
			$key   = 'kurs_' . $field;
			$value = isset( $_POST[ $key ] ) ? '1' : '0';
			update_post_meta( $post_id, self::META_PREFIX . $field, $value );
		}

		// Save varianten (price variants).
		if ( isset( $_POST['kurs_varianten'] ) && is_array( $_POST['kurs_varianten'] ) ) {
			$varianten = array();
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in loop below via absint(), sanitize_text_field(), floatval().
			foreach ( wp_unslash( $_POST['kurs_varianten'] ) as $variante ) {
				$sanitized_variant = array(
					'id'           => absint( $variante['id'] ?? 0 ),
					'name'         => sanitize_text_field( $variante['name'] ?? '' ),
					'preis'        => floatval( $variante['preis'] ?? 0 ),
					'limit'        => absint( $variante['limit'] ?? 0 ),
					'per_day'      => ! empty( $variante['per_day'] ),
					'auto_invoice' => ! empty( $variante['auto_invoice'] ),
					'hinweis'      => sanitize_text_field( $variante['hinweis'] ?? '' ),
				);

				// Sprint 4.11: Allow modules to add extra fields to variants.
				$sanitized_variant = apply_filters( 'kurs_booking_sanitize_variant', $sanitized_variant, $variante );

				$varianten[] = $sanitized_variant;
			}
			// Re-index array to ensure sequential IDs.
			foreach ( $varianten as $index => &$v ) {
				$v['id'] = $index + 1;
			}
			update_post_meta( $post_id, self::META_PREFIX . 'varianten', wp_json_encode( $varianten ) );
		}

		// Save video IDs (array of integers).
		if ( isset( $_POST['kurs_video_ids'] ) && is_array( $_POST['kurs_video_ids'] ) ) {
			$video_ids = array_map( 'absint', $_POST['kurs_video_ids'] );
			$video_ids = array_filter( $video_ids ); // Remove zeros.
			update_post_meta( $post_id, self::META_PREFIX . 'video_ids', $video_ids );
		} else {
			// No videos selected - save empty array.
			update_post_meta( $post_id, self::META_PREFIX . 'video_ids', array() );
		}

		// Save related kurse settings (separate nonce).
		if ( isset( $_POST['kurs_related_nonce'] ) &&
			 wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['kurs_related_nonce'] ) ), 'kurs_related_nonce' ) ) {

			// Save related mode (auto or manual).
			$related_mode = isset( $_POST['kurs_related_mode'] ) ? sanitize_key( $_POST['kurs_related_mode'] ) : 'auto';
			update_post_meta( $post_id, self::META_PREFIX . 'related_mode', $related_mode );

			// Save related IDs (only if manual mode).
			if ( 'manual' === $related_mode && isset( $_POST['kurs_related_ids'] ) && is_array( $_POST['kurs_related_ids'] ) ) {
				$related_ids = array_map( 'absint', $_POST['kurs_related_ids'] );
				$related_ids = array_filter( $related_ids );
				$related_ids = array_slice( $related_ids, 0, 6 ); // Max 6 related kurse.
				update_post_meta( $post_id, self::META_PREFIX . 'related_ids', $related_ids );
			} elseif ( 'auto' === $related_mode ) {
				// Clear manual selection when switching to auto.
				delete_post_meta( $post_id, self::META_PREFIX . 'related_ids' );
			}
		}
	}

	/**
	 * Get meta value for a kurs
	 *
	 * @param int    $post_id The post ID.
	 * @param string $key     The meta key (without prefix).
	 * @param mixed  $default The default value.
	 * @return mixed
	 */
	public static function get_meta( int $post_id, string $key, mixed $default = '' ): mixed {
		$value = get_post_meta( $post_id, self::META_PREFIX . $key, true );
		return '' !== $value ? $value : $default;
	}

	/**
	 * Get all price variants for a kurs.
	 *
	 * @param int $post_id The post ID.
	 * @return array<int, array<string, mixed>> Price variants.
	 */
	public static function get_varianten( int $post_id ): array {
		$varianten = get_post_meta( $post_id, self::META_PREFIX . 'varianten', true );

		// Handle different data formats.
		if ( empty( $varianten ) ) {
			return array();
		}

		// Already an array (from update_post_meta with array value).
		if ( is_array( $varianten ) ) {
			return $varianten;
		}

		// JSON string (legacy format).
		if ( is_string( $varianten ) ) {
			$decoded = json_decode( $varianten, true );
			return is_array( $decoded ) ? $decoded : array();
		}

		return array();
	}

	/**
	 * Check if booking is enabled for a kurs
	 *
	 * @param int $post_id The post ID.
	 * @return bool
	 */
	public static function is_booking_enabled( int $post_id ): bool {
		return '1' === self::get_meta( $post_id, 'booking_enabled', '1' );
	}

	/**
	 * Get available spots for a kurs
	 *
	 * @param int $post_id The post ID.
	 * @return int -1 for unlimited, 0+ for actual spots.
	 */
	public static function get_available_spots( int $post_id ): int {
		$max = (int) self::get_meta( $post_id, 'max_participants', 0 );

		if ( 0 === $max ) {
			return -1; // Unlimited.
		}

		// Count confirmed bookings.
		$booked = Kurs_Booking_Buchung::count_confirmed_bookings( $post_id );

		return max( 0, $max - $booked );
	}

	/**
	 * Get total bookings count for a kurs
	 *
	 * Used by frontend and AJAX handlers.
	 *
	 * @param int $kurs_id The kurs post ID.
	 * @return int Total number of booked tickets (confirmed only).
	 */
	public static function get_bookings_count( int $kurs_id ): int {
		return Kurs_Booking_Buchung::count_confirmed_bookings( $kurs_id );
	}

	/**
	 * Get bookings count for a specific variant
	 *
	 * @param int $kurs_id    The kurs post ID.
	 * @param int $variant_id The variant ID.
	 * @return int Number of booked tickets for this variant.
	 */
	public static function get_variant_bookings_count( int $kurs_id, int $variant_id ): int {
		return Kurs_Booking_Buchung::count_variant_bookings( $kurs_id, $variant_id );
	}

	/**
	 * Render the video assignment meta box
	 *
	 * @param WP_Post $post The post object.
	 */
	public static function render_video_meta_box( WP_Post $post ): void {
		$produktart        = get_post_meta( $post->ID, self::META_PREFIX . 'produktart', true ) ?: 'kurs';
		$video_ids         = get_post_meta( $post->ID, self::META_PREFIX . 'video_ids', true );
		$video_ids         = is_array( $video_ids ) ? $video_ids : array();
		$video_access_days = (int) get_post_meta( $post->ID, self::META_PREFIX . 'video_access_days', true );

		// Get all published videos.
		$videos = get_posts(
			array(
				'post_type'      => 'kurs-video',
				'post_status'    => 'publish',
				'posts_per_page' => -1,
				'orderby'        => 'title',
				'order'          => 'ASC',
			)
		);

		// Hide this metabox for non-video product types via inline style.
		$hide_class = ( 'videokurs' !== $produktart && 'webinar' !== $produktart ) ? 'kb-video-metabox-hidden' : '';
		?>
		<div class="kurs-meta-box kb-video-metabox <?php echo esc_attr( $hide_class ); ?>" id="kb-video-metabox">
			<style>
				.kb-video-metabox-hidden { display: none !important; }
				#kurs_video_zuordnung.kb-video-metabox-hidden { display: none !important; }
			</style>

			<div class="kb-section">
				<div class="kb-section-header">
					<div class="kb-section-icon">
						<span class="dashicons dashicons-video-alt3"></span>
					</div>
					<h3 class="kb-section-title"><?php esc_html_e( 'Videos zuordnen', 'kurs-booking' ); ?></h3>
				</div>

				<?php if ( empty( $videos ) ) : ?>
					<div class="kb-info-box kb-info-warning">
						<span class="dashicons dashicons-warning"></span>
						<p>
							<?php esc_html_e( 'Keine Videos vorhanden.', 'kurs-booking' ); ?>
							<a href="<?php echo esc_url( admin_url( 'post-new.php?post_type=kurs-video' ) ); ?>">
								<?php esc_html_e( 'Video erstellen', 'kurs-booking' ); ?>
							</a>
						</p>
					</div>
				<?php else : ?>
					<div class="kb-video-select-container">
						<div class="kb-video-list">
							<?php
							foreach ( $videos as $video ) :
								$video_status   = get_post_meta( $video->ID, '_video_status', true );
								$video_duration = (int) get_post_meta( $video->ID, '_video_duration', true );
								$is_checked     = in_array( $video->ID, $video_ids, true );
								$status_class   = 'ready' === $video_status ? 'kb-video-ready' : 'kb-video-processing';
								?>
								<label class="kb-video-item <?php echo esc_attr( $status_class ); ?>">
									<input type="checkbox"
										   name="kurs_video_ids[]"
										   value="<?php echo esc_attr( (string) $video->ID ); ?>"
										   <?php checked( $is_checked ); ?>>
									<span class="kb-video-item-content">
										<span class="kb-video-title"><?php echo esc_html( $video->post_title ); ?></span>
										<span class="kb-video-meta">
											<?php if ( $video_duration > 0 ) : ?>
												<span class="kb-video-duration">
													<span class="dashicons dashicons-clock"></span>
													<?php echo esc_html( gmdate( 'H:i:s', $video_duration ) ); ?>
												</span>
											<?php endif; ?>
											<span class="kb-video-status kb-status-<?php echo esc_attr( $video_status ?: 'pending' ); ?>">
												<?php
												$status_labels = array(
													'pending'    => __( 'Ausstehend', 'kurs-booking' ),
													'processing' => __( 'Verarbeitung', 'kurs-booking' ),
													'ready'      => __( 'Bereit', 'kurs-booking' ),
													'error'      => __( 'Fehler', 'kurs-booking' ),
												);
												echo esc_html( $status_labels[ $video_status ] ?? __( 'Unbekannt', 'kurs-booking' ) );
												?>
											</span>
										</span>
									</span>
								</label>
							<?php endforeach; ?>
						</div>
					</div>

					<p class="kb-hint" style="margin-top: 15px;">
						<?php esc_html_e( 'Waehlen Sie die Videos aus, die zu diesem Kurs/Produkt gehoeren.', 'kurs-booking' ); ?>
					</p>
				<?php endif; ?>
			</div>

			<!-- Video-Kurs spezifische Felder -->
			<div class="kb-section kb-videokurs-only" id="kb-videokurs-fields" <?php echo 'videokurs' !== $produktart ? 'style="display:none;"' : ''; ?>>
				<div class="kb-section-header">
					<div class="kb-section-icon">
						<span class="dashicons dashicons-admin-settings"></span>
					</div>
					<h3 class="kb-section-title"><?php esc_html_e( 'Video-Kurs Einstellungen', 'kurs-booking' ); ?></h3>
				</div>

				<div class="kb-grid kb-grid-2">
					<div class="kb-row">
						<label for="kurs_video_access_days"><?php esc_html_e( 'Zugangs-Dauer (Tage)', 'kurs-booking' ); ?></label>
						<input type="number"
							   name="kurs_video_access_days"
							   id="kurs_video_access_days"
							   value="<?php echo esc_attr( (string) $video_access_days ); ?>"
							   min="0"
							   placeholder="0"
							   style="width: 100px;">
						<span class="kb-hint"><?php esc_html_e( '0 = Unbegrenzter Zugang', 'kurs-booking' ); ?></span>
					</div>

					<div class="kb-row">
						<div class="kb-info-box">
							<span class="dashicons dashicons-info"></span>
							<div>
								<strong><?php esc_html_e( 'Video-Kurs Info', 'kurs-booking' ); ?></strong>
								<ul style="margin: 5px 0 0 20px; padding: 0;">
									<li><?php esc_html_e( 'Kein Termin erforderlich', 'kurs-booking' ); ?></li>
									<li><?php esc_html_e( 'Sofort nach Buchung verfuegbar', 'kurs-booking' ); ?></li>
									<li><?php esc_html_e( 'Digitales Produkt (kein Widerruf)', 'kurs-booking' ); ?></li>
								</ul>
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>

		<style>
			.kb-video-list {
				display: flex;
				flex-direction: column;
				gap: 8px;
				max-height: 300px;
				overflow-y: auto;
				padding: 10px;
				background: #f9f9f9;
				border-radius: 4px;
			}
			.kb-video-item {
				display: flex;
				align-items: center;
				gap: 10px;
				padding: 10px 12px;
				background: #fff;
				border: 1px solid #dcdcde;
				border-radius: 4px;
				cursor: pointer;
				transition: all 0.2s ease;
			}
			.kb-video-item:hover {
				border-color: var(--kb-primary, #2271b1);
				background: #f0f7fc;
			}
			.kb-video-item input[type="checkbox"] {
				margin: 0;
			}
			.kb-video-item-content {
				display: flex;
				flex-direction: column;
				gap: 4px;
				flex: 1;
			}
			.kb-video-title {
				font-weight: 500;
			}
			.kb-video-meta {
				display: flex;
				gap: 15px;
				font-size: 12px;
				color: #666;
			}
			.kb-video-duration .dashicons {
				font-size: 14px;
				width: 14px;
				height: 14px;
				vertical-align: middle;
			}
			.kb-video-status {
				padding: 2px 8px;
				border-radius: 3px;
				font-size: 11px;
				font-weight: 500;
			}
			.kb-status-ready { background: #d4edda; color: #155724; }
			.kb-status-processing { background: #fff3cd; color: #856404; }
			.kb-status-pending { background: #e2e3e5; color: #383d41; }
			.kb-status-error { background: #f8d7da; color: #721c24; }
			.kb-info-warning {
				background: #fff8e5;
				border-left-color: #996800;
			}
			.kb-info-warning .dashicons { color: #996800; }
		</style>
		<?php
	}

	/**
	 * Render the related kurse meta box.
	 *
	 * @param WP_Post $post The post object.
	 */
	public static function render_related_meta_box( WP_Post $post ): void {
		$related_mode  = get_post_meta( $post->ID, self::META_PREFIX . 'related_mode', true ) ?: 'auto';
		$related_ids   = get_post_meta( $post->ID, self::META_PREFIX . 'related_ids', true );
		$related_ids   = is_array( $related_ids ) ? $related_ids : array();

		// Get all other kurse for selection.
		$kurse = get_posts(
			array(
				'post_type'      => self::POST_TYPE,
				'post_status'    => 'publish',
				'posts_per_page' => -1,
				'exclude'        => array( $post->ID ),
				'orderby'        => 'title',
				'order'          => 'ASC',
			)
		);

		wp_nonce_field( 'kurs_related_nonce', 'kurs_related_nonce' );
		?>
		<div class="kurs-meta-box kb-related-metabox">
			<div class="kb-section">
				<div class="kb-related-mode">
					<label class="kb-radio-card <?php echo 'auto' === $related_mode ? 'kb-radio-card--active' : ''; ?>">
						<input type="radio"
							   name="kurs_related_mode"
							   value="auto"
							   <?php checked( $related_mode, 'auto' ); ?>>
						<span class="kb-radio-card__icon dashicons dashicons-randomize"></span>
						<span class="kb-radio-card__content">
							<strong><?php esc_html_e( 'Automatisch', 'kurs-booking' ); ?></strong>
							<span class="kb-radio-card__desc"><?php esc_html_e( 'Basierend auf Kategorie', 'kurs-booking' ); ?></span>
						</span>
					</label>

					<label class="kb-radio-card <?php echo 'manual' === $related_mode ? 'kb-radio-card--active' : ''; ?>">
						<input type="radio"
							   name="kurs_related_mode"
							   value="manual"
							   <?php checked( $related_mode, 'manual' ); ?>>
						<span class="kb-radio-card__icon dashicons dashicons-edit"></span>
						<span class="kb-radio-card__content">
							<strong><?php esc_html_e( 'Manuell auswählen', 'kurs-booking' ); ?></strong>
							<span class="kb-radio-card__desc"><?php esc_html_e( 'Kurse selbst bestimmen', 'kurs-booking' ); ?></span>
						</span>
					</label>
				</div>

				<div class="kb-related-manual" id="kb-related-manual" <?php echo 'manual' !== $related_mode ? 'style="display:none;"' : ''; ?>>
					<div class="kb-related-search">
						<input type="text"
							   id="kb-related-search-input"
							   class="kb-search-input"
							   placeholder="<?php esc_attr_e( 'Kurs suchen...', 'kurs-booking' ); ?>">
					</div>

					<div class="kb-related-selected" id="kb-related-selected">
						<?php if ( ! empty( $related_ids ) ) : ?>
							<?php
							foreach ( $related_ids as $related_id ) :
								$related_kurs = get_post( $related_id );
								if ( ! $related_kurs ) {
									continue;
								}
								?>
								<div class="kb-related-item" data-id="<?php echo esc_attr( $related_id ); ?>">
									<input type="hidden" name="kurs_related_ids[]" value="<?php echo esc_attr( $related_id ); ?>">
									<span class="kb-related-item__title"><?php echo esc_html( $related_kurs->post_title ); ?></span>
									<button type="button" class="kb-related-item__remove" title="<?php esc_attr_e( 'Entfernen', 'kurs-booking' ); ?>">
										<span class="dashicons dashicons-no-alt"></span>
									</button>
								</div>
							<?php endforeach; ?>
						<?php endif; ?>
					</div>

					<div class="kb-related-available" id="kb-related-available">
						<?php
						foreach ( $kurse as $kurs ) :
							$is_selected = in_array( $kurs->ID, $related_ids, true );
							$produktart  = get_post_meta( $kurs->ID, self::META_PREFIX . 'produktart', true ) ?: 'kurs';
							?>
							<div class="kb-related-option <?php echo $is_selected ? 'kb-related-option--selected' : ''; ?>"
								 data-id="<?php echo esc_attr( (string) $kurs->ID ); ?>"
								 data-title="<?php echo esc_attr( $kurs->post_title ); ?>">
								<span class="kb-related-option__title"><?php echo esc_html( $kurs->post_title ); ?></span>
								<span class="kb-related-option__type"><?php echo esc_html( ucfirst( $produktart ) ); ?></span>
							</div>
						<?php endforeach; ?>
					</div>

					<p class="kb-hint">
						<?php esc_html_e( 'Klicken Sie auf einen Kurs, um ihn hinzuzufügen. Max. 3 werden angezeigt.', 'kurs-booking' ); ?>
					</p>
				</div>
			</div>
		</div>

		<style>
			.kb-related-mode {
				display: flex;
				gap: 12px;
				margin-bottom: 20px;
			}
			.kb-radio-card {
				flex: 1;
				display: flex;
				align-items: center;
				gap: 12px;
				padding: 15px;
				border: 2px solid #ddd;
				border-radius: 8px;
				cursor: pointer;
				transition: all 0.2s;
				background: #fff;
			}
			.kb-radio-card:hover {
				border-color: #2271b1;
				background: #f0f6fc;
			}
			.kb-radio-card--active {
				border-color: #2271b1;
				background: #f0f6fc;
			}
			.kb-radio-card input[type="radio"] {
				display: none;
			}
			.kb-radio-card__icon {
				font-size: 24px;
				color: #2271b1;
			}
			.kb-radio-card__content {
				display: flex;
				flex-direction: column;
			}
			.kb-radio-card__desc {
				font-size: 12px;
				color: #666;
			}
			.kb-related-search {
				margin-bottom: 12px;
			}
			.kb-search-input {
				width: 100%;
				padding: 10px 12px;
				border: 1px solid #ddd;
				border-radius: 6px;
				font-size: 14px;
			}
			.kb-related-selected {
				display: flex;
				flex-wrap: wrap;
				gap: 8px;
				margin-bottom: 12px;
				min-height: 40px;
				padding: 10px;
				background: #f0f6fc;
				border-radius: 6px;
				border: 1px dashed #2271b1;
			}
			.kb-related-selected:empty::before {
				content: 'Keine Kurse ausgewählt';
				color: #666;
				font-style: italic;
			}
			.kb-related-item {
				display: inline-flex;
				align-items: center;
				gap: 8px;
				padding: 6px 10px;
				background: #2271b1;
				color: #fff;
				border-radius: 4px;
				font-size: 13px;
			}
			.kb-related-item__remove {
				background: none;
				border: none;
				color: #fff;
				cursor: pointer;
				padding: 0;
				line-height: 1;
				opacity: 0.8;
			}
			.kb-related-item__remove:hover {
				opacity: 1;
			}
			.kb-related-item__remove .dashicons {
				font-size: 16px;
				width: 16px;
				height: 16px;
			}
			.kb-related-available {
				max-height: 200px;
				overflow-y: auto;
				border: 1px solid #ddd;
				border-radius: 6px;
				background: #fff;
			}
			.kb-related-option {
				display: flex;
				justify-content: space-between;
				align-items: center;
				padding: 10px 12px;
				cursor: pointer;
				border-bottom: 1px solid #eee;
				transition: background 0.15s;
			}
			.kb-related-option:last-child {
				border-bottom: none;
			}
			.kb-related-option:hover {
				background: #f0f6fc;
			}
			.kb-related-option--selected {
				display: none;
			}
			.kb-related-option--hidden {
				display: none;
			}
			.kb-related-option__type {
				font-size: 11px;
				color: #666;
				background: #f0f0f0;
				padding: 2px 8px;
				border-radius: 3px;
			}
		</style>

		<script>
		jQuery(document).ready(function($) {
			// Toggle manual section.
			$('input[name="kurs_related_mode"]').on('change', function() {
				var mode = $(this).val();
				$('#kb-related-manual').toggle(mode === 'manual');
				$('.kb-radio-card').removeClass('kb-radio-card--active');
				$(this).closest('.kb-radio-card').addClass('kb-radio-card--active');
			});

			// Search filter.
			$('#kb-related-search-input').on('input', function() {
				var search = $(this).val().toLowerCase();
				$('.kb-related-option').each(function() {
					var title = $(this).data('title').toLowerCase();
					var isMatch = title.indexOf(search) !== -1;
					var isSelected = $(this).hasClass('kb-related-option--selected');
					$(this).toggleClass('kb-related-option--hidden', !isMatch && !isSelected);
				});
			});

			// Add kurs.
			$(document).on('click', '.kb-related-option:not(.kb-related-option--selected)', function() {
				var $option = $(this);
				var id = $option.data('id');
				var title = $option.data('title');

				// Create selected item.
				var $item = $('<div class="kb-related-item" data-id="' + id + '">' +
					'<input type="hidden" name="kurs_related_ids[]" value="' + id + '">' +
					'<span class="kb-related-item__title">' + title + '</span>' +
					'<button type="button" class="kb-related-item__remove" title="Entfernen">' +
					'<span class="dashicons dashicons-no-alt"></span></button></div>');

				$('#kb-related-selected').append($item);
				$option.addClass('kb-related-option--selected');
			});

			// Remove kurs.
			$(document).on('click', '.kb-related-item__remove', function() {
				var $item = $(this).closest('.kb-related-item');
				var id = $item.data('id');

				$item.remove();
				$('.kb-related-option[data-id="' + id + '"]').removeClass('kb-related-option--selected');
			});
		});
		</script>
		<?php
	}

	/**
	 * Check if a kurs is a digital product (Video-Kurs)
	 *
	 * @param int $post_id The post ID.
	 * @return bool
	 */
	public static function is_digital_product( int $post_id ): bool {
		$produktart = self::get_meta( $post_id, 'produktart', 'kurs' );
		return 'videokurs' === $produktart;
	}

	/**
	 * Get video IDs assigned to a kurs.
	 *
	 * @param int $post_id The post ID.
	 * @return array<int, int> Video IDs.
	 */
	public static function get_video_ids( int $post_id ): array {
		$video_ids = get_post_meta( $post_id, self::META_PREFIX . 'video_ids', true );
		return is_array( $video_ids ) ? $video_ids : array();
	}

	/**
	 * Get video access duration in days
	 *
	 * @param int $post_id The post ID.
	 * @return int 0 = unlimited
	 */
	public static function get_video_access_days( int $post_id ): int {
		return (int) self::get_meta( $post_id, 'video_access_days', 0 );
	}

	/**
	 * Get the number of course days
	 *
	 * Calculates the number of days between start and end date (inclusive).
	 * Returns 1 for single-day courses (no end date or same as start).
	 *
	 * @param int $post_id The post ID.
	 * @return int Number of days (minimum 1).
	 */
	public static function get_course_days( int $post_id ): int {
		$start_date = self::get_meta( $post_id, 'start_date', '' );
		$end_date   = self::get_meta( $post_id, 'end_date', '' );

		// No start date - return 1 day.
		if ( empty( $start_date ) ) {
			return 1;
		}

		// No end date or same as start - single day course.
		if ( empty( $end_date ) || $end_date === $start_date ) {
			return 1;
		}

		// Calculate difference.
		try {
			$start = new DateTime( $start_date );
			$end   = new DateTime( $end_date );
			$diff  = $start->diff( $end );

			// Return days + 1 (inclusive of both start and end day).
			return max( 1, $diff->days + 1 );
		} catch ( Exception $e ) {
			return 1;
		}
	}

	/**
	 * Calculate total price for a variant considering per_day option.
	 *
	 * @param array<string, mixed> $variante  The variant data.
	 * @param int                  $kurs_id   The kurs post ID.
	 * @param int                  $quantity  The quantity (default 1).
	 * @return float The calculated total price.
	 */
	public static function calculate_variant_price( array $variante, int $kurs_id, int $quantity = 1 ): float {
		$base_price = (float) ( $variante['preis'] ?? 0 );
		$per_day    = ! empty( $variante['per_day'] );

		if ( $per_day ) {
			$days = self::get_course_days( $kurs_id );
			return $base_price * $days * $quantity;
		}

		return $base_price * $quantity;
	}

	/**
	 * Get the hint text for a variant.
	 *
	 * Returns the variant-specific hint or the global default.
	 *
	 * @param array<string, mixed> $variante The variant data.
	 * @return string The hint text (empty if auto_invoice is true).
	 */
	public static function get_variant_hint( array $variante ): string {
		// Only return hint if not auto-invoiced.
		$auto_invoice = $variante['auto_invoice'] ?? true;
		if ( $auto_invoice ) {
			return '';
		}

		// Return variant-specific hint or global default.
		$hint = $variante['hinweis'] ?? '';
		if ( empty( $hint ) ) {
			$hint = get_option( 'kurs_booking_manual_payment_hint', 'Wird vor Ort verrechnet' );
		}

		return $hint;
	}

	/**
	 * Get related kurse based on category or produktart.
	 *
	 * @param int $kurs_id Current kurs ID to exclude.
	 * @param int $limit   Maximum number of related kurse to return.
	 * @return array<int, WP_Post> Array of WP_Post objects.
	 */
	public static function get_related_kurse( int $kurs_id, int $limit = 3 ): array {
		// Check if manual selection is enabled.
		$related_mode = self::get_meta( $kurs_id, 'related_mode', 'auto' );

		if ( 'manual' === $related_mode ) {
			// Get manually selected kurse.
			$related_ids = get_post_meta( $kurs_id, self::META_PREFIX . 'related_ids', true );
			if ( ! empty( $related_ids ) && is_array( $related_ids ) ) {
				$related_ids = array_slice( $related_ids, 0, $limit );
				$related = get_posts(
					array(
						'post_type'      => self::POST_TYPE,
						'post_status'    => 'publish',
						'post__in'       => $related_ids,
						'orderby'        => 'post__in', // Preserve order.
						'posts_per_page' => $limit,
					)
				);
				if ( ! empty( $related ) ) {
					return $related;
				}
			}
			// Fall through to auto if no valid manual selection.
		}

		// Auto mode: Get related kurse based on category.
		$related = array();

		// Get current kurs categories.
		$terms = get_the_terms( $kurs_id, self::TAXONOMY );
		$term_ids = array();
		if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
			$term_ids = wp_list_pluck( $terms, 'term_id' );
		}

		// Build query args.
		$args = array(
			'post_type'      => self::POST_TYPE,
			'post_status'    => 'publish',
			'posts_per_page' => $limit,
			'post__not_in'   => array( $kurs_id ),
			'orderby'        => 'meta_value',
			'order'          => 'ASC',
			'meta_key'       => self::META_PREFIX . 'start_date',
			'meta_type'      => 'DATE',
		);

		// First try: same category.
		if ( ! empty( $term_ids ) ) {
			$args['tax_query'] = array(
				array(
					'taxonomy' => self::TAXONOMY,
					'field'    => 'term_id',
					'terms'    => $term_ids,
				),
			);

			$query = new WP_Query( $args );
			$related = $query->posts;
		}

		// If not enough results, get any other kurse.
		if ( count( $related ) < $limit ) {
			$remaining = $limit - count( $related );
			$exclude = array_merge( array( $kurs_id ), wp_list_pluck( $related, 'ID' ) );

			$fallback_args = array(
				'post_type'      => self::POST_TYPE,
				'post_status'    => 'publish',
				'posts_per_page' => $remaining,
				'post__not_in'   => $exclude,
				'orderby'        => 'rand',
			);

			$query = new WP_Query( $fallback_args );
			$related = array_merge( $related, $query->posts );
		}

		return $related;
	}
}
