<?php
/**
 * File Path: includes/admin/class-mbs-admin-native-bulk-edit.php
 *
 * MBS Admin — Native Bulk & Quick Edit Panel Overrides
 *
 * Replaces WordPress's auto-generated taxonomy fields in the native bulk edit
 * and quick edit panels with purpose-built MBS UI:
 *
 *   Series            → single-select <select>  (enforces 1:1 cardinality)
 *   Authors           → checkbox list            (quick: replace; bulk: append)
 *   Tags              → checkbox list            (quick: replace; bulk: append)
 *   Collections       → checkbox list            (quick: replace; bulk: append)
 *   Universes         → checkbox list            (quick: replace; bulk: append)
 *   Themes / Tropes   → checkbox list            (quick: replace; bulk: append)
 *   Content Warnings  → checkbox list            (quick: replace; bulk: append)
 *
 * Genres are left to WordPress's native hierarchical checkbox rendering —
 * they are already correct without intervention.
 *
 * Auto-generated WP fields for the above taxonomies are suppressed by setting
 * 'show_in_quick_edit' => false on each taxonomy registration (see taxonomy
 * class files). This class re-introduces them via bulk_edit_custom_box and
 * quick_edit_custom_box, keyed to the hidden 'mbs_book_data' column.
 *
 * Quick edit pre-population: current term IDs are serialised as a JSON data
 * attribute on each list-table row (rendered via the mbs_book_data column).
 * child-admin-inline-edit.js reads those attributes when the quick edit panel
 * opens and pre-checks the appropriate controls.
 *
 * Save semantics:
 *   Quick edit  — REPLACE: the checked set is the exact new set of terms.
 *   Bulk edit   — APPEND for flat taxonomies (add to existing, never remove);
 *                 REPLACE for Series (single-select enforces 1:1).
 *
 * Note on $_REQUEST usage in save_fields():
 *   WordPress's native bulk edit submits the list-table form as GET (method="get"
 *   on #posts-filter), so our custom fields arrive in $_GET / $_REQUEST.
 *   Quick edit submits via AJAX POST, so fields arrive in $_POST / $_REQUEST.
 *   Using $_REQUEST (as WordPress core itself does in edit.php bulk handling)
 *   covers both code paths with a single read.
 *
 * @package MyBookShowroom
 * @since   1.0.0
 */

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

class MBS_Admin_Native_Bulk_Edit {

	// =========================================================================
	// Configuration
	// =========================================================================

	/**
	 * Flat taxonomy configurations handled by this class.
	 * Key   = taxonomy constant.
	 * Value = array( 'label' => translatable label, 'key' => JS/data-attribute key ).
	 *
	 * Public static so MBS_Admin_Native_Bulk_Edit_Render can call it directly
	 * without needing an instance reference.
	 *
	 * @return array<string, array{label: string, key: string}>
	 */
	public static function flat_taxonomies(): array {
		return array(
			MBS_TAX_AUTHOR          => array(
				'label' => __( 'Authors', 'my-book-showroom' ),
				'key'   => 'authors',
			),
			MBS_TAX_TAG             => array(
				'label' => __( 'Tags', 'my-book-showroom' ),
				'key'   => 'tags',
			),
			MBS_TAX_COLLECTION      => array(
				'label' => __( 'Collections', 'my-book-showroom' ),
				'key'   => 'collections',
			),
			MBS_TAX_UNIVERSE        => array(
				'label' => __( 'Universes', 'my-book-showroom' ),
				'key'   => 'universes',
			),
			MBS_TAX_THEME           => array(
				'label' => __( 'Themes / Tropes', 'my-book-showroom' ),
				'key'   => 'themes',
			),
			MBS_TAX_CONTENT_WARNING => array(
				'label' => __( 'Content Warnings', 'my-book-showroom' ),
				'key'   => 'warnings',
			),
		);
	}

	// =========================================================================
	// Bootstrap
	// =========================================================================

	public function __construct() {
		// Hidden data column for quick edit pre-population.
		add_filter( 'manage_' . MBS_POST_TYPE . '_posts_columns',       array( $this, 'add_data_column' ) );
		add_action( 'manage_' . MBS_POST_TYPE . '_posts_custom_column', array( 'MBS_Admin_Native_Bulk_Edit_Render', 'render_data_column' ), 10, 2 );

		// Custom bulk / quick edit fields (keyed on the hidden column).
		add_action( 'bulk_edit_custom_box',  array( 'MBS_Admin_Native_Bulk_Edit_Render', 'render_bulk_edit_fields' ),  10, 2 );
		add_action( 'quick_edit_custom_box', array( 'MBS_Admin_Native_Bulk_Edit_Render', 'render_quick_edit_fields' ), 10, 2 );

		// Save handler — fires for both bulk edit (GET) and quick edit (AJAX POST).
		add_action( 'save_post', array( $this, 'save_fields' ) );

		// Assets and column CSS on the Books list screen only.
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
		add_action( 'admin_head',            array( 'MBS_Admin_Native_Bulk_Edit_Render', 'hide_data_column_css' ) );
	}

	// =========================================================================
	// Hidden data column (registration)
	// =========================================================================

	/**
	 * Register the hidden mbs_book_data column on the Books list table.
	 * The column never shows visible content; it exists only so that
	 * bulk_edit_custom_box / quick_edit_custom_box fire for it.
	 *
	 * @param  array $columns Existing columns.
	 * @return array
	 */
	public function add_data_column( array $columns ): array {
		$columns['mbs_book_data'] = '';
		return $columns;
	}

