<?php
/**
 * File Path: includes/import/class-mbs-importer-wp-books-gallery.php
 *
 * MBS_Importer_WP_Books_Gallery -- Competitor WXR importer for WP Books Gallery.
 *
 * Accepts a WXR export from the WP Books Gallery plugin (post type: books)
 * and maps flat wbg_* scalar meta into MBS native fields. No serialised groups;
 * one format row per book. Part of the CI-003 competitor-importer series.
 *
 * Tier: FREE (competitor migration -- no mbs_is_pro() gate).
 *
 * @package    My_Book_Showroom
 * @subpackage Includes/Import
 * @since      1.2.0
 *
 * @see PATCHES/SPEC-COMPETITOR-IMPORTERS.md §3.3
 */

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

/**
 * MBS_Importer_WP_Books_Gallery
 *
 * Extends MBS_Competitor_WXR_Base and implements the three abstract methods
 * required to drive the shared XMLReader streaming loop.
 *
 * source_key()      -- Returns 'wp-books-gallery'.
 * target_cpt()      -- Returns 'books' (the WBG post type).
 * matches_source()  -- Confirms WBG by presence of 'wbg_isbn' or 'wbg_isbn_13'.
 * map_item()        -- Maps every wbg_* meta key to an MBS data array.
 *
 * @since 1.2.0
 */
class MBS_Importer_WP_Books_Gallery extends MBS_Competitor_WXR_Base { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- mbs_/MBS_ prefix is correct; scanner not configured with plugin prefix

	// ── Abstract method implementations ───────────────────────────────────────

	/**
	 * Canonical source identifier used in telemetry and AJAX routing.
	 *
	 * @since  1.2.0
	 * @return string
	 */
	protected static function source_key(): string {
		return 'wp-books-gallery';
	}

	/**
	 * WXR post_type value that identifies WP Books Gallery items.
	 *
	 * @since  1.2.0
	 * @return string
	 */
	protected static function target_cpt(): string {
		return 'books';
	}

