<?php
/**
 * File Path: includes/admin/class-mbs-admin.php
 *
 * Admin Menu and Settings
 *
 * @package MyBookShowroom
 * @since   1.0.0
 */

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

class MBS_Admin {

	public function __construct() {
		add_action( 'admin_menu',            array( $this, 'add_menu' ) );

		// MENU-01: Redirect the top-level parent page to All Books.
		// Must be on admin_init — NOT inside the add_menu_page callback — because
		// admin-header.php runs before the callback fires, making wp_safe_redirect()
		// ineffective (headers already sent).
		add_action( 'admin_init',            array( $this, 'maybe_redirect_top_menu' ) );

		// MENU-01: Remove the auto-generated duplicate "My Book Showroom" first child.
		// admin_head fires after menu.php has populated $submenu — the only hook at
		// which remove_submenu_page() reliably finds and removes the entry.
		add_action( 'admin_head', array( $this, 'remove_duplicate_submenu' ) );

		// MENU-03: Hide the auto-generated first-child duplicate from the visual
		// submenu via CSS. The entry must remain in $submenu so WordPress resolves
		// the parent href to admin.php?page=my-book-showroom (the dashboard).
		add_action( 'admin_head', array( $this, 'render_admin_menu_css' ) );

		// ACE-001: Disable browser autocomplete on all MBS admin inputs.
		add_action( 'admin_head', array( $this, 'disable_autocomplete' ) );

		// MENU-01: Fix active-menu highlighting when browsing CPT/taxonomy screens.
		// WordPress uses parent_file to decide which top-level item is "open".
		// Because we set show_in_menu => false on the CPT and all three taxonomies,
		// WordPress would leave the My Book Showroom menu collapsed on those screens
		// without this filter.
		add_filter( 'parent_file',           array( $this, 'fix_menu_parent' ) );

		// Add tier-conditional action links on the Plugins page.
		add_filter( 'plugin_action_links_' . plugin_basename( MBS_DIR . 'bookshowroom.php' ), array( $this, 'add_plugin_action_links' ) );

		// Add Documentation + DMRS Tech links in the plugin row meta area.
		add_filter( 'plugin_row_meta', array( $this, 'add_plugin_row_meta' ), 10, 2 );

		// REF-28: Book Editor asset enqueuing delegated to MBS_Admin_Assets.
		new MBS_Admin_Assets();

		// BUG-03: One-time cleanup of orphaned format rows written with post_id=0 by
		// BUG-02.  Those rows caused false ASIN/ISBN duplicate conflicts.  Runs once
		// per installation via an option flag; no-ops on all subsequent loads.
		add_action( 'admin_init', array( $this, 'cleanup_orphaned_format_rows' ) );

		// BUG-01: The Book Header metabox is registered to the 'normal' column but
		// WordPress persists per-user drag-and-drop positions in user-meta.  If the
		// box was ever dragged to the sidebar the user-meta override keeps it there
		// indefinitely.  This filter intercepts the stored preference and moves the
		// box back to 'normal' whenever it has drifted to 'side', without modifying
		// any other user preference.
		add_filter( 'get_user_option_meta-box-order_mbs_book', array( $this, 'ensure_book_header_in_normal_column' ) );

		// UX-BAN-001: Taxonomy list pages show a notice directing editors to
		// MBS Settings for full entity management (author profiles, series
		// cover images, etc.) since the WP taxonomy edit screen exposes only
		// term name and slug.
		add_action( 'admin_notices', array( $this, 'render_taxonomy_banners' ) );

		// UX-TIP-001: Enqueue mbs-admin.css on MBS taxonomy screens so that
		// mbs_help_tip() markup renders correctly on the WP taxonomy pages.
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_taxonomy_assets' ) );

		// UX-TIP-001: Inject a help tip next to the 'Add New Collection' h2
		// on the WP taxonomy list page for mbs_collection.
		add_action( 'mbs_collection_pre_add_form', array( $this, 'render_collection_add_tip' ) );
	}