	// =========================================================================
	// Save
	// =========================================================================

	/**
	 * Process custom taxonomy fields submitted from the bulk or quick edit panel.
	 *
	 * Uses $_REQUEST so the same handler covers:
	 *   • Bulk edit  — form submits as GET (WordPress list table uses method="get")
	 *   • Quick edit — AJAX POSTs via inlineEditPost.save()
	 *
	 * Quick edit (single post): REPLACES all custom taxonomy terms with the
	 * checked set (unchecking all boxes = remove all).
	 *
	 * Bulk edit (multi-post): REPLACES series; APPENDS flat taxonomy terms
	 * (add checked to existing without removing anything).
	 *
	 * @param int $post_id Post ID being saved.
	 */
	public function save_fields( int $post_id ): void {
		// Skip autosaves.
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}

		// Only process MBS book posts (revisions have post_type='revision').
		if ( MBS_POST_TYPE !== get_post_type( $post_id ) ) {
			return;
		}

		// Only process when our panel was actually submitted.
		if ( empty( $_REQUEST['mbs_inline_edit_active'] ) ) {
			return;
		}

		// Nonce verification. $_REQUEST covers both GET (bulk) and POST (quick edit).
		if ( empty( $_REQUEST['mbs_inline_edit_nonce'] ) ) {
			return;
		}

		if ( ! wp_verify_nonce(
			sanitize_key( wp_unslash( $_REQUEST['mbs_inline_edit_nonce'] ) ),
			'mbs_inline_edit'
		) ) {
			return;
		}

		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}

		// Detect context: bulk_edit is the submit-button name on the bulk edit form.
		$is_bulk = ! empty( $_REQUEST['bulk_edit'] );

		// ── Series (single-select, 1:1) ───────────────────────────────────────
		if ( isset( $_REQUEST['mbs_inline_series'] ) ) {
			$series_raw = sanitize_key( wp_unslash( $_REQUEST['mbs_inline_series'] ) );

			if ( '__remove__' === $series_raw ) {
				// Explicit remove.
				wp_set_object_terms( $post_id, array(), MBS_TAX_SERIES );

			} elseif ( '' === $series_raw && $is_bulk ) {
				// "— No change —" in bulk edit — preserve existing assignment.

			} elseif ( '' === $series_raw ) {
				// Quick edit, empty selection = no series.
				wp_set_object_terms( $post_id, array(), MBS_TAX_SERIES );

			} elseif ( is_numeric( $series_raw ) ) {
				wp_set_object_terms( $post_id, array( absint( $series_raw ) ), MBS_TAX_SERIES );
			}
		}

		// ── Series Position (quick edit only) ────────────────────────────────
		if ( ! $is_bulk && isset( $_REQUEST['mbs_inline_series_position'] ) ) {
			$pos = sanitize_text_field( wp_unslash( $_REQUEST['mbs_inline_series_position'] ) );
			if ( '' !== $pos ) {
				update_post_meta( $post_id, 'mbs_series_position', $pos );
				// Explicit dual-write: sync to mbs_book_meta immediately, independent of hook order (DAT-030).
				MBS_Book_Meta_DAO::upsert( $post_id, 'mbs_series_position', $pos );
			} else {
				delete_post_meta( $post_id, 'mbs_series_position' );
				// Explicit dual-write: clear mbs_book_meta immediately, independent of hook order (DAT-030).
				MBS_Book_Meta_DAO::upsert( $post_id, 'mbs_series_position', '' );
			}
		}

		// ── Flat taxonomies ──────────────────────────────────────────────────
		$submitted_tax = ( isset( $_REQUEST['mbs_inline_tax'] ) && is_array( $_REQUEST['mbs_inline_tax'] ) )
			? $_REQUEST['mbs_inline_tax'] // 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
			: array();

		foreach ( array_keys( self::flat_taxonomies() ) as $taxonomy ) {
			$submitted = array();

			if ( isset( $submitted_tax[ $taxonomy ] ) ) {
				$submitted = array_filter(
					array_map( 'absint', (array) $submitted_tax[ $taxonomy ] )
				);
			}

			if ( $is_bulk ) {
				// Bulk edit: append checked terms to existing — never remove.
				if ( ! empty( $submitted ) ) {
					wp_set_object_terms( $post_id, $submitted, $taxonomy, true );
				}
			} else {
				// Quick edit: replace — checked set is the complete new set.
				wp_set_object_terms( $post_id, $submitted, $taxonomy, false );
			}
		}
	}

	// =========================================================================
	// Assets
	// =========================================================================

	/**
	 * Enqueue the quick edit JS and panel CSS on the Books list screen.
	 *
	 * @param string $hook Current admin hook suffix.
	 */
	public function enqueue_assets( string $hook ): void {
		if ( 'edit.php' !== $hook ) {
			return;
		}
		global $post_type;
		if ( $post_type !== MBS_POST_TYPE ) {
			return;
		}

		wp_enqueue_script(
			'mbs-inline-edit',
			plugins_url( 'assets/js/adminjs/admin-inline-edit.js', MBS_DIR . 'bookshowroom.php' ),
			array( 'jquery', 'inline-edit-post' ),
			MBS_VERSION,
			true
		);

		wp_enqueue_style(
			'mbs-inline-edit',
			plugins_url( 'assets/css/mbs-admin-inline-edit.css', MBS_DIR . 'bookshowroom.php' ),
			array(),
			MBS_VERSION
		);
	}
}
