<?php
/**
 * File Path: includes/admin/class-mbs-admin-bulk-edit.php
 *
 * MBS Admin Bulk Edit — Registration & Render
 *
 * Adds a custom "MBS: Edit Selected" bulk action to the Books list screen.
 * Allows setting Genre, Series, or Visibility across multiple books at once.
 *
 * Flow:
 *   1. Admin selects books + chooses "MBS: Edit Selected" → bulk action fires.
 *   2. Handler stores selected IDs in a transient, redirects to confirmation screen.
 *   3. Confirmation screen (rendered via admin_notices) shows what will change.
 *   4. Admin fills in the field(s) to apply and clicks "Apply Changes".
 *   5. admin_post_mbs_bulk_edit_apply handler validates + applies via WP core functions.
 *   6. Redirect back to list with a success notice.
 *
 * All writes use WordPress core functions (wp_set_object_terms, wp_update_post) —
 * no direct $wpdb calls.
 *
 * The save handler (handle_apply) lives in MBS_Admin_Bulk_Edit_Save (REF-013, Session 137).
 *
 * @package MyBookShowroom
 * @since   1.0.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.Security.NonceVerification -- nonce verified in parent class verify_save() / check_admin_referer() before $_POST access; PHPCS cannot trace cross-method nonce verification
class MBS_Admin_Bulk_Edit {

	/** Transient prefix — stores selected post IDs for the confirmation step. */
	private const TRANSIENT_PREFIX = 'mbs_bulk_edit_';

	/** Maximum books per bulk operation (guard against server timeout). */
	private const MAX_BOOKS = 200;

	public function __construct() {
		// Register the bulk action on the books list table.
		add_filter( 'bulk_actions-edit-' . MBS_POST_TYPE,        array( $this, 'register_bulk_action' ) );
		add_filter( 'handle_bulk_actions-edit-' . MBS_POST_TYPE, array( $this, 'handle_bulk_action' ), 10, 3 );

		// Show confirmation form or result notices.
		add_action( 'admin_notices', array( $this, 'maybe_show_confirmation' ) );
		add_action( 'admin_notices', array( $this, 'maybe_show_result_notice' ) );
		// Note: admin_post_mbs_bulk_edit_apply is wired by MBS_Admin_Bulk_Edit_Save.
	}

	// =========================================================================
	// Step 1 — Add bulk action to dropdown
	// =========================================================================

	/**
	 * Register the MBS bulk edit action in the bulk-actions dropdown.
	 * S13-15: Available on all license tiers (PRO gate removed).
	 *
	 * @param array $actions Existing bulk actions.
	 * @return array Modified bulk actions.
	 */
	public function register_bulk_action( array $actions ): array {
		$actions['mbs_bulk_edit'] = __( 'MBS: Edit Selected', 'my-book-showroom' );
		return $actions;
	}

	// =========================================================================
	// Step 2 — Intercept bulk action, store IDs, redirect to confirmation
	// =========================================================================

	/**
	 * Handle the mbs_bulk_edit bulk action.
	 *
	 * Stores the selected post IDs in a transient, then redirects to the
	 * list screen with a confirmation token in the URL.
	 *
	 * @param string $redirect_to Redirect URL from WP.
	 * @param string $action      Action name.
	 * @param int[]  $post_ids    Selected post IDs.
	 * @return string Modified redirect URL.
	 */
	public function handle_bulk_action( string $redirect_to, string $action, array $post_ids ): string {
		if ( 'mbs_bulk_edit' !== $action ) {
			return $redirect_to;
		}

		// SA-L4: WordPress core verifies the 'bulk-{post_type_plural}' nonce automatically
		// via WP_List_Table before invoking handle_bulk_actions. An explicit nonce check
		// here is therefore not required; capability check serves as the additional gate.
		if ( ! current_user_can( 'edit_posts' ) ) {
			return $redirect_to;
		}

		// Sanitise and cap the list of IDs.
		$post_ids = array_map( 'absint', $post_ids );
		$post_ids = array_filter( $post_ids );
		$post_ids = array_slice( $post_ids, 0, self::MAX_BOOKS );

		if ( empty( $post_ids ) ) {
			return $redirect_to;
		}

		// Store IDs in a transient (5-minute TTL — time to complete the confirm step).
		$token = wp_generate_password( 20, false );
		set_transient( self::TRANSIENT_PREFIX . $token, $post_ids, 5 * MINUTE_IN_SECONDS );

		// Redirect to the list screen with the confirmation token.
		return add_query_arg( array(
			'mbs_bulk_confirm' => '1',
			'mbs_bulk_token'   => rawurlencode( $token ),
			'mbs_bulk_count'   => count( $post_ids ),
		), remove_query_arg( array( 'action', 'action2' ), $redirect_to ) );
	}

	// =========================================================================
	// Step 3 — Show confirmation form
	// =========================================================================

	/**
	 * Render the confirmation form when ?mbs_bulk_confirm=1 is present.
	 */
	public function maybe_show_confirmation(): void {
		$screen = get_current_screen();
		if ( ! $screen || 'edit-' . MBS_POST_TYPE !== $screen->id ) {
			return;
		}

		if ( empty( $_GET['mbs_bulk_confirm'] ) || '1' !== $_GET['mbs_bulk_confirm'] ) {
			return;
		}

		if ( ! current_user_can( 'edit_posts' ) ) {
			return;
		}

		$token = sanitize_key( wp_unslash( $_GET['mbs_bulk_token'] ?? '' ) );
		$count = absint( $_GET['mbs_bulk_count'] ?? 0 );

		if ( empty( $token ) ) {
			return;
		}

		// Verify the transient still exists (not expired / already used).
		$post_ids = get_transient( self::TRANSIENT_PREFIX . $token );
		if ( false === $post_ids ) {
			echo '<div class="notice notice-error"><p>' .
			     esc_html__( 'MBS bulk edit session expired. Please select your books again.', 'my-book-showroom' ) .
			     '</p></div>';
			return;
		}

		// Build genre options.
		$genres = get_terms( array(
			'taxonomy'   => MBS_TAX_GENRE,
			'hide_empty' => false,
			'orderby'    => 'name',
		) );

		// Build series options.
		$series_terms = get_terms( array(
			'taxonomy'   => MBS_TAX_SERIES,
			'hide_empty' => false,
			'orderby'    => 'name',
		) );

		$apply_url = admin_url( 'admin-post.php' );

		?>
		<div class="notice notice-warning" style="padding:16px 16px 20px;">
			<h3 style="margin:0 0 10px;">
				<?php
				/* translators: %d: number of selected books */
				printf( esc_html__( 'MBS Bulk Edit — %d book(s) selected', 'my-book-showroom' ), absint( $count ) );
				?>
			</h3>
			<p><?php esc_html_e( 'Choose what to change for all selected books. Only non-blank fields will be applied.', 'my-book-showroom' ); ?></p>

			<form method="post" action="<?php echo esc_url( $apply_url ); ?>">
				<?php wp_nonce_field( 'mbs_bulk_edit_apply', 'mbs_bulk_nonce' ); ?>
				<input type="hidden" name="action" value="mbs_bulk_edit_apply">
				<input type="hidden" name="mbs_bulk_token" value="<?php echo esc_attr( $token ); ?>">

				<table class="form-table" style="max-width:600px;margin:12px 0 0;">
					<tr>
						<th style="padding:8px 16px 8px 0; width:140px;">
							<label for="mbs_bulk_genre"><?php esc_html_e( 'Set Genre', 'my-book-showroom' ); ?></label>
						</th>
						<td style="padding:8px 0;">
							<select name="mbs_bulk_genre" id="mbs_bulk_genre">
								<option value=""><?php esc_html_e( '— No change —', 'my-book-showroom' ); ?></option>
								<?php if ( ! is_wp_error( $genres ) ) : ?>
									<?php foreach ( $genres as $genre ) : ?>
										<option value="<?php echo esc_attr( $genre->term_id ); ?>">
											<?php echo esc_html( $genre->name ); ?>
										</option>
									<?php endforeach; ?>
								<?php endif; ?>
							</select>
							<p class="description" style="margin:4px 0 0;"><?php esc_html_e( 'Replaces the primary genre on all selected books.', 'my-book-showroom' ); ?></p>
						</td>
					</tr>
					<tr>
						<th style="padding:8px 16px 8px 0;">
							<label for="mbs_bulk_series"><?php esc_html_e( 'Set Series', 'my-book-showroom' ); ?></label>
						</th>
						<td style="padding:8px 0;">
							<select name="mbs_bulk_series" id="mbs_bulk_series">
								<option value=""><?php esc_html_e( '— No change —', 'my-book-showroom' ); ?></option>
								<option value="__remove__"><?php esc_html_e( 'Remove from all series', 'my-book-showroom' ); ?></option>
								<?php if ( ! is_wp_error( $series_terms ) ) : ?>
									<?php foreach ( $series_terms as $series ) : ?>
										<option value="<?php echo esc_attr( $series->term_id ); ?>">
											<?php echo esc_html( $series->name ); ?>
										</option>
									<?php endforeach; ?>
								<?php endif; ?>
							</select>
							<p class="description" style="margin:4px 0 0;"><?php esc_html_e( 'Assigns all selected books to this series (or removes them from any series).', 'my-book-showroom' ); ?></p>
						</td>
					</tr>
					<tr>
						<th style="padding:8px 16px 8px 0;">
							<label for="mbs_bulk_status"><?php esc_html_e( 'Set Visibility', 'my-book-showroom' ); ?></label>
						</th>
						<td style="padding:8px 0;">
							<select name="mbs_bulk_status" id="mbs_bulk_status">
								<option value=""><?php esc_html_e( '— No change —', 'my-book-showroom' ); ?></option>
								<option value="publish"><?php esc_html_e( 'Published', 'my-book-showroom' ); ?></option>
								<option value="draft"><?php esc_html_e( 'Draft', 'my-book-showroom' ); ?></option>
								<option value="private"><?php esc_html_e( 'Private', 'my-book-showroom' ); ?></option>
							</select>
						</td>
					</tr>
				</table>

				<div style="margin-top:16px;">
					<button type="submit" class="button button-primary">
						<?php esc_html_e( 'Apply Changes', 'my-book-showroom' ); ?>
					</button>
					<a href="<?php echo esc_url( remove_query_arg( array( 'mbs_bulk_confirm', 'mbs_bulk_token', 'mbs_bulk_count' ) ) ); ?>"
					   class="button" style="margin-left:8px;">
						<?php esc_html_e( 'Cancel', 'my-book-showroom' ); ?>
					</a>
				</div>
			</form>
		</div>
		<?php
	}

	// =========================================================================
	// Step 6 — Success notice
	// =========================================================================

	/**
	 * Show a success notice after bulk changes are applied.
	 */
	public function maybe_show_result_notice(): void {
		$screen = get_current_screen();
		if ( ! $screen || 'edit-' . MBS_POST_TYPE !== $screen->id ) {
			return;
		}

		if ( ! isset( $_GET['mbs_bulk_applied'] ) ) {
			return;
		}

		$applied = absint( $_GET['mbs_bulk_applied'] );
		/* translators: %d: number of books updated */
		$message = sprintf( _n(
			'MBS bulk edit: %d book updated.',
			'MBS bulk edit: %d books updated.',
			$applied,
			'my-book-showroom'
		), $applied );

		echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( $message ) . '</p></div>';
	}
}