	/**
	 * BUG-03: Soft-delete any format rows that were saved with post_id = 0 by the
	 * BUG-02 regression (MBS_Format_Row_DAO::insert() passed 0 as the post_id to
	 * save(), causing rows to be written with post_id = 0).  Those orphaned rows
	 * matched every subsequent ASIN/ISBN duplicate check and silently wiped the
	 * field on save.  Runs once per installation and sets an option flag so it
	 * never re-runs.
	 *
	 */
	public function cleanup_orphaned_format_rows(): void {
		MBS_Format_Row_DAO::cleanup_orphaned();
	}

	/**
	 * BUG-01: Return the mbs_book metabox order with Book Header forced into the
	 * normal column.
	 *
	 * @param mixed $order Stored metabox order (array keyed by column name, or false/null).
	 * @return mixed Corrected order, or the original value if nothing needed fixing.
	 */
	public function ensure_book_header_in_normal_column( $order ) {
		if ( ! is_array( $order ) ) {
			return $order;
		}

		$side = $order['side'] ?? '';
		if ( false === strpos( $side, 'mbs_book_header' ) ) {
			return $order; // Already in the right place — nothing to do.
		}

		// Remove from side column.
		$side_parts = array_filter(
			array_map( 'trim', explode( ',', $side ) ),
			static function ( string $id ): bool {
				return 'mbs_book_header' !== $id;
			}
		);
		$order['side'] = implode( ',', $side_parts );

		// Prepend to normal column so it appears at the top.
		$normal       = $order['normal'] ?? '';
		$normal_parts = array_filter( array_map( 'trim', explode( ',', $normal ) ) );
		array_unshift( $normal_parts, 'mbs_book_header' );
		$order['normal'] = implode( ',', $normal_parts );

		return $order;
	}

	// -------------------------------------------------------------------------
	// Menu registration
	// -------------------------------------------------------------------------

	/**
	 * MENU-01: Redirect admin.php?page=my-book-showroom to All Books before
	 * any output is sent.  The add_menu_page callback fires too late (after
	 * admin-header.php) for wp_safe_redirect() to work there.
	 */
	public function maybe_redirect_top_menu(): void {
		// GC3-1: Dashboard now renders on admin.php?page=my-book-showroom — redirect
		// to All Books is no longer needed.  Method retained for hook compatibility.
	}

	/**
	 * MENU-02: No-op — retained for hook compatibility only.
	 * Previously removed the auto-generated first child so the old All Books
	 * redirect could work.  GC3-1 replaced that redirect with a real Dashboard;
	 * the first-child entry must now remain so WordPress sets the parent menu
	 * href to admin.php?page=my-book-showroom (the dashboard).
	 */
	public function remove_duplicate_submenu(): void {
		// No-op: dashboard is the intended first-child destination.
	}

	/**
	 * MENU-03: Output CSS that hides the auto-generated first-child duplicate
	 * from the MBS submenu. The <li class="wp-first-item"> is the entry
	 * WordPress auto-inserts to mirror the parent; it must remain in $submenu
	 * (so the parent href resolves to the dashboard) but should not be visible.
	 */
	public function render_admin_menu_css(): void {
		?>
		<style id="mbs-admin-menu-css">
		#adminmenu #toplevel_page_my-book-showroom ul.wp-submenu .wp-first-item { display: none; }
		</style>
		<?php
	}

	/**
	 * MENU-01: Ensure the My Book Showroom top-level menu stays highlighted
	 * (open/active) when the user is on any MBS CPT or taxonomy screen.
	 *
	 * @return string              Corrected parent file slug.
	 */
	public function fix_menu_parent( string $parent_file ): string {
		global $current_screen;

		if ( ! $current_screen instanceof WP_Screen ) {
			return $parent_file;
		}

		$is_mbs_post = ( MBS_POST_TYPE === $current_screen->post_type );
		$is_mbs_tax  = in_array(
			$current_screen->taxonomy,
			array( MBS_TAX_AUTHOR, MBS_TAX_SERIES, MBS_TAX_GENRE, MBS_TAX_TAG, MBS_TAX_COLLECTION, MBS_TAX_UNIVERSE ),
			true
		);

		if ( $is_mbs_post || $is_mbs_tax ) {
			return 'my-book-showroom';
		}

		return $parent_file;
	}

