<?php
/**
 * File Path: includes/admin/tabs/authors-series/class-mbs-tab-collections.php
 *
 * Collections Tab — Save & Render
 *
 * Manages the Settings → Collections tab: one collapsible <details>/<summary>
 * card per mbs_collection term, with description, collection-type select, and a
 * drag-and-drop reading-order list.
 *
 * Mirrors MBS_Tab_Series (class-mbs-tab-series.php). Differences:
 *   · No "Default sort" radio — collections have no series_number / reading_order
 *     dual-sort concept.
 *   · No "Complete" checkbox — not applicable to collections.
 *   · Collection Type select — exposed here alongside the WP term edit screen;
 *     both surfaces write the same mbs_collection_type term_meta key.
 *   · Reading order stored in mbs_collection_reading_order term_meta (JSON),
 *     managed via MBS_Collection_Reading_Order_DAO.
 *
 * The per-book position (mbs_book_collection_positions table, via
 * MBS_Book_Collection_Position_DAO) is NOT modified here; it belongs to the
 * Book Header metabox (F-016). The legacy postmeta was retired in migration 4.17.
 *
 * Owned term_meta keys:
 *   · mbs_collection_reading_order  — JSON array of book post IDs.
 *   · mbs_collection_type           — slug from MBS_Taxonomy_Collection::get_types().
 *                                     Shared key with WP taxonomy add/edit hooks.
 *   · mbs_term_layout               — Layout slug override. TLA-001.
 *   · mbs_collection_banner_id       — Attachment ID for the collection banner image.
 *
 * Tab slug: 'collections'
 * Nonce:    mbs_collection_save / mbs_collection_nonce
 *
 * @package    My_Book_Showroom
 * @subpackage Includes/Admin/Tabs/Authors-Series
 * @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
// phpcs:disable WordPress.Security.ValidatedSanitizedInput -- input sanitized at point of use (sanitize_text_field, absint, wp_kses_post, etc.); false positives from PHPCS not tracing sanitization helpers called before this method
class MBS_Tab_Collections extends MBS_Tab_Base {

	public function __construct() {
		add_action( 'admin_init', array( $this, 'handle_save' ) );
	}

	// -------------------------------------------------------------------------
	// Save accessor overrides — DUP-005 (handle_save() now in MBS_Tab_Base)
	// -------------------------------------------------------------------------

	/** @return string */
	protected function save_nonce_field(): string { return 'mbs_collection_nonce'; }
	/** @return string */
	protected function save_nonce_action(): string { return 'mbs_collection_save'; }
	/** @return string */
	protected function save_tab_slug(): string { return 'collections'; }
	/** @return string */
	protected function save_post_id_field(): string { return 'mbs_save_collection_id'; }

	/**
	 * Save extended collection fields for a single mbs_collection term.
	 *
	 * Called by handle_save() after nonce verification and capability check.
	 * Also callable directly from unit tests that bypass the security layer.
	 *
	 * @param int $term_id Validated, absint-cast term ID.
	 * @return void
	 */
	public function save( int $term_id ): void {
		if ( ! $term_id || ! term_exists( $term_id, MBS_TAX_COLLECTION ) ) {
			return;
		}

		// ── Description — stored on the term itself (not term_meta) ──────────
		$description = isset( $_POST['mbs_collection_description'][ $term_id ] )
			? sanitize_textarea_field( wp_unslash( $_POST['mbs_collection_description'][ $term_id ] ) )
			: '';
		wp_update_term( $term_id, MBS_TAX_COLLECTION, array( 'description' => $description ) );

		// ── Collection Type (enum) ────────────────────────────────────────────
		// Accept empty string (no type) or any key defined in the TYPES registry.
		$type_raw = isset( $_POST['mbs_collection_type_select'][ $term_id ] )
			? sanitize_key( wp_unslash( $_POST['mbs_collection_type_select'][ $term_id ] ) )
			: '';
		if ( '' === $type_raw || array_key_exists( $type_raw, MBS_Taxonomy_Collection::get_types() ) ) {
			update_term_meta( $term_id, 'mbs_collection_type', $type_raw );
		}

		// ── Book Grid Layout (TLA-001) — extracted to MBS_Tab_Base::save_layout_field()
		$this->save_layout_field( $term_id );

		// Collection banner image (F-BNR-C) — DUP-006: delegate to MBS_Tab_Base
		if ( mbs_is_pro() || mbs_is_pub() ) {
			$this->save_banner_field( $term_id, 'mbs_collection_banner_id', 'mbs_collection_banner_id' );
		}

		// ── Reading order (JSON-encoded array of book post IDs) ───────────────
		// Hidden input is populated by the card's JS at submit time or after a
		// drag. Saving a card without dragging locks in the currently-displayed
		// default order — which is the intended R1 behavior.
		$raw_order = isset( $_POST['mbs_collection_reading_order'][ $term_id ] )
			? (string) wp_unslash( $_POST['mbs_collection_reading_order'][ $term_id ] )
			: '';
		if ( '' !== $raw_order ) {
			$decoded = json_decode( $raw_order, true );
			if ( is_array( $decoded ) ) {
				MBS_Collection_Reading_Order_DAO::save_reading_order( $term_id, $decoded );
			}
		}
	}

	// -------------------------------------------------------------------------
	// Enqueue
	// -------------------------------------------------------------------------

	/**
	 * Enqueue Collections tab assets when this tab is active.
	 *
	 * @param string $current_tab The active tab slug.
	 * @return void
	 */
	public function enqueue( string $current_tab ): void {
		if ( 'collections' !== $current_tab ) {
			return;
		}

		$this->enqueue_entity_base_assets();

		wp_enqueue_style(
			'mbs-admin-settings-collections',
			plugins_url( 'assets/css/mbs-admin-settings-collections.css', MBS_DIR . 'bookshowroom.php' ),
			array( 'mbs-admin-settings' ),
			MBS_VERSION
		);

		// jQuery UI Sortable is already globally enqueued via mbs-book-editor;
		// declared here as a dep for safety (deps are idempotent).
		wp_enqueue_script(
			'mbs-admin-collections',
			plugins_url( 'assets/js/adminjs/admin-collections.js', MBS_DIR . 'bookshowroom.php' ),
			array( 'jquery', 'jquery-ui-sortable', 'mbs-admin-utils', 'wp-i18n' ),
			MBS_VERSION,
			true
		);
		wp_set_script_translations( 'mbs-admin-collections', 'my-book-showroom', MBS_DIR . 'languages' );

		// Live filter + A-Z collapse/expand (shared with Authors and Series tabs).
		wp_enqueue_script(
			'mbs-admin-filter',
			plugins_url( 'assets/js/adminjs/mbs-admin-filter.js', MBS_DIR . 'bookshowroom.php' ),
			array(),
			MBS_VERSION,
			true
		);

		// F-SORT-2: Sort preference toggle.
		wp_enqueue_script(
			'mbs-admin-sort-pref',
			plugins_url( 'assets/js/adminjs/mbs-admin-sort-pref.js', MBS_DIR . 'bookshowroom.php' ),
			array(),
			MBS_VERSION,
			true
		);
		$this->localize_sort_pref( 'collections', array( 'name', 'name_sort' ), 'name' );
	}

	// -------------------------------------------------------------------------
	// Render
	// -------------------------------------------------------------------------

	/**
	 * Render the Collections tab.
	 *
	 * Delegates to MBS_Tab_Collections_Render::render().
	 * Kept as a thin instance method so class-mbs-settings.php can call
	 * $tab->render() without modification (R-16 delegate pattern).
	 *
	 * @return void
	 */
	public function render(): void {
		MBS_Tab_Collections_Render::render();
	}

}
