<?php
/**
 * Post Navigation and Duplicate Functionality
 *
 * Adds Previous/Next navigation and Duplicate button to post edit screens.
 *
 * @package KursBooking
 */

declare(strict_types=1);

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

/**
 * Class Kurs_Booking_Post_Navigation
 *
 * Handles post navigation and duplication in admin.
 */
class Kurs_Booking_Post_Navigation {

	/**
	 * Post types that get navigation buttons
	 */
	private const NAVIGATION_POST_TYPES = array( 'kurs', 'kurs-buchung', 'kurs-video', 'post', 'page' );

	/**
	 * Post types that get duplicate button
	 */
	private const DUPLICATE_POST_TYPES = array( 'kurs', 'kurs-video' );

	/**
	 * Initialize hooks
	 */
	public static function init(): void {
		add_action( 'add_meta_boxes', array( __CLASS__, 'add_navigation_meta_box' ) );
		add_action( 'admin_action_kurs_booking_duplicate_post', array( __CLASS__, 'duplicate_post' ) );
		add_filter( 'post_row_actions', array( __CLASS__, 'add_duplicate_row_action' ), 10, 2 );
		add_filter( 'page_row_actions', array( __CLASS__, 'add_duplicate_row_action' ), 10, 2 );
	}

	/**
	 * Add navigation meta box to supported post types
	 */
	public static function add_navigation_meta_box(): void {
		$screen = get_current_screen();

		if ( ! $screen || 'post' !== $screen->base ) {
			return;
		}

		$post_type = $screen->post_type;

		// Check if this post type should have navigation.
		if ( ! in_array( $post_type, self::NAVIGATION_POST_TYPES, true ) ) {
			return;
		}

		add_meta_box(
			'kurs_booking_post_navigation',
			__( 'Navigation', 'kurs-booking' ),
			array( __CLASS__, 'render_navigation_meta_box' ),
			$post_type,
			'side',
			'high'
		);
	}