	public function add_menu(): void {
		// MENU-03: Top-level item. Callback renders the Dashboard (GC3-1).
		// The auto-generated first child (slug = my-book-showroom) keeps the
		// parent href pointing to the dashboard URL. render_admin_menu_css()
		// hides that duplicate entry from the visual submenu via CSS.
		add_menu_page(
			__( 'My Book Showroom', 'my-book-showroom' ),
			__( 'My Book Showroom', 'my-book-showroom' ),
			'manage_options',
			'my-book-showroom',
			array( MBS_Admin_Dashboard::get_instance(), 'render' ),
			'dashicons-book',
			5
		);

		// 1. All Books
		add_submenu_page(
			'my-book-showroom',
			__( 'All Books', 'my-book-showroom' ),
			__( 'Books', 'my-book-showroom' ),
			'manage_options',
			'edit.php?post_type=' . MBS_POST_TYPE
		);

		// 2. Add New Book
		add_submenu_page(
			'my-book-showroom',
			__( 'Add New Book', 'my-book-showroom' ),
			__( 'Add New Book', 'my-book-showroom' ),
			'manage_options',
			'post-new.php?post_type=' . MBS_POST_TYPE
		);

		// 3. Author(s) — singular label when 1 or fewer authors, plural when 2+.
		$_author_count = wp_count_terms( array( 'taxonomy' => MBS_TAX_AUTHOR, 'hide_empty' => false ) );
		$_author_label = ( ! is_wp_error( $_author_count ) && (int) $_author_count > 1 )
			? __( 'Authors', 'my-book-showroom' )
			: __( 'Author', 'my-book-showroom' );
		add_submenu_page(
			'my-book-showroom',
			__( 'Authors', 'my-book-showroom' ),
			$_author_label,
			'manage_options',
			'edit-tags.php?taxonomy=' . MBS_TAX_AUTHOR . '&post_type=' . MBS_POST_TYPE
		);

		// 4. Series
		add_submenu_page(
			'my-book-showroom',
			__( 'Series', 'my-book-showroom' ),
			__( 'Series', 'my-book-showroom' ),
			'manage_options',
			'edit-tags.php?taxonomy=' . MBS_TAX_SERIES . '&post_type=' . MBS_POST_TYPE
		);

		// 5. Universes — conditional on opt-in toggle (Settings -> Advanced).
		// B-UNI-01: submenu was never registered despite being documented in
		// class-mbs-taxonomy-universe.php (MENU-01 pattern).
		if ( get_option( 'mbs_setting_advanced_universe_enabled' ) ) {
			add_submenu_page(
				'my-book-showroom',
				__( 'Universes', 'my-book-showroom' ),
				__( 'Universes', 'my-book-showroom' ),
				'manage_options',
				'edit-tags.php?taxonomy=' . MBS_TAX_UNIVERSE . '&post_type=' . MBS_POST_TYPE
			);
		}

		// 6. Collections — F-016
		add_submenu_page(
			'my-book-showroom',
			__( 'Collections', 'my-book-showroom' ),
			__( 'Collections', 'my-book-showroom' ),
			'manage_options',
			'edit-tags.php?taxonomy=' . MBS_TAX_COLLECTION . '&post_type=' . MBS_POST_TYPE
		);

		// 7. Genre
		add_submenu_page(
			'my-book-showroom',
			__( 'Genre', 'my-book-showroom' ),
			__( 'Genre', 'my-book-showroom' ),
			'manage_options',
			'edit-tags.php?taxonomy=' . MBS_TAX_GENRE . '&post_type=' . MBS_POST_TYPE
		);

		// 8. Tags/Keywords
		add_submenu_page(
			'my-book-showroom',
			__( 'Tags/Keywords', 'my-book-showroom' ),
			__( 'Tags/Keywords', 'my-book-showroom' ),
			'manage_options',
			'edit-tags.php?taxonomy=' . MBS_TAX_TAG . '&post_type=' . MBS_POST_TYPE
		);

		// 9. Settings — always last in the group.
		add_submenu_page(
			'my-book-showroom',
			__( 'Settings', 'my-book-showroom' ),
			__( 'Settings', 'my-book-showroom' ),
			'manage_options',
			'my-book-showroom-settings',
			array( $this, 'settings_page' )
		);
	}