	/**
	 * Confirms this WXR file came from WP Books Gallery (not Genesis Author Pro,
	 * which shares the same 'books' CPT). Checks for any wbg_* meta key.
	 *
	 * @since  1.2.0
	 * @param  string[] $meta_keys Meta keys collected from the first item.
	 * @return bool
	 */
	protected static function matches_source( array $meta_keys ): bool {
		foreach ( $meta_keys as $k ) {
			if ( 0 === strpos( $k, 'wbg_' ) ) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Map a raw WXR item array into the normalised MBS data shape.
	 *
	 * Handles all wbg_* flat scalar meta per spec §3.3. One format row is built
	 * per book. Format type defaults to 'ebook' when only an ASIN is present,
	 * otherwise 'paperback'.
	 *
	 * @since  1.2.0
	 * @param  array $item_data  Raw item from the streaming loop:
	 *                           title, content, post_type, meta[], categories[].
	 * @return array|null  Normalised MBS data array, or null to skip.
	 */
	protected static function map_item( array $item_data ): ?array {
		$meta  = $item_data['meta'] ?? array();
		$cats  = $item_data['categories'] ?? array();
		$notes = array();

		// ── ISBN / ASIN ────────────────────────────────────────────────────────
		$raw_isbn = $meta['wbg_isbn_13'] ?? $meta['wbg_isbn'] ?? '';
		$isbn13   = '' !== $raw_isbn
			? MBS_ISBN_Helper::normalize_isbn( $raw_isbn )
			: '';

		$raw_asin = $meta['wbg_asin'] ?? '';
		$asin     = '' !== $raw_asin
			? MBS_ISBN_Helper::normalize_asin( $raw_asin )
			: '';

		// ── Publisher ──────────────────────────────────────────────────────────
		$publisher     = sanitize_text_field( $meta['wbg_publisher'] ?? '' );
		$co_publisher  = sanitize_text_field( $meta['wbg_co_publisher'] ?? '' );
		if ( '' !== $publisher && '' !== $co_publisher ) {
			$publisher = $publisher . ', ' . $co_publisher;
		} elseif ( '' !== $co_publisher ) {
			$publisher = $co_publisher;
		}

		// ── Listening length ("X hr Y min" → duration_hh / duration_mm) ───────
		$duration_hh = null;
		$duration_mm = null;
		$raw_length  = $meta['wbg_listening_length'] ?? '';
		if ( '' !== $raw_length ) {
			if ( preg_match( '/(\d+)\s*hr/i', $raw_length, $m ) ) {
				$duration_hh = (int) $m[1];
			}
			if ( preg_match( '/(\d+)\s*min/i', $raw_length, $m ) ) {
				$duration_mm = (int) $m[1];
			}
		}

		// ── Format row ─────────────────────────────────────────────────────────
		$format = ( '' !== $asin && '' === $isbn13 ) ? 'ebook' : 'paperback';

		$format_row = array(
			'format'       => $format,
			'isbn13'       => $isbn13,
			'asin'         => $asin,
			'subtitle'     => sanitize_text_field( $meta['wbg_sub_title'] ?? '' ),
			'edition_notes'=> sanitize_text_field( $meta['wbg_edition'] ?? '' ),
			'pub_date'     => sanitize_text_field( $meta['wbg_published_on'] ?? '' ),
			'page_length'  => absint( $meta['wbg_pages'] ?? 0 ),
			'narrator'     => sanitize_text_field( $meta['wbg_narrator'] ?? '' ),
			'duration_hh'  => $duration_hh,
			'duration_mm'  => $duration_mm,
		);

		// ── Buy link ───────────────────────────────────────────────────────────
		// V-001 fix: WBG stores the buy link under 'wbgp_buy_link' (note the 'p'),
		// not 'wbg_buy_link'. Price fields also carry the 'wbgp_' prefix.
		$buy_links = array();
		$buy_url   = esc_url_raw( $meta['wbgp_buy_link'] ?? '' );
		if ( '' !== $buy_url ) {
			$buy_links[] = array(
				'url'          => $buy_url,
				'retailer_key' => '',    // base class auto-detects from URL
				'label'        => '',
			);
		}

		// ── Postmeta ───────────────────────────────────────────────────────────
		$post_meta = array();

		if ( '' !== $publisher ) {
			$post_meta['mbs_publisher'] = $publisher;
		}

		$preserved = array(
			'wbg_editorial_reviews' => 'mbs_wbg_editorial_reviews',
			'wbg_best_sellers_rank' => 'mbs_wbg_bsr',
			'wbg_dimension'         => 'mbs_dimensions',
			'wbg_item_weight'       => 'mbs_weight',
			'wbg_filesize'          => 'mbs_wbg_filesize',
		);
		foreach ( $preserved as $src => $dest ) {
			$v = $meta[ $src ] ?? '';
			if ( '' !== (string) $v ) {
				$post_meta[ $dest ] = sanitize_text_field( (string) $v );
			}
		}

		// wbg_status: map 'active'/'inactive' → mbs_lifecycle_state.
		// 'active'   → '' (default; hydrator treats empty as active).
		// 'inactive' → 'discontinued'.
		$raw_status = strtolower( sanitize_text_field( $meta['wbg_status'] ?? '' ) );
		if ( 'inactive' === $raw_status ) {
			$post_meta['mbs_lifecycle_state'] = 'discontinued';
		} elseif ( 'active' === $raw_status ) {
			$post_meta['mbs_lifecycle_state'] = '';
		}

		// ── Dropped fields ─────────────────────────────────────────────────────
		// wbg_country     -- no MBS equivalent.
		// wbg_language    -- deferred to ONIX 3.0 language field.
		// wbg_is_featured -- no MBS featured flag.
		// wbg_wc_product_type / wbg_cost_type -- WooCommerce internal.

		// ── Taxonomies ─────────────────────────────────────────────────────────
		$taxonomies = array();
		$drop_cats  = false;

		foreach ( $cats as $cat ) {
			$domain   = $cat['domain'] ?? '';
			$name     = sanitize_text_field( $cat['name'] ?? '' );
			if ( '' === $name ) {
				continue;
			}
			switch ( $domain ) {
				case 'book_author':
					$taxonomies[ MBS_TAX_AUTHOR ][] = $name;
					break;
				case 'book_series':
					$taxonomies[ MBS_TAX_SERIES ][] = $name;
					break;
				case 'book_genre':
					$taxonomies[ MBS_TAX_GENRE ][] = $name;
					break;
				case 'book_tag':
					$taxonomies[ MBS_TAX_TAG ][] = $name;
					break;
				case 'book_category':
					$drop_cats = true;   // log once below
					break;
				default:
					break;
			}
		}
		if ( $drop_cats ) {
			$notes[] = 'book_category taxonomy has no MBS equivalent and was not imported.';
		}

		// wbg_translator / wbg_illustrator → MBS_TAX_CONTRIBUTOR terms.
		foreach ( array( 'wbg_translator', 'wbg_illustrator' ) as $key ) {
			$v = sanitize_text_field( $meta[ $key ] ?? '' );
			if ( '' !== $v ) {
				$taxonomies[ MBS_TAX_CONTRIBUTOR ][] = $v;
			}
		}

		return array(
			'title'      => sanitize_text_field( $item_data['title'] ?? '' ),
			'content'    => wp_kses_post( $item_data['content'] ?? '' ),
			'post_meta'  => $post_meta,
			'format_row' => $format_row,
			'buy_links'  => $buy_links,
			'taxonomies' => $taxonomies,
			'notes'      => $notes,
		);
	}
}
