<?php
/**
 * File Path: includes/admin/class-mbs-admin-ajax.php
 *
 * Book Editor AJAX Endpoints
 *
 * Handles wp_ajax_* actions that serve the book editor (Context 2):
 *   mbs_publisher_suggest    — returns matching distinct publisher values
 *                              from existing books for the autocomplete widget.
 *   mbs_create_series_term   — creates a new mbs_series taxonomy term and
 *                              returns its term_id so the book editor can add
 *                              it to the Series dropdown without a page reload.
 *   mbs_create_universe_term — creates a new mbs_universe taxonomy term (PRO).
 *                              Returns term_id + name so the Universe metabox
 *                              can inject a new checkbox without a page reload.
 *   mbs_save_book_order      — S13-14: saves drag-and-drop order via menu_order.
 *   mbs_save_sort_pref       — F-SORT-2: saves per-user sort preference for Authors,
 *                              Series, or Collections tab. Nonce: mbs_sort_pref_nonce.
 *
 * Nonce action: 'mbs_book_editor_ajax' (set via MBS_BookEditorAjax.nonce in
 * class-mbs-admin-assets.php).
 *
 * @package MyBookShowroom
 */

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

class MBS_Admin_Ajax {

	public function __construct() {
		add_action( 'wp_ajax_mbs_publisher_suggest',       array( $this, 'publisher_suggest' ) );
		add_action( 'wp_ajax_mbs_create_series_term',      array( $this, 'create_series_term' ) );
		add_action( 'wp_ajax_mbs_create_universe_term',    array( $this, 'create_universe_term' ) );
		add_action( 'wp_ajax_mbs_save_book_order',         array( $this, 'save_book_order' ) );
		add_action( 'wp_ajax_mbs_dismiss_callout',         array( $this, 'dismiss_callout' ) );
		add_action( 'wp_ajax_mbs_save_sort_pref',          array( $this, 'save_sort_pref' ) );
	}

	/**
	 * Return distinct publisher values that begin with the query string.
	 * Used by admin-publisher.js jQuery UI autocomplete.
	 *
	 * GET param: q — the search term (sanitized)
	 */
	public function publisher_suggest(): void {
		check_ajax_referer( 'mbs_book_editor_ajax', 'nonce' );

		if ( ! current_user_can( 'edit_posts' ) ) {
			wp_send_json_error( __( 'Insufficient permissions.', 'my-book-showroom' ), 403 );
		}

		$q       = isset( $_GET['q'] ) ? sanitize_text_field( wp_unslash( $_GET['q'] ) ) : '';
		$results = MBS_Book_Query::suggest_publishers( $q );

		wp_send_json_success( $results );
	}

	/**
	 * Create a new series taxonomy term and return its term_id.
	 * Used by the "Create Series" button in admin-book-series.js.
	 *
	 * POST param: name — the series name (sanitized)
	 */
	public function create_series_term(): void {
		check_ajax_referer( 'mbs_book_editor_ajax', 'nonce' );

		if ( ! current_user_can( 'manage_categories' ) ) {
			wp_send_json_error( __( 'Insufficient permissions to create a series.', 'my-book-showroom' ) );
		}

		$name = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
		if ( '' === $name ) {
			wp_send_json_error( __( 'Series name is required.', 'my-book-showroom' ) );
		}

		// If the term already exists, return it rather than erroring.
		$existing = get_term_by( 'name', $name, 'mbs_series' );
		if ( $existing ) {
			wp_send_json_success( array( 'term_id' => $existing->term_id, 'name' => $existing->name ) );
		}

		$result = wp_insert_term( $name, 'mbs_series' );
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( $result->get_error_message() );
		}