	// -------------------------------------------------------------------------
	// Plugin action links + row meta
	// -------------------------------------------------------------------------

	/**
	 * Add tier-conditional action links on the Plugins page.
	 *
	 * Link shown depends on registration/license state (WO-002):
	 *   · Keyless          → 'Register Plugin'   (bold, routes to License tab)
	 *   · Key unactivated  → 'Activate License'  (bold, routes to License tab)
	 *   · FREE registered  → 'Upgrade to PRO'    (bold, routes to upgrade page)
	 *   · PRO / Publisher  → 'Manage License'    (routes to License tab)
	 *
	 * All new links are prepended before the core Deactivate/Edit links.
	 *
	 * @param array $links Current action links from WordPress core.
	 * @return array Modified action links.
	 */
	public function add_plugin_action_links( array $links ): array {
		$settings_url = admin_url( 'admin.php?page=my-book-showroom-settings' );
		$license_url  = admin_url( 'admin.php?page=my-book-showroom-settings&tab=license' );

		$new_links = array(
			'settings' => sprintf(
				'<a href="%1$s">%2$s</a>',
				esc_url( $settings_url ),
				esc_html__( 'Settings', 'my-book-showroom' )
			),
		);

		if ( mbs_is_keyless() ) {
			// No key stored — invite them to register (optional, benefit-driven).
			$new_links['register'] = sprintf(
				'<a href="%s" class="mbs-link-bold">%s</a>',
				esc_url( $license_url ),
				esc_html__( 'Register Plugin', 'my-book-showroom' )
			);
		} elseif ( ! mbs_is_registered() ) {
			// Key stored but not yet activated — prompt activation.
			$new_links['license'] = sprintf(
				'<a href="%s" class="mbs-link-bold">%s</a>',
				esc_url( $license_url ),
				esc_html__( 'Activate License', 'my-book-showroom' )
			);
		} elseif ( ! mbs_is_pro() ) {
			// FREE registered — surface the upgrade path.
			$new_links['upgrade'] = sprintf(
				'<a href="%s" target="_blank" rel="noopener noreferrer" class="mbs-link-bold">%s</a>',
				esc_url( add_query_arg( 'tier', 'pro', MBS_UPGRADE_URL ) ),
				esc_html__( 'Upgrade to PRO', 'my-book-showroom' )
			);
		} else {
			// PRO or Publisher — give quick access to license management.
			$new_links['license'] = sprintf(
				'<a href="%1$s">%2$s</a>',
				esc_url( $license_url ),
				esc_html__( 'Manage License', 'my-book-showroom' )
			);
		}

		// Our links go first; core links (Deactivate, Edit) follow.
		return array_merge( $new_links, $links );
	}

	/**
	 * Add Documentation and DMRS Tech links to the MBS row meta area
	 * (the line below the plugin description on the Plugins page).
	 *
	 * @param string $plugin_file Plugin basename being filtered.
	 * @return array Modified row meta links.
	 */
	public function add_plugin_row_meta( array $links, string $plugin_file ): array {
		if ( plugin_basename( MBS_DIR . 'bookshowroom.php' ) !== $plugin_file ) {
			return $links;
		}

		$links[] = sprintf(
			'<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
			esc_url( MBS_WEBSITE_URL . '/guides/' ),
			esc_html__( 'Documentation', 'my-book-showroom' )
		);

		$links[] = sprintf(
			'<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
			esc_url( MBS_WEBSITE_URL ),
			esc_html__( 'Visit DMRS Tech', 'my-book-showroom' )
		);

		return $links;
	}

	// -------------------------------------------------------------------------
	// -------------------------------------------------------------------------
	// Taxonomy page banners (UX-BAN-001)
	// -------------------------------------------------------------------------

