<?php
/**
 * File Path: includes/import/class-mbs-importer-wxr-inserter.php
 *
 * WXR Importer — Single-Item Inserter
 *
 * Delegates all post creation and meta writing to MBS_Book_Hydrator::hydrate().
 * Reader-platform buy links (goodreads, storygraph, bookbub) carry link_type='platform'
 * which is outside the MBS Book Object shape; they are written via MBS_Buy_Link_DAO::save()
 * directly after hydration.
 *
 * @package    My_Book_Showroom
 * @subpackage Includes/Import
 * @since      1.0.0
 */

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

class MBS_Importer_WXR_Inserter { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- mbs_/MBS_ prefix is correct; scanner not configured with plugin prefix

	/**
	 * Import a single WXR item into the MBS book post type.
	 *
	 * @param array $item_data { title, content, post_type, meta[] }
	 * @param array $mapping   Source key => MBS target field.
	 * @return true|'skipped'|string  true on success, 'skipped' on duplicate, error string on failure.
	 */
	public static function import_item( array $item_data, array $mapping ) {
		$title = sanitize_text_field( $item_data['title'] );
		if ( '' === $title ) {
			return 'No title — skipped.';
		}

		// ── Duplicate detection ───────────────────────────────────────────────
		$dup_candidates = array( 'title' => $title );

		foreach ( $mapping as $src_key => $mbs_field ) {
			if ( 'mbs_isbn13' === $mbs_field && isset( $item_data['meta'][ $src_key ] ) ) {
				$dup_candidates['isbn13'] = $item_data['meta'][ $src_key ];
			}
			if ( 'mbs_asin' === $mbs_field && isset( $item_data['meta'][ $src_key ] ) ) {
				$dup_candidates['asin'] = $item_data['meta'][ $src_key ];
			}
		}

		if ( null !== MBS_Duplicate_Detector::find_duplicate( $dup_candidates ) ) {
			return 'skipped';
		}

		// ── Build MBS Book Object from user-supplied mapping ──────────────────
		$post_meta      = array();
		$taxonomies     = array();
		$fr             = array(); // format-row fields (isbn13, asin, pub_date, page_length)
		$platform_links = array(); // goodreads/storygraph/bookbub — written after hydrate

		// Lifecycle normalisation map (applied before storing in post_meta).
		static $lifecycle_val_map = array(
			'pre_order' => 'preorder', // legacy spelling
			'published' => '',         // 'published' maps to empty lifecycle state
		);
		$lifecycle_allowed = array( '', 'draft', 'preorder', 'out_of_print', 'out_of_stock', 'discontinued', 'coming_soon' );

		foreach ( $mapping as $src_key => $mbs_field ) {
			if ( '' === $mbs_field || ! isset( $item_data['meta'][ $src_key ] ) ) {
				continue;
			}

			$raw_value = $item_data['meta'][ $src_key ];

			switch ( $mbs_field ) {

				// ── Format-row fields ─────────────────────────────────────────
				case 'mbs_isbn13':
					$fr['isbn13'] = sanitize_text_field( $raw_value );
					break;

				case 'mbs_asin':
					$fr['asin'] = sanitize_text_field( $raw_value );
					break;

				case 'mbs_pub_date':
					$fr['pub_date'] = sanitize_text_field( $raw_value );
					break;

				case 'mbs_page_count':
					$fr['page_length'] = absint( $raw_value );
					break;

				// ── Post-meta fields ──────────────────────────────────────────
				case 'mbs_series_number':
					// ARCH-SERIES-001: series position is book-level post_meta.
					$post_meta['mbs_series_position'] = sanitize_text_field( $raw_value );
					break;

				case 'mbs_publisher_url':
					$post_meta['mbs_publisher_url'] = esc_url_raw( $raw_value );
					break;

				case 'mbs_publisher':
					$post_meta[ $mbs_field ] = sanitize_text_field( $raw_value );
					break;

				case 'mbs_author_bio':
					break; // Excluded — author bio requires term_meta storage via Catalog > Authors.

				case 'mbs_subtitle':
					$post_meta['mbs_subtitle'] = sanitize_text_field( $raw_value );
					break;

				case 'mbs_synopsis':
					$post_meta['mbs_synopsis'] = sanitize_textarea_field( $raw_value );
					break;

				case 'mbs_teaser':
					$post_meta['mbs_teaser'] = sanitize_textarea_field( $raw_value );
					break;

				case 'mbs_word_count':
					$post_meta['mbs_word_count'] = absint( $raw_value );
					break;

				case 'mbs_book_status': // legacy key — fall through to lifecycle handler
				case 'mbs_lifecycle_state':
					$lc_val = sanitize_key( $raw_value );
					$lc_val = $lifecycle_val_map[ $lc_val ] ?? $lc_val;
					if ( ! in_array( $lc_val, $lifecycle_allowed, true ) ) {
						$lc_val = '';
					}
					$post_meta['mbs_lifecycle_state'] = $lc_val;
					break;

				// ── Taxonomy fields ───────────────────────────────────────────
				case 'mbs_series_name':
					$series_name = sanitize_text_field( $raw_value );
					if ( '' !== $series_name ) {
						$taxonomies[ MBS_TAX_SERIES ][] = $series_name;
					}
					break;

				// ── Reader-platform links (written after hydrate) ─────────────
				case 'mbs_goodreads_url':
				case 'mbs_storygraph_url':
				case 'mbs_bookbub_url':
					$_retailer_key = ( 'mbs_goodreads_url' === $mbs_field ) ? 'goodreads'
					               : ( ( 'mbs_storygraph_url' === $mbs_field ) ? 'storygraph' : 'bookbub' );
					$_clean_url    = esc_url_raw( $raw_value );
					if ( '' !== $_clean_url ) {
						$platform_links[] = array(
							'url'          => $_clean_url,
							'retailer_key' => $_retailer_key,
						);
					}
					break;

				default:
					// Unrecognized target — skip silently (never fatal).
					break;
			}
		}

		$book_object = array(
			'post_title'     => $title,
			'post_content'   => wp_kses_post( $item_data['content'] ),
			'post_status'    => 'publish',
			'post_meta'      => $post_meta,
			'taxonomies'     => $taxonomies,
			'format_rows'    => ! empty( $fr ) ? array( $fr ) : array(),
			'book_buy_links' => array(),
		);

		// Dedup already ran above — skip the hydrator's internal check.
		$result = MBS_Book_Hydrator::hydrate( $book_object, array( 'skip_duplicate_check' => true ) );

		if ( is_wp_error( $result ) ) {
			return 'Import failed: ' . $result->get_error_message();
		}

		$post_id = $result;

		// ── Platform reader links ─────────────────────────────────────────────
		// link_type='platform' is outside the MBS Book Object shape so these are
		// written directly after hydration rather than through the hydrator.
		foreach ( $platform_links as $pl ) {
			MBS_Buy_Link_DAO::save( array(
				'post_id'       => $post_id,
				'url'           => $pl['url'],
				'retailer_key'  => $pl['retailer_key'],
				'link_type'     => 'platform',
				'format_row_id' => null,
				'sort_order'    => 0,
			) );
		}

		return true;
	}
}