	/**
	 * Render the navigation meta box
	 *
	 * @param WP_Post $post The current post.
	 */
	public static function render_navigation_meta_box( WP_Post $post ): void {
		$post_type      = $post->post_type;
		$show_duplicate = in_array( $post_type, self::DUPLICATE_POST_TYPES, true );

		// Get adjacent posts.
		$prev_post = self::get_adjacent_post( $post, 'prev' );
		$next_post = self::get_adjacent_post( $post, 'next' );

		?>
		<div class="kb-post-navigation">
			<style>
				.kb-post-navigation {
					display: flex;
					flex-direction: column;
					gap: 10px;
				}
				.kb-nav-buttons {
					display: flex;
					gap: 8px;
				}
				.kb-nav-buttons .button {
					flex: 1;
					display: inline-flex;
					align-items: center;
					justify-content: center;
					gap: 4px;
					text-decoration: none;
				}
				.kb-nav-buttons .button .dashicons {
					font-size: 16px;
					width: 16px;
					height: 16px;
				}
				.kb-nav-buttons .button:disabled,
				.kb-nav-buttons .button.disabled {
					opacity: 0.5;
					pointer-events: none;
				}
				.kb-nav-title {
					font-size: 11px;
					color: #646970;
					white-space: nowrap;
					overflow: hidden;
					text-overflow: ellipsis;
					max-width: 100%;
					display: block;
					margin-top: 2px;
				}
				.kb-nav-group {
					display: flex;
					flex-direction: column;
					flex: 1;
					min-width: 0;
				}
				.kb-duplicate-section {
					padding-top: 10px;
					border-top: 1px solid #dcdcde;
				}
				.kb-duplicate-btn {
					width: 100%;
					display: inline-flex !important;
					align-items: center;
					justify-content: center;
					gap: 6px;
				}
				.kb-duplicate-btn .dashicons {
					font-size: 16px;
					width: 16px;
					height: 16px;
				}
			</style>

			<div class="kb-nav-buttons">
				<div class="kb-nav-group">
					<?php if ( $prev_post ) : ?>
						<a href="<?php echo esc_url( get_edit_post_link( $prev_post->ID ) ); ?>" class="button" title="<?php echo esc_attr( $prev_post->post_title ); ?>">
							<span class="dashicons dashicons-arrow-left-alt2"></span>
							<?php esc_html_e( 'Vorherige', 'kurs-booking' ); ?>
						</a>
						<span class="kb-nav-title" title="<?php echo esc_attr( $prev_post->post_title ); ?>">
							<?php echo esc_html( wp_trim_words( $prev_post->post_title, 5, '...' ) ); ?>
						</span>
					<?php else : ?>
						<span class="button disabled">
							<span class="dashicons dashicons-arrow-left-alt2"></span>
							<?php esc_html_e( 'Vorherige', 'kurs-booking' ); ?>
						</span>
						<span class="kb-nav-title"><?php esc_html_e( 'Keine', 'kurs-booking' ); ?></span>
					<?php endif; ?>
				</div>

				<div class="kb-nav-group">
					<?php if ( $next_post ) : ?>
						<a href="<?php echo esc_url( get_edit_post_link( $next_post->ID ) ); ?>" class="button" title="<?php echo esc_attr( $next_post->post_title ); ?>">
							<?php esc_html_e( 'Nächste', 'kurs-booking' ); ?>
							<span class="dashicons dashicons-arrow-right-alt2"></span>
						</a>
						<span class="kb-nav-title" title="<?php echo esc_attr( $next_post->post_title ); ?>">
							<?php echo esc_html( wp_trim_words( $next_post->post_title, 5, '...' ) ); ?>
						</span>
					<?php else : ?>
						<span class="button disabled">
							<?php esc_html_e( 'Nächste', 'kurs-booking' ); ?>
							<span class="dashicons dashicons-arrow-right-alt2"></span>
						</span>
						<span class="kb-nav-title"><?php esc_html_e( 'Keine', 'kurs-booking' ); ?></span>
					<?php endif; ?>
				</div>
			</div>

			<?php if ( $show_duplicate ) : ?>
				<div class="kb-duplicate-section">
					<a href="<?php echo esc_url( self::get_duplicate_url( $post->ID ) ); ?>" class="button kb-duplicate-btn">
						<span class="dashicons dashicons-admin-page"></span>
						<?php esc_html_e( 'Duplizieren', 'kurs-booking' ); ?>
					</a>
				</div>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Get adjacent post (previous or next)
	 *
	 * @param WP_Post $post      The current post.
	 * @param string  $direction 'prev' or 'next'.
	 * @return WP_Post|null
	 */
	private static function get_adjacent_post( WP_Post $post, string $direction ): ?WP_Post {
		$args = array(
			'post_type'      => $post->post_type,
			'posts_per_page' => 1,
			'orderby'        => 'date',
			'order'          => 'prev' === $direction ? 'DESC' : 'ASC',
			'post_status'    => array( 'publish', 'draft', 'pending', 'private' ),
			'date_query'     => array(
				array(
					'prev' === $direction ? 'before' : 'after' => $post->post_date,
					'inclusive' => false,
				),
			),
		);

		// For same date, use ID as tiebreaker.
		$query = new WP_Query( $args );

		if ( $query->have_posts() ) {
			return $query->posts[0];
		}

		// Fallback: try by ID if date query returns nothing.
		$args = array(
			'post_type'      => $post->post_type,
			'posts_per_page' => 1,
			'orderby'        => 'ID',
			'order'          => 'prev' === $direction ? 'DESC' : 'ASC',
			'post_status'    => array( 'publish', 'draft', 'pending', 'private' ),
		);

		if ( 'prev' === $direction ) {
			$args['post__in'] = range( 1, $post->ID - 1 );
		} else {
			$args['meta_query'] = array(); // Reset.
		}

		// Simple ID-based query.
		global $wpdb;

		$operator = 'prev' === $direction ? '<' : '>';
		$order    = 'prev' === $direction ? 'DESC' : 'ASC';

		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $operator and $order are hardcoded literals ('<'/'>' and 'DESC'/'ASC'), not user input.
		$adjacent_id = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT ID FROM {$wpdb->posts}
				WHERE post_type = %s
				AND post_status IN ('publish', 'draft', 'pending', 'private')
				AND ID {$operator} %d
				ORDER BY ID {$order}
				LIMIT 1",
				$post->post_type,
				$post->ID
			)
		);
		// phpcs:enable

		if ( $adjacent_id ) {
			return get_post( (int) $adjacent_id );
		}