		wp_send_json_success( array( 'term_id' => $result['term_id'], 'name' => $name ) );
	}

	/**
	 * Create a new universe taxonomy term and return its term_id + name.
	 * Used by the Universe metabox "Create Universe" inline button. PRO only.
	 *
	 * POST param: name — the universe name (sanitized)
	 */
	public function create_universe_term(): void {
		check_ajax_referer( 'mbs_book_editor_ajax', 'nonce' );

		if ( ! mbs_is_pro() ) {
			wp_send_json_error( array( 'message' => 'PRO license required.' ), 403 );
		}

		if ( ! current_user_can( 'manage_categories' ) ) {
			wp_send_json_error( __( 'Insufficient permissions to create a universe.', 'my-book-showroom' ) );
		}

		$name = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
		if ( '' === $name ) {
			wp_send_json_error( __( 'Universe name is required.', 'my-book-showroom' ) );
		}

		$existing = get_term_by( 'name', $name, 'mbs_universe' );
		if ( $existing ) {
			wp_send_json_success( array( 'term_id' => $existing->term_id, 'name' => $existing->name ) );
		}

		$result = wp_insert_term( $name, 'mbs_universe' );
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( $result->get_error_message() );
		}

		wp_send_json_success( array( 'term_id' => $result['term_id'], 'name' => $name ) );
	}

	/**
	 * Permanently dismiss the "Add to Pages" how-to callout for the current user.
	 *
	 * POST param: nonce — wp_nonce 'mbs_dismiss_callout'.
	 */
	public function dismiss_callout(): void {
		check_ajax_referer( 'mbs_dismiss_callout', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Permission denied.' ), 403 );
		}

		update_user_meta( get_current_user_id(), 'mbs_dismissed_add_to_pages_callout', 1 );
		wp_send_json_success();
	}

	// -------------------------------------------------------------------------
	// S13-14: Book list drag-and-drop ordering (FREE)
	// -------------------------------------------------------------------------

	/**
	 * Save the book list sort order by updating menu_order on each post.
	 *
	 * POST param: order — array of post IDs in the desired sequence.
	 * Nonce action: mbs_book_order_nonce.
	 */
	public function save_book_order(): void {
		check_ajax_referer( 'mbs_book_order_nonce', 'nonce' );

		// F-07: gate on the Books CPT capability, not the generic edit_posts
		// primitive (held by Contributor/Author by default).
		if ( ! current_user_can( 'edit_mbs_books' ) ) {
			wp_send_json_error( array( 'message' => 'Insufficient permissions.' ), 403 );
		}

		$raw_order = isset( $_POST['order'] ) ? (array) $_POST['order'] : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- input sanitized via sanitize_* helpers or validated before use; see inline sanitization
		if ( empty( $raw_order ) ) {
			wp_send_json_error( array( 'message' => 'No order provided.' ), 400 );
		}

		foreach ( $raw_order as $position => $post_id ) {
			$post_id = absint( $post_id );
			if ( $post_id < 1 ) {
				continue;
			}
			// Verify the post is actually an mbs_book before updating.
			if ( get_post_type( $post_id ) !== MBS_POST_TYPE ) {
				continue;
			}
			// F-07: re-check the per-post edit capability so a user cannot reorder
			// books they are not allowed to edit (IDOR).
			if ( ! current_user_can( 'edit_post', $post_id ) ) {
				continue;
			}
			wp_update_post( array(
				'ID'         => $post_id,
				'menu_order' => (int) $position,
			) );
		}

		wp_send_json_success( array( 'message' => 'Order saved.' ) );
	}
	// -------------------------------------------------------------------------
	// F-SORT-2: Per-user tab sort preference
	// -------------------------------------------------------------------------

	/**
	 * Save a tab-specific sort preference for the current user.
	 *
	 * Nonce action: mbs_sort_pref_nonce.
	 * POST param: tab  — one of: authors, series, collections
	 * POST param: pref — allowed value for that tab
	 */
	public function save_sort_pref(): void {
		check_ajax_referer( 'mbs_sort_pref_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Permission denied.' ), 403 );
		}

		$tab  = isset( $_POST['tab'] )  ? sanitize_key( wp_unslash( $_POST['tab'] ) )  : '';
		$pref = isset( $_POST['pref'] ) ? sanitize_key( wp_unslash( $_POST['pref'] ) ) : '';

		// Allowed pref values per tab.
		$allowed = array(
			'authors'     => array( 'first_name', 'last_name' ),
			'series'      => array( 'name', 'name_sort' ),
			'collections' => array( 'name', 'name_sort' ),
			'universes'   => array( 'name', 'name_sort' ),
		);

		if ( ! isset( $allowed[ $tab ] ) ) {
			wp_send_json_error( array( 'message' => 'Invalid tab.' ), 400 );
		}

		if ( ! in_array( $pref, $allowed[ $tab ], true ) ) {
			wp_send_json_error( array( 'message' => 'Invalid pref.' ), 400 );
		}

		update_user_meta( get_current_user_id(), 'mbs_sort_pref_' . $tab, $pref );
		wp_send_json_success( array( 'tab' => $tab, 'pref' => $pref ) );
	}
}