	/**
	 * Display an info notice on WordPress taxonomy list/edit screens for
	 * MBS taxonomies, directing editors to the MBS Settings tab where
	 * full entity management is available.
	 *
	 * @return void
	 */
	public function render_taxonomy_banners(): void {
		$screen = get_current_screen();
		if ( ! $screen ) {
			return;
		}

		$base = admin_url( 'admin.php?page=my-book-showroom-settings&tab=' );

		$banners = array(
			MBS_TAX_AUTHOR     => array(
				'tab'  => 'authors',
				'link' => __( 'MBS Settings → Catalog → Authors', 'my-book-showroom' ),
				/* translators: 1: MBS settings tab URL, 2: settings link label */
				'text' => __( 'Full author profiles — biography, photo, social links, website, pen name, display name, and Featured Author status — are managed in <a href="%1$s">%2$s</a>. The fields on this WordPress page cover only the term name and slug.', 'my-book-showroom' ),
			),
			MBS_TAX_SERIES     => array(
				'tab'  => 'series',
				'link' => __( 'MBS Settings → Catalog → Series', 'my-book-showroom' ),
				/* translators: 1: MBS settings tab URL, 2: settings link label */
				'text' => __( 'Series details — cover image, description, reading order management, and archive display options — are managed in <a href="%1$s">%2$s</a>. The fields on this WordPress page cover only the term name and slug.', 'my-book-showroom' ),
			),
			MBS_TAX_COLLECTION => array(
				'tab'  => 'collections',
				'link' => __( 'MBS Settings → Catalog → Collections', 'my-book-showroom' ),
				/* translators: 1: MBS settings tab URL, 2: settings link label */
				'text' => __( 'Collection details — type, description, and reading order — are managed in <a href="%1$s">%2$s</a>. The fields on this WordPress page cover only the term name and slug.', 'my-book-showroom' ),
			),
			MBS_TAX_UNIVERSE   => array(
				'tab'  => 'universes',
				'link' => __( 'MBS Settings → Catalog → Universes', 'my-book-showroom' ),
				/* translators: 1: MBS settings tab URL, 2: settings link label */
				'text' => __( 'Universe details — description and reading order across series and standalones — are managed in <a href="%1$s">%2$s</a>. The fields on this WordPress page cover only the term name and slug.', 'my-book-showroom' ),
			),
		);

		if ( ! isset( $banners[ $screen->taxonomy ] ) ) {
			return;
		}

		$entry = $banners[ $screen->taxonomy ];
		$url   = esc_url( $base . $entry['tab'] );
		$link  = esc_html( $entry['link'] );
		$msg   = sprintf( $entry['text'], $url, $link );

		printf(
			'<div class="notice notice-info"><p>%s</p></div>',
			wp_kses( $msg, array( 'a' => array( 'href' => array() ) ) )
		);
	}

	// -------------------------------------------------------------------------
	// Taxonomy page assets + help tip (UX-TIP-001)
	// -------------------------------------------------------------------------

	/**
	 * Enqueue mbs-admin.css on MBS taxonomy list/edit screens so that
	 * mbs_help_tip() markup (rendered by render_collection_add_tip()) has
	 * the styles it needs.
	 *
	 * @param string $hook Current admin page hook suffix.
	 * @return void
	 */
	public function enqueue_taxonomy_assets( string $hook ): void {
		if ( ! in_array( $hook, array( 'edit-tags.php', 'term.php' ), true ) ) {
			return;
		}
		$screen = get_current_screen();
		if ( ! $screen ) {
			return;
		}
		$mbs_taxonomies = array(
			MBS_TAX_AUTHOR,
			MBS_TAX_SERIES,
			MBS_TAX_COLLECTION,
			MBS_TAX_UNIVERSE,
		);
		if ( ! in_array( $screen->taxonomy, $mbs_taxonomies, true ) ) {
			return;
		}
		wp_enqueue_style(
			'mbs-admin',
			plugins_url( 'assets/css/mbs-admin.css', MBS_DIR . 'bookshowroom.php' ),
			array(),
			(string) ( @filemtime( MBS_ASSETS_DIR . 'css/mbs-admin.css' ) ?: MBS_VERSION )
		);
	}