		return null;
	}

	/**
	 * Get duplicate post URL
	 *
	 * @param int $post_id The post ID to duplicate.
	 * @return string
	 */
	private static function get_duplicate_url( int $post_id ): string {
		return wp_nonce_url(
			admin_url( 'admin.php?action=kurs_booking_duplicate_post&post=' . $post_id ),
			'kurs_booking_duplicate_' . $post_id
		);
	}

	/**
	 * Handle post duplication
	 */
	public static function duplicate_post(): void {
		// Verify request.
		if ( ! isset( $_GET['post'] ) || ! isset( $_GET['_wpnonce'] ) ) {
			wp_die( esc_html__( 'Ungültige Anfrage.', 'kurs-booking' ) );
		}

		$post_id = absint( $_GET['post'] );
		$nonce   = sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) );

		// Verify nonce.
		if ( ! wp_verify_nonce( $nonce, 'kurs_booking_duplicate_' . $post_id ) ) {
			wp_die( esc_html__( 'Sicherheitsüberprüfung fehlgeschlagen.', 'kurs-booking' ) );
		}

		// Get original post.
		$post = get_post( $post_id );

		if ( ! $post ) {
			wp_die( esc_html__( 'Beitrag nicht gefunden.', 'kurs-booking' ) );
		}

		// Check if user can create posts of this type.
		$post_type_obj = get_post_type_object( $post->post_type );
		if ( ! current_user_can( $post_type_obj->cap->create_posts ) ) {
			wp_die( esc_html__( 'Sie haben keine Berechtigung für diese Aktion.', 'kurs-booking' ) );
		}

		// Check if this post type allows duplication.
		if ( ! in_array( $post->post_type, self::DUPLICATE_POST_TYPES, true ) ) {
			wp_die( esc_html__( 'Dieser Beitragstyp kann nicht dupliziert werden.', 'kurs-booking' ) );
		}

		// Create duplicate.
		$new_post_id = self::create_duplicate( $post );

		if ( is_wp_error( $new_post_id ) ) {
			wp_die( esc_html( $new_post_id->get_error_message() ) );
		}

		// Redirect to the new post edit screen.
		wp_safe_redirect( admin_url( 'post.php?action=edit&post=' . $new_post_id ) );
		exit;
	}

	/**
	 * Create a duplicate of a post
	 *
	 * @param WP_Post $post The post to duplicate.
	 * @return int|WP_Error New post ID or error.
	 */
	private static function create_duplicate( WP_Post $post ): int|WP_Error {
		// Prepare new post data.
		$new_post = array(
			'post_title'     => sprintf(
				/* translators: %s: Original post title */
				__( '%s (Kopie)', 'kurs-booking' ),
				$post->post_title
			),
			'post_content'   => $post->post_content,
			'post_excerpt'   => $post->post_excerpt,
			'post_status'    => 'draft',
			'post_type'      => $post->post_type,
			'post_author'    => get_current_user_id(),
			'post_parent'    => $post->post_parent,
			'menu_order'     => $post->menu_order,
			'comment_status' => $post->comment_status,
			'ping_status'    => $post->ping_status,
		);

		// Insert new post.
		$new_post_id = wp_insert_post( $new_post, true );

		if ( is_wp_error( $new_post_id ) ) {
			return $new_post_id;
		}

		// Duplicate taxonomies.
		$taxonomies = get_object_taxonomies( $post->post_type );
		foreach ( $taxonomies as $taxonomy ) {
			$terms = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'slugs' ) );
			if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
				wp_set_object_terms( $new_post_id, $terms, $taxonomy );
			}
		}

		// Duplicate post meta.
		$meta_keys = get_post_custom_keys( $post->ID );
		if ( $meta_keys ) {
			foreach ( $meta_keys as $meta_key ) {
				// Skip internal WordPress meta.
				if ( in_array( $meta_key, array( '_edit_lock', '_edit_last', '_wp_old_slug' ), true ) ) {
					continue;
				}

				$meta_values = get_post_meta( $post->ID, $meta_key );
				foreach ( $meta_values as $meta_value ) {
					add_post_meta( $new_post_id, $meta_key, $meta_value );
				}
			}
		}

		// Duplicate featured image.
		$thumbnail_id = get_post_thumbnail_id( $post->ID );
		if ( $thumbnail_id ) {
			set_post_thumbnail( $new_post_id, $thumbnail_id );
		}

		return $new_post_id;
	}

	/**
	 * Add duplicate link to post row actions.
	 *
	 * @param array<string, string> $actions Existing actions.
	 * @param WP_Post               $post    The post.
	 * @return array<string, string> Modified actions.
	 */
	public static function add_duplicate_row_action( array $actions, WP_Post $post ): array {
		// Only for allowed post types.
		if ( ! in_array( $post->post_type, self::DUPLICATE_POST_TYPES, true ) ) {
			return $actions;
		}

		// Check permissions.
		$post_type_obj = get_post_type_object( $post->post_type );
		if ( ! current_user_can( $post_type_obj->cap->create_posts ) ) {
			return $actions;
		}

		// Add duplicate action.
		$actions['duplicate'] = sprintf(
			'<a href="%s" aria-label="%s">%s</a>',
			esc_url( self::get_duplicate_url( $post->ID ) ),
			/* translators: %s: Post title */
			esc_attr( sprintf( __( '„%s" duplizieren', 'kurs-booking' ), $post->post_title ) ),
			esc_html__( 'Duplizieren', 'kurs-booking' )
		);

		return $actions;
	}
}
