<?php
/**
 * File Path: includes/admin/tabs/authors-series/class-mbs-tab-authors.php
 *
 * Authors Tab — Save & Render
 *
 * Top-level handler for the Authors tab. Owns its own admin_init save
 * handler, nonce, capability check, and render.
 *
 * Social platform registry (PLATFORMS constant), decode_social_links(), and
 * get_platform_info() have been extracted to MBS_Author_Social_Links
 * (REF-009). Call MBS_Author_Social_Links::{method} directly.
 *
 * UI model: one top-level <form> per author, each wrapping a native
 * <details>/<summary> element that provides accessible collapse/expand
 * without JavaScript. Auto-expands the just-saved card after PRG redirect
 * via a 'saved' query arg. Scales to hundreds of authors because only the
 * summary is rendered in the compact (collapsed) state.
 *
 * Owned term_meta keys:
 *
 *   Photo:
 *     · mbs_author_photo_id
 *         Consumer: [mbs_author_directory] shortcode
 *
 *   Biographical:
 *     · mbs_author_bio
 *     · mbs_author_website_url
 *
 *   Social platforms (Sprint SOCIAL-LINKS):
 *     · mbs_author_social_links   — JSON array of {platform, url[, label]} objects
 *         Consumer: templates/partials/section-author-hero.php
 *                   templates/partials/section-social-share.php
 *
 *   Legacy keys (read-only; migrated to mbs_author_social_links on first read):
 *     · mbs_author_twitter_url
 *     · mbs_author_facebook_url
 *     · mbs_author_instagram_url
 *     · mbs_author_tiktok_url
 *     · mbs_author_goodreads_url
 *     · mbs_author_bookbub_url
 *     · mbs_author_linkedin_url
 *
 *   · mbs_term_layout
 *         Layout slug override. TLA-001.
 *
 * Tab slug: 'authors'
 * Nonce:    mbs_authors_save / mbs_authors_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_Authors extends MBS_Tab_Base {

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

	// -------------------------------------------------------------------------
	// Save handler — nonce + cap + delegation to save()
	// -------------------------------------------------------------------------

	/**
	 * Handle author profile saves submitted from this tab.
	 * Hooked on admin_init so it fires before any output.
	 *
	 * Returns early if the expected nonce field is absent (the request is for
	 * a different tab) or if nonce verification / capability check fails. On
	 * success, delegates to save() and issues a PRG redirect including a
	 * 'saved' query arg so render() can auto-expand the edited author's card.
	 *
	 * @return void
	 */
	public function handle_save(): void {
		if ( ! isset( $_POST['mbs_authors_nonce'] ) ) {
			return;
		}

		check_admin_referer( 'mbs_authors_save', 'mbs_authors_nonce' );

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

		if ( ! isset( $_POST['mbs_save_author_id'] ) ) {
			return;
		}

		$term_id = absint( $_POST['mbs_save_author_id'] );
		$this->save( $term_id );

		wp_safe_redirect( add_query_arg( array(
			'page'    => 'my-book-showroom-settings',
			'tab'     => 'authors',
			'updated' => '1',
			'saved'   => $term_id,
		), admin_url( 'admin.php' ) ) );
		exit;
	}

	/**
	 * Save extended author profile fields for a single mbs_author term.
	 *
	 * Called by handle_save() after nonce verification and capability check.
	 * Also callable directly from unit tests that bypass the security layer
	 * to exercise data-persistence behavior in isolation.
	 *
	 * @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_AUTHOR ) ) {
			return;
		}

		// ── Photo attachment ID ───────────────────────────────────────────────
		$photo_id = absint( $_POST['mbs_author_photo_id'][ $term_id ] ?? 0 );
		if ( $photo_id > 0 ) {
			update_term_meta( $term_id, 'mbs_author_photo_id', $photo_id );
		} else {
			delete_term_meta( $term_id, 'mbs_author_photo_id' );
		}

		// ── Bio (allows basic HTML via wp_kses_post) ──────────────────────────
		$bio = isset( $_POST['mbs_author_bio'][ $term_id ] )
			? wp_kses_post( wp_unslash( $_POST['mbs_author_bio'][ $term_id ] ) )
			: '';
		$bio = mb_substr( $bio, 0, 4000 ); // Enforce 4 000-char limit (spec requirement).
		update_term_meta( $term_id, 'mbs_author_bio', $bio );

		// ── Website URL ───────────────────────────────────────────────────────
		$website = isset( $_POST['mbs_author_website_url'][ $term_id ] )
			? esc_url_raw( trim( wp_unslash( $_POST['mbs_author_website_url'][ $term_id ] ) ) )
			: '';
		update_term_meta( $term_id, 'mbs_author_website_url', $website );

		// ── Birth Year (LOC authority control) ───────────────────────────────
		$birth_year_raw = absint( $_POST['mbs_author_birth_year'][ $term_id ] ?? 0 );
		$birth_year     = ( $birth_year_raw >= 1000 && $birth_year_raw <= 9999 ) ? $birth_year_raw : 0;
		update_term_meta( $term_id, 'mbs_author_birth_year', $birth_year ?: '' );

		// ── Social platform links ─ JSON blob (Sprint SOCIAL-LINKS) ────────────────────
		$json_raw     = isset( $_POST['mbs_author_social_links'][ $term_id ] )
			? wp_unslash( $_POST['mbs_author_social_links'][ $term_id ] )
			: '';
		$raw_links    = json_decode( $json_raw, true );
		$social_links = array();
		if ( is_array( $raw_links ) ) {
			foreach ( $raw_links as $entry ) {
				if ( ! is_array( $entry ) ) {
					continue;
				}
				$platform = sanitize_key( $entry['platform'] ?? '' );
				$url      = esc_url_raw( trim( $entry['url'] ?? '' ) );
				if ( '' === $platform || '' === $url ) {
					continue;
				}
				$item = array( 'platform' => $platform, 'url' => $url );
				if ( 'custom' === $platform && ! empty( $entry['label'] ) ) {
					$item['label'] = sanitize_text_field( $entry['label'] );
				}
				$social_links[] = $item;
			}
		}
		MBS_Author_Social_Link_DAO::save_for_term( $term_id, $social_links ); // RF-012.

		// -- F-015: Featured flag ------------------------------------------------
		$featured = isset( $_POST['mbs_author_featured'][ $term_id ] ) ? 1 : 0;
		update_term_meta( $term_id, 'mbs_author_featured', $featured );

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

		// -- F-NAMES-1: Structured name fields (sorting & ONIX) -------------------
		$name_titles_before = isset( $_POST['mbs_name_titles_before'][ $term_id ] )
			? sanitize_text_field( wp_unslash( $_POST['mbs_name_titles_before'][ $term_id ] ) )
			: '';
		update_term_meta( $term_id, 'mbs_name_titles_before', $name_titles_before );

		$name_before_key = isset( $_POST['mbs_name_before_key'][ $term_id ] )
			? sanitize_text_field( wp_unslash( $_POST['mbs_name_before_key'][ $term_id ] ) )
			: '';
		update_term_meta( $term_id, 'mbs_name_before_key', $name_before_key );

		$name_prefix_to_key = isset( $_POST['mbs_name_prefix_to_key'][ $term_id ] )
			? sanitize_text_field( wp_unslash( $_POST['mbs_name_prefix_to_key'][ $term_id ] ) )
			: '';
		update_term_meta( $term_id, 'mbs_name_prefix_to_key', $name_prefix_to_key );

		$name_key = isset( $_POST['mbs_name_key'][ $term_id ] )
			? sanitize_text_field( wp_unslash( $_POST['mbs_name_key'][ $term_id ] ) )
			: '';
		update_term_meta( $term_id, 'mbs_name_key', $name_key );

		$name_after_key = isset( $_POST['mbs_name_after_key'][ $term_id ] )
			? sanitize_text_field( wp_unslash( $_POST['mbs_name_after_key'][ $term_id ] ) )
			: '';
		update_term_meta( $term_id, 'mbs_name_after_key', $name_after_key );

		$name_letters = isset( $_POST['mbs_name_letters'][ $term_id ] )
			? sanitize_text_field( wp_unslash( $_POST['mbs_name_letters'][ $term_id ] ) )
			: '';
		update_term_meta( $term_id, 'mbs_name_letters', $name_letters );

		// mbs_name_inverted: use manual entry or auto-compute from structured parts.
		$name_inverted = isset( $_POST['mbs_name_inverted'][ $term_id ] )
			? sanitize_text_field( wp_unslash( $_POST['mbs_name_inverted'][ $term_id ] ) )
			: '';
		if ( '' === $name_inverted && '' !== $name_key ) {
			$key_part      = trim( $name_prefix_to_key . ' ' . $name_key );
			$rest_parts    = array_filter( array( $name_before_key, $name_after_key ) );
			$rest          = implode( ' ', $rest_parts );
			$name_inverted = $rest ? $key_part . ', ' . $rest : $key_part;
		}
		update_term_meta( $term_id, 'mbs_name_inverted', $name_inverted );
	}

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

	/**
	 * Enqueue Authors 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 ( 'authors' !== $current_tab ) {
			return;
		}

		wp_enqueue_media();

		$this->enqueue_entity_base_assets();

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

		// Photo uploader — Round 2 PLG-051 fix.
		wp_enqueue_script(
			'mbs-admin-authors-photo',
			plugins_url( 'assets/js/adminjs/admin-authors-photo.js', MBS_DIR . 'bookshowroom.php' ),
			array( 'jquery', 'mbs-admin-utils', 'wp-i18n' ),
			MBS_VERSION,
			true
		);
		wp_set_script_translations( 'mbs-admin-authors-photo', 'my-book-showroom', MBS_DIR . 'languages' );


		// Live filter + A-Z collapse/expand (shared with Series tab).
		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( 'authors', array( 'first_name', 'last_name' ), 'first_name' );

		// MBS.SortableList factory — required by mbs-admin-social-links.js.
		// Normally loaded only in the book-editor context; explicitly loaded here
		// so MBS.SortableList is defined for the social platform picker (BUG-SOC-001).
		wp_enqueue_script(
			'mbs-admin-utils',
			plugins_url( 'assets/js/adminjs/mbs-admin-utils.js', MBS_DIR . 'bookshowroom.php' ),
			array(),
			MBS_VERSION,
			true
		);

		wp_enqueue_script(
			'mbs-sortable-list',
			plugins_url( 'assets/js/adminjs/mbs-sortable-list.js', MBS_DIR . 'bookshowroom.php' ),
			array( 'jquery', 'jquery-ui-sortable', 'mbs-admin-utils' ),
			MBS_VERSION,
			true
		);

		// Sprint SOCIAL-LINKS: add-as-you-go social platform UI.
		wp_enqueue_style(
			'mbs-admin-social-links',
			plugins_url( 'assets/css/mbs-admin-social-links.css', MBS_DIR . 'bookshowroom.php' ),
			array( 'mbs-admin-settings-authors' ),
			MBS_VERSION
		);

		wp_enqueue_script(
			'mbs-admin-social-links',
			plugins_url( 'assets/js/adminjs/mbs-admin-social-links.js', MBS_DIR . 'bookshowroom.php' ),
			array( 'jquery', 'jquery-ui-sortable', 'mbs-sortable-list', 'wp-i18n' ),
			MBS_VERSION,
			true
		);
		wp_set_script_translations( 'mbs-admin-social-links', 'my-book-showroom', MBS_DIR . 'languages' );
	}

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

}