	/**
	 * Inject a help tip next to the WordPress-rendered 'Add New Collection'
	 * h2 on the mbs_collection taxonomy list page (UX-TIP-001).
	 *
	 * Uses ob_start() to capture the mbs_help_tip() output (which includes
	 * its self-contained inline JS on first call), then emits a small script
	 * that appends the tip span into the .form-wrap h2 element.
	 *
	 * @return void
	 */
	public function render_collection_add_tip(): void {
		ob_start();
		mbs_help_tip(
			__( 'A Collection groups books that share a theme, setting, or world with no required reading order. Unlike a Series, readers can start anywhere — there is no \'Book 1.\' Use Collections for standalone novels, holiday titles, or thematic sets you want readers to discover together.', 'my-book-showroom' ),
			__( 'What is a Collection?', 'my-book-showroom' ),
			'mbs-help-tip--wide'
		);
		$tip_html = ob_get_clean();
		?>
		<script>
		document.addEventListener('DOMContentLoaded', function() {
			var h2 = document.querySelector('.form-wrap h2');
			if (!h2) return;
			var wrap = document.createElement('span');
			wrap.style.verticalAlign = 'middle';
			wrap.style.marginLeft = '4px';
			wrap.innerHTML = <?php echo wp_json_encode( $tip_html ); ?>;
			h2.appendChild(wrap);
		});
		</script>
		<?php
	}

	// -------------------------------------------------------------------------
	// Autocomplete suppression — ACE-001
	// -------------------------------------------------------------------------

	/**
	 * Output an inline script that disables browser autocomplete on every
	 * input within the MBS admin surface.
	 *
	 * Covers all three MBS admin contexts from a single hook:
	 *   - Book editor  (post.php / post-new.php for mbs_book)
	 *   - Settings     (admin.php?page=my-book-showroom-*)
	 *   - Taxonomy screens (edit-tags.php / term.php for mbs_* taxonomies)
	 *
	 * A MutationObserver re-applies the attribute to any input injected
	 * after DOMContentLoaded (format-row repeaters, social-link entries,
	 * buy-link rows, etc.) so dynamically-added fields are also covered.
	 *
	 * ACE-001
	 *
	 * @return void
	 */
	public function disable_autocomplete(): void {
		$screen = get_current_screen();
		if ( ! $screen ) {
			return;
		}

		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		$raw_page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		$on_mbs_page = (
			( in_array( $screen->base, array( 'post', 'add' ), true ) && MBS_POST_TYPE === $screen->post_type )
			|| ( '' !== $raw_page && strpos( $raw_page, 'my-book-showroom' ) === 0 )
			|| ( in_array( $screen->base, array( 'edit-tags', 'term' ), true ) && strpos( (string) $screen->taxonomy, 'mbs_' ) === 0 )
		);

		if ( ! $on_mbs_page ) {
			return;
		}
		?>
		<script>
		(function () {
			// ACE-001: Chrome ignores autocomplete="off" on fields whose placeholder
			// mentions "email". Using "new-password" is the only value all major
			// browsers honour unconditionally. Also covers inputs with no type attr
			// (they default to text but may not match the type= selector).
			var FIELDS = 'input[type="text"],input[type="url"],input[type="email"],' +
			             'input[type="number"],input[type="tel"],input:not([type]),textarea';
			function mbsAcOff(root) {
				root.querySelectorAll(FIELDS).forEach(function (el) {
					el.setAttribute('autocomplete', 'new-password');
				});
			}
			document.addEventListener('DOMContentLoaded', function () {
				mbsAcOff(document);
				new MutationObserver(function (mutations) {
					mutations.forEach(function (m) {
						m.addedNodes.forEach(function (n) {
							if (n.nodeType === 1) { mbsAcOff(n); }
						});
					});
				}).observe(document.body, { childList: true, subtree: true });
			});
		}());
		</script>
		<?php
	}

	// -------------------------------------------------------------------------
	// Settings page callback
	// -------------------------------------------------------------------------

	public function settings_page(): void {
		$settings = MBS_Settings::get_instance();
		$settings->render_settings_page();
	}
}
