<?php
/**
 * This file is part of the Wisewand WordPress plugin.
 *
 * @package Wisewand
 * @since 1.0.0
 * @license GPL-2.0-or-later
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */
namespace Wisewand\Content;

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use WP_Error;
use WP_Post;
use Wisewand\Utils\Options;
use Wisewand\Logging\Logger;
use Wisewand\Media\Media_Manager;

// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_error_log, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- error_log() used within WP_DEBUG conditionals; dynamic placeholder generation for IN clauses; table names derived from $wpdb->prefix are safe to interpolate; direct database calls required for custom plugin table operations

class Content_Manager {

	private $options;
	private $logger;
	private $media_manager;
	private $pull_queue_table;

	public function __construct( Options $options, Logger $logger, Media_Manager $media_manager ) {
		$this->options       = $options;
		$this->logger        = $logger;
		$this->media_manager = $media_manager;

		global $wpdb;
		$this->pull_queue_table = $wpdb->prefix . 'wisewand_pull_queue';
	}

	public function process_content( array $payload ) {
		$this->logger->debug(
			'Processing content payload',
			array(
				'external_id'  => $payload['external_id'] ?? 'unknown',
				'payload_keys' => array_keys( $payload ),
			)
		);

		// Validate required fields
		$validation_result = $this->validate_payload( $payload );
		if ( is_wp_error( $validation_result ) ) {
			return $validation_result;
		}

		// Determine if this is an update or create operation
		$existing_post = $this->find_existing_post( $payload );
		$operation     = $existing_post ? 'update' : 'create';

		// Extract categories early so they're available for debug logging later
		$category_ids = $this->extract_and_prepare_categories( $payload );

		// Prepare post data (passing extracted categories)
		$post_data = $this->prepare_post_data( $payload, $existing_post, $category_ids );
		if ( is_wp_error( $post_data ) ) {
			return $post_data;
		}

		// Handle special post types (categories vs regular posts)
		$target_post_type = $this->determine_target_post_type( $payload );

		if ( $target_post_type === 'category' ) {
			// Special handling for WordPress categories (taxonomies, not posts)
			$category_id = $this->handle_category_creation( $payload );

			if ( is_wp_error( $category_id ) ) {
				$this->logger->error(
					'Failed to create/update category',
					array(
						'error' => $category_id->get_error_message(),
					)
				);
				return $category_id;
			}

			$language = $this->process_language_for_taxonomy( $category_id, $payload );

			return array(
				'post_id'     => null,
				'category_id' => $category_id,
				'operation'   => 'category_' . ( ! empty( $payload['update_existing_category'] ) ? 'update' : 'create' ),
				'language'    => $language,
				'warnings'    => array(),
				'taxonomy'    => $this->get_taxonomy_for_post_type( $payload['target_post_type'] ?? 'category' ),
			);
		}

		// Regular post/page/product creation
		if ( WP_DEBUG ) {
			error_log( 'CREATE_POST: Operation: ' . $operation );
			error_log( 'CREATE_POST: Post data summary:' );
			error_log( '  - Title: "' . $post_data['post_title'] . '"' );
			error_log( '  - Status: ' . $post_data['post_status'] );
			error_log( '  - Type: ' . $post_data['post_type'] );
			error_log( '  - Author: ' . $post_data['post_author'] );
			error_log( '  - Content length: ' . strlen( $post_data['post_content'] ) );
		}

		if ( $operation === 'create' ) {
			if ( WP_DEBUG ) {
				error_log( 'CREATE_POST: Calling wp_insert_post...' );
			}
			$post_id = wp_insert_post( $post_data, true );
		} else {
			$post_data['ID'] = $existing_post->ID;
			if ( WP_DEBUG ) {
				error_log( 'CREATE_POST: Calling wp_update_post for ID: ' . $existing_post->ID );
			}
			$post_id = wp_update_post( $post_data, true );
		}

		if ( is_wp_error( $post_id ) ) {
			if ( WP_DEBUG ) {
				error_log( '❌ CREATE_POST: Failed - ' . $post_id->get_error_message() );
			}
			$this->logger->error(
				'Failed to save post',
				array(
					'operation' => $operation,
					'post_type' => $target_post_type,
					'error'     => $post_id->get_error_message(),
				)
			);
			return $post_id;
		}

		if ( WP_DEBUG ) {
			error_log( '✅ CREATE_POST: Post created/updated - ID: ' . $post_id );

			// CRITICAL DEBUG: Check what categories WordPress actually assigned
			$wordpress_assigned_categories = wp_get_post_categories( $post_id );
			error_log( 'CREATE_POST: WordPress assigned categories after wp_insert_post:' );
			error_log( '  - Count: ' . count( $wordpress_assigned_categories ) );
			error_log( '  - IDs: ' . implode( ', ', $wordpress_assigned_categories ) );

			if ( count( $wordpress_assigned_categories ) < count( $category_ids ) ) {
				error_log( '❌ CREATE_POST: CATEGORY BUG - WordPress only assigned ' . count( $wordpress_assigned_categories ) . ' out of ' . count( $category_ids ) . ' requested categories!' );
				error_log( '  - Requested: ' . implode( ', ', $category_ids ) );
				error_log( '  - Actually assigned: ' . implode( ', ', $wordpress_assigned_categories ) );
			}

			// Log category names
			foreach ( $wordpress_assigned_categories as $cat_id ) {
				$cat = get_category( $cat_id );
				if ( $cat && ! is_wp_error( $cat ) ) {
					error_log( '  - Assigned: ' . $cat->name . ' (ID: ' . $cat_id . ')' );
				}
			}
		}

		// Verify post was created correctly
		$created_post = get_post( $post_id );
		if ( $created_post ) {
			if ( WP_DEBUG ) {
				error_log( 'CREATE_POST: Verification - Post exists' );
				error_log( '  - Actual status: ' . $created_post->post_status );
				error_log( '  - Actual type: ' . $created_post->post_type );
				error_log( '  - Actual title: ' . $created_post->post_title );
				error_log( '  - Actual slug: ' . $created_post->post_name );
			}
		} elseif ( WP_DEBUG ) {
				error_log( '❌ CREATE_POST: CRITICAL - Post not found after creation!' );
		}

		$warnings = array();

		// Store Wisewand metadata first
		if ( WP_DEBUG ) {
			error_log( 'CREATE_POST: Storing Wisewand metadata...' );
		}
		$this->store_wisewand_metadata( $post_id, $payload );

		// Process taxonomies (categories, tags, custom taxonomies)
		if ( WP_DEBUG ) {
			error_log( 'CREATE_POST: Processing taxonomies...' );
		}
		$taxonomy_result = $this->process_taxonomies( $post_id, $payload );
		if ( is_wp_error( $taxonomy_result ) ) {
			$warnings[] = 'Taxonomy processing failed: ' . $taxonomy_result->get_error_message();
			if ( WP_DEBUG ) {
				error_log( 'CREATE_POST: Taxonomy warning: ' . $taxonomy_result->get_error_message() );
			}
		}

		// Process media FIRST (before content processing to ensure URLs are available)
		$media_warnings = $this->process_media( $post_id, $payload );
		$warnings       = array_merge( $warnings, $media_warnings );

		// Process custom fields and ACF
		$fields_result = $this->process_custom_fields( $post_id, $payload );
		if ( is_wp_error( $fields_result ) ) {
			$warnings[] = 'Custom fields processing failed: ' . $fields_result->get_error_message();
		}

		// Handle WPML/multilingual BEFORE SEO processing (language affects SEO)
		$language = $this->process_language( $post_id, $payload );

		// Process SEO data AFTER media and language are set
		$seo_result = $this->process_seo_data( $post_id, $payload );
		if ( is_wp_error( $seo_result ) ) {
			$warnings[] = 'SEO data processing failed: ' . $seo_result->get_error_message();
		}

		// Enhanced post-processing for API imports
		if ( isset( $payload['output'] ) || isset( $payload['data']['output'] ) ) {
			if ( WP_DEBUG ) {
				error_log( 'CREATE_POST: Running import enhancement...' );
			}
			$enhancement_warnings = $this->run_import_enhancement( $post_id, $payload );
			$warnings             = array_merge( $warnings, $enhancement_warnings );
		}

		// FINAL VERIFICATION: Check permalink and accessibility
		if ( WP_DEBUG ) {
			error_log( 'CREATE_POST: Final verification...' );
		}

		// Clean post cache to ensure fresh permalink generation
		clean_post_cache( $post_id );

		// Get the actual permalink WordPress generated
		$permalink = get_permalink( $post_id );
		if ( WP_DEBUG ) {
			error_log( '✅ CREATE_POST: Final permalink: ' . $permalink );
		}

		// Verify categories (critical for /%category%/ permalink structure)
		$final_categories = wp_get_post_categories( $post_id );
		if ( empty( $final_categories ) ) {
			if ( WP_DEBUG ) {
				error_log( '❌ CREATE_POST: WARNING - Post has NO categories after all processing!' );
			}
			$warnings[] = 'Post created without categories - may cause 404 with current permalink structure';
		} elseif ( WP_DEBUG ) {
				error_log( '✅ CREATE_POST: Final categories: ' . implode( ', ', $final_categories ) );
		}

		// Verify featured image
		if ( has_post_thumbnail( $post_id ) ) {
			$thumb_id = get_post_thumbnail_id( $post_id );
			if ( WP_DEBUG ) {
				error_log( '✅ CREATE_POST: Featured image set (ID: ' . $thumb_id . ')' );
			}
		} elseif ( WP_DEBUG ) {
				error_log( '⚠️  CREATE_POST: No featured image set' );
		}

		// Final summary log
		if ( WP_DEBUG ) {
			error_log( '=== CREATE_POST: COMPLETE ===' );
			error_log( 'Post ID: ' . $post_id );
			error_log( 'Title: ' . get_the_title( $post_id ) );
			error_log( 'Status: ' . get_post_status( $post_id ) );
			error_log( 'Type: ' . get_post_type( $post_id ) );
			error_log( 'Permalink: ' . $permalink );
			error_log( 'Categories: ' . count( $final_categories ) );
			error_log( 'Warnings: ' . count( $warnings ) );
			error_log( '============================' );
		}

		$this->logger->info(
			'Content processed successfully',
			array(
				'post_id'        => $post_id,
				'operation'      => $operation,
				'language'       => $language,
				'permalink'      => $permalink,
				'warnings_count' => count( $warnings ),
			)
		);

		return array(
			'post_id'   => $post_id,
			'operation' => $operation,
			'language'  => $language,
			'permalink' => $permalink,  // Add permalink to result
			'warnings'  => $warnings,
		);
	}

	private function run_import_enhancement( $post_id, $payload ) {
		// Load Import_Enhancer if not already loaded
		if ( ! class_exists( 'Wisewand\\Utils\\Import_Enhancer' ) ) {
			$enhancer_file = WISEWAND_PLUGIN_DIR . 'includes/Utils/Import_Enhancer.php';
			if ( file_exists( $enhancer_file ) ) {
				require_once $enhancer_file;
			}
		}

		if ( class_exists( 'Wisewand\\Utils\\Import_Enhancer' ) ) {
			$enhancer = new \Wisewand\Utils\Import_Enhancer( $this->logger, $this->options );
			return $enhancer->enhance_post_import( $post_id, $payload );
		}

		return array( 'Import enhancer not available' );
	}

	public function pull_content( $article_id, $output_index = 0 ) {
		$this->logger->info(
			'Starting pull operation',
			array(
				'article_id'   => $article_id,
				'output_index' => $output_index,
			)
		);

		// Check if already in queue
		$existing_queue_item = $this->get_queue_item( $article_id );

		if ( $existing_queue_item ) {
			if ( $existing_queue_item->status === 'completed' ) {
				return new WP_Error(
					'wisewand_already_processed',
					__( 'Article has already been processed successfully.', 'wisewand-ai-content-writer-seo-content-generator' ),
					array( 'status' => 409 )
				);
			}

			if ( $existing_queue_item->status === 'pending' ) {
				return array(
					'status'      => 'pending',
					'retry_after' => $this->calculate_retry_after( $existing_queue_item ),
					'attempts'    => $existing_queue_item->attempts,
				);
			}
		}

		// Fetch content from Wisewand API
		$content_data = $this->fetch_from_wisewand_api( $article_id );

		if ( is_wp_error( $content_data ) ) {
			return $content_data;
		}

		if ( $content_data['status'] !== 'completed' ) {
			// Article not ready yet, schedule retry
			$this->schedule_pull_retry( $article_id, $output_index );

			return array(
				'status'      => 'pending',
				'retry_after' => $this->get_next_retry_delay( 1 ),
				'attempts'    => 1,
			);
		}

		// Process the content
		$output_data = $this->extract_output_data( $content_data, $output_index );
		if ( is_wp_error( $output_data ) ) {
			return $output_data;
		}

		$process_result = $this->process_content( $output_data );
		if ( is_wp_error( $process_result ) ) {
			$this->update_queue_item( $article_id, 'failed', $process_result->get_error_message() );
			return $process_result;
		}

		// Mark as completed
		$this->update_queue_item( $article_id, 'completed', null, $process_result['post_id'] );

		return array_merge( $process_result, array( 'status' => 'completed' ) );
	}

	public function process_pull_retry( $article_id ) {
		$this->logger->debug( 'Processing pull retry', array( 'article_id' => $article_id ) );

		$queue_item = $this->get_queue_item( $article_id );
		if ( ! $queue_item || $queue_item->status !== 'pending' ) {
			return;
		}

		if ( $queue_item->attempts >= $queue_item->max_attempts ) {
			$this->update_queue_item( $article_id, 'failed', 'Maximum retry attempts exceeded' );
			$this->logger->warning(
				'Pull retry failed - max attempts exceeded',
				array(
					'article_id' => $article_id,
					'attempts'   => $queue_item->attempts,
				)
			);
			return;
		}

		// Try to fetch content again
		$content_data = $this->fetch_from_wisewand_api( $article_id );

		if ( is_wp_error( $content_data ) ) {
			$this->increment_queue_attempts( $article_id, $content_data->get_error_message() );
			$this->schedule_next_retry( $article_id );
			return;
		}

		if ( $content_data['status'] !== 'completed' ) {
			// Still not ready, schedule another retry
			$this->increment_queue_attempts( $article_id );
			$this->schedule_next_retry( $article_id );
			return;
		}

		// Content is ready, process it
		$meta         = json_decode( $queue_item->meta, true ) ?: array();
		$output_index = $meta['output_index'] ?? 0;

		$output_data = $this->extract_output_data( $content_data, $output_index );
		if ( is_wp_error( $output_data ) ) {
			$this->update_queue_item( $article_id, 'failed', $output_data->get_error_message() );
			return;
		}

		$process_result = $this->process_content( $output_data );
		if ( is_wp_error( $process_result ) ) {
			$this->update_queue_item( $article_id, 'failed', $process_result->get_error_message() );
			return;
		}

		// Success!
		$this->update_queue_item( $article_id, 'completed', null, $process_result['post_id'] );

		$this->logger->info(
			'Pull retry completed successfully',
			array(
				'article_id' => $article_id,
				'post_id'    => $process_result['post_id'],
				'attempts'   => $queue_item->attempts + 1,
			)
		);
	}

	private function validate_payload( array $payload ) {
		$required_fields = array( 'external_id' );

		foreach ( $required_fields as $field ) {
			if ( empty( $payload[ $field ] ) ) {
				return new WP_Error(
					'wisewand_missing_field',
					sprintf(
						/* translators: %s: Field name that is missing from the payload */
						__( 'Required field missing: %s', 'wisewand-ai-content-writer-seo-content-generator' ),
						$field
					)
				);
			}
		}

		// Validate post type if provided
		if ( isset( $payload['post_type'] ) ) {
			$allowed_types = $this->options->get_content_settings()['allowed_post_types'];
			if ( ! in_array( $payload['post_type'], $allowed_types, true ) ) {
				return new WP_Error(
					'wisewand_invalid_post_type',
					sprintf(
						/* translators: %s: Post type that is not allowed */
						__( 'Post type not allowed: %s', 'wisewand-ai-content-writer-seo-content-generator' ),
						$payload['post_type']
					)
				);
			}
		}

		return true;
	}

	private function find_existing_post( array $payload ) {
		global $wpdb;

		$external_id = sanitize_text_field( $payload['external_id'] );
		$language    = $this->determine_language( $payload );

		// Build query to find existing post
		$sql = "
            SELECT p.* FROM %i p
            INNER JOIN %i pm ON p.ID = pm.post_id
            WHERE pm.meta_key = '_wisewand_external_id'
            AND pm.meta_value = %s
        ";

		$args = array( $wpdb->posts, $wpdb->postmeta, $external_id );

		// Add language condition if WPML is active
		if ( $this->options->is_wpml_active() && $language ) {
			$sql   .= " AND p.ID IN (
                SELECT element_id FROM %i
                WHERE language_code = %s AND element_type LIKE 'post_%'
            )";
			$args[] = $wpdb->prefix . 'icl_translations';
			$args[] = $language;
		}

		$sql .= ' LIMIT 1';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- JOIN query more efficient than WP_Query for external ID lookup
		$post = $wpdb->get_row( $wpdb->prepare( $sql, $args ) );

		return $post ? new WP_Post( $post ) : null;
	}

	private function prepare_post_data( array $payload, ?WP_Post $existing_post = null, array $category_ids = array() ) {
		$content_settings = $this->options->get_content_settings();

		// Handle post type selection (user override vs smart default)
		$post_type = $this->determine_target_post_type( $payload );

		// Handle existing content updates
		$existing_content_id = $this->find_existing_content_for_upgmdate( $payload );

		// Categories are now passed as parameter (extracted early in process_content)
		// This ensures they're available for both wp_insert_post and debug logging

		// Start with payload data
		$post_data = array(
			'post_type'     => $post_type,
			'post_status'   => $payload['post_status'] ?? $content_settings['default_post_status'],
			'post_title'    => $this->extract_title( $payload ),
			'post_content'  => $this->extract_content( $payload ),
			'post_excerpt'  => $this->extract_excerpt( $payload ),
			'post_author'   => $this->determine_author( $payload ),
			// FIX #1: Include categories in wp_insert_post() to prevent auto-assignment
			'post_category' => $category_ids,
		);

		// CRITICAL DEBUG: Log exactly what we're passing to wp_insert_post
		if ( WP_DEBUG ) {
			error_log( 'PREPARE_POST_DATA: About to call wp_insert_post with:' );
			if ( is_array( $category_ids ) ) {
				error_log( '  - post_category count: ' . count( $category_ids ) );
				error_log( '  - post_category IDs: ' . implode( ', ', $category_ids ) );
				error_log( '  - post_category is_array: YES' );
			} else {
				error_log( '  - post_category is_array: NO - Type: ' . gettype( $category_ids ) );
			}
			error_log( '  - post_category raw: ' . wp_json_encode( $category_ids ) );
		}

		// If updating existing content, set the ID
		if ( $existing_content_id ) {
			$post_data['ID'] = $existing_content_id;
		}

		// Use Wisewand URL as post slug (priority over post_name)
		if ( isset( $payload['output']['url'] ) && ! empty( $payload['output']['url'] ) ) {
			$url = $payload['output']['url'];

			// Extract just the slug from the URL (remove domain and protocol)
			$parsed = wp_parse_url( $url );
			if ( isset( $parsed['path'] ) ) {
				// Get the path and remove leading/trailing slashes
				$path          = trim( $parsed['path'], '/' );
				$wisewand_slug = sanitize_title( $path );
			} else {
				// Fallback: sanitize the whole URL (shouldn't happen)
				$wisewand_slug = sanitize_title( $url );
			}

			if ( ! empty( $wisewand_slug ) ) {
				$post_data['post_name'] = $wisewand_slug;
				$this->logger->debug(
					'Using Wisewand URL as post slug',
					array(
						'original_url'   => $url,
						'extracted_path' => $path ?? 'N/A',
						'sanitized_slug' => $wisewand_slug,
					)
				);
			}
		} elseif ( isset( $payload['post_name'] ) && $content_settings['allow_slug_override'] ) {
			$post_data['post_name'] = sanitize_title( $payload['post_name'] );
		}

		if ( isset( $payload['post_date'] ) ) {
			// v1.2.6: post_date comes in as local WordPress time (e.g., "2025-11-11 19:39:37")
			// WordPress handles GMT conversion internally via get_gmt_from_date()
			$post_data['post_date'] = $payload['post_date'];

			// Set status to future if date is in the future
			if ( strtotime( $payload['post_date'] ) > current_time( 'timestamp' ) ) {
				$post_data['post_status'] = 'future';

				if ( WP_DEBUG ) {
					error_log( sprintf(
						'CONTENT_MANAGER: Setting status=future (post_date %s is in future)',
						$payload['post_date']
					) );
				}
			}
		}

		// Additional optional fields
		foreach ( array( 'comment_status', 'ping_status', 'post_parent', 'menu_order', 'post_password' ) as $field ) {
			if ( isset( $payload[ $field ] ) ) {
				$post_data[ $field ] = $payload[ $field ];
			}
		}

		// Handle sticky posts
		if ( isset( $payload['sticky'] ) && $payload['sticky'] ) {
			stick_post( $post_data['ID'] ?? 0 );
		}

		return $post_data;
	}

	private function extract_title( array $payload ) {
		// Priority: output.h1 (without HTML tags) > input.title > fallback
		if ( isset( $payload['output']['h1'] ) ) {
			return wp_strip_all_tags( $payload['output']['h1'] );
		}

		if ( isset( $payload['input']['title'] ) ) {
			return sanitize_text_field( $payload['input']['title'] );
		}

		if ( isset( $payload['title'] ) ) {
			return sanitize_text_field( $payload['title'] );
		}

		return __( 'Untitled', 'wisewand-ai-content-writer-seo-content-generator' );
	}

	private function extract_content( array $payload ) {
		$content = '';

		if ( isset( $payload['output']['content'] ) ) {
			$content = $payload['output']['content'];
		} elseif ( isset( $payload['content'] ) ) {
			$content = $payload['content'];
		}

		// Clean content using Content_Cleaner
		if ( ! class_exists( 'Wisewand\\Utils\\Content_Cleaner' ) ) {
			$cleaner_file = WISEWAND_PLUGIN_DIR . 'includes/Utils/Content_Cleaner.php';
			if ( file_exists( $cleaner_file ) ) {
				require_once $cleaner_file;
			}
		}

		if ( class_exists( 'Wisewand\\Utils\\Content_Cleaner' ) ) {
			$post_type = $payload['post_type'] ?? 'post';
			$content   = \Wisewand\Utils\Content_Cleaner::format_for_post_type( $content, $post_type );
		}

		// Sanitize HTML content
		$allowed_html = wp_kses_allowed_html( 'post' );

		// Allow additional tags for rich content
		$allowed_html['iframe'] = array(
			'src'             => true,
			'width'           => true,
			'height'          => true,
			'frameborder'     => true,
			'allowfullscreen' => true,
			'loading'         => true,
		);

		// Allow audio tags for audio players (simple format)
		$allowed_html['audio'] = array(
			'controls'                => true,
			'preload'                 => true,
			'style'                   => true,
			'data-wisewand-preserved' => true,
		);

		$allowed_html['source'] = array(
			'src'  => true,
			'type' => true,
		);

		// Allow div with wp-audio-player class (universal format)
		if ( ! isset( $allowed_html['div'] ) ) {
			$allowed_html['div'] = array();
		}
		$allowed_html['div']['class'] = true;
		$allowed_html['div']['style'] = true;

		return wp_kses( $content, $allowed_html );
	}

	private function extract_excerpt( array $payload ) {
		if ( isset( $payload['excerpt'] ) ) {
			return sanitize_textarea_field( $payload['excerpt'] );
		}

		if ( isset( $payload['output']['meta_description'] ) ) {
			return sanitize_textarea_field( $payload['output']['meta_description'] );
		}

		return '';
	}

	/**
	 * Extract and prepare categories BEFORE wp_insert_post()
	 *
	 * CRITICAL FIX: This prevents WordPress from auto-assigning default_category
	 * By including post_category in wp_insert_post(), we tell WordPress exactly
	 * which categories to use, preventing the "Assurance" bug.
	 *
	 * PRIORITY CASCADE:
	 * 1. Manual categories (RSS feed target_categories)
	 * 2. API categories (publishwordpress_category)
	 * 3. AI matching (if enabled and no manual)
	 * 4. Default category (last resort)
	 *
	 * @param array $payload Content payload with categories
	 * @return array Category IDs ready for wp_insert_post()
	 */
	private function extract_and_prepare_categories( array $payload ) {
		$content_settings = $this->options->get_content_settings();
		$category_ids     = array();

		if ( WP_DEBUG ) {
			error_log( 'CATEGORY_EXTRACT: Starting category extraction' );
			error_log( 'CATEGORY_EXTRACT: Payload categories: ' . ( isset( $payload['categories'] ) ? wp_json_encode( $payload['categories'] ) : 'NOT SET' ) );
		}

		// PRIORITY 1 & 2: Manual or API categories
		if ( isset( $payload['categories'] ) && ! empty( $payload['categories'] ) ) {
			if ( WP_DEBUG ) {
				error_log( 'CATEGORY_EXTRACT: Processing provided categories...' );
			}

			// Use existing process_category_terms method (validates, creates if needed)
			$processed_ids = $this->process_category_terms(
				$payload['categories'],
				$content_settings['auto_create_categories']
			);

			if ( is_wp_error( $processed_ids ) ) {
				if ( WP_DEBUG ) {
					error_log( 'CATEGORY_EXTRACT: ERROR processing categories: ' . $processed_ids->get_error_message() );
				}
				$category_ids = array();
			} else {
				$category_ids = $processed_ids;
				if ( WP_DEBUG ) {
					error_log( 'CATEGORY_EXTRACT: Processed category IDs: ' . implode( ', ', $category_ids ) );
				}
			}
		}

		// FIX #2: Auto-include hierarchical parents
		if ( ! empty( $category_ids ) ) {
			$category_ids = $this->ensure_hierarchical_parents_included( $category_ids );
			if ( WP_DEBUG ) {
				error_log( 'CATEGORY_EXTRACT: After parent inclusion: ' . implode( ', ', $category_ids ) );
			}
		}

		// PRIORITY 3: AI Category Matching (if enabled and no categories yet)
		if ( empty( $category_ids ) ) {
			if ( WP_DEBUG ) {
				error_log( 'CATEGORY_EXTRACT: No manual categories provided' );
			}

			// Check if AI matching flag is enabled
			$use_ai_matching = $payload['use_ai_category_matching'] ?? false;

			if ( WP_DEBUG ) {
				error_log( 'CATEGORY_EXTRACT: AI matching flag: ' . ( $use_ai_matching ? 'ENABLED' : 'DISABLED' ) );
			}

			if ( $use_ai_matching ) {
				// Try AI matching
				$ai_result = $this->match_article_to_categories( $payload );

				if ( ! is_wp_error( $ai_result ) && ! empty( $ai_result ) ) {
					$category_ids = $ai_result;

					if ( WP_DEBUG ) {
						error_log( '✅ AI_CATEGORY_MATCH: Successfully matched to categories: ' . implode( ', ', $category_ids ) );
					}
				} elseif ( is_wp_error( $ai_result ) ) {
					if ( WP_DEBUG ) {
						error_log( '❌ AI_CATEGORY_MATCH: Failed - ' . $ai_result->get_error_message() );
					}
				} else {
					if ( WP_DEBUG ) {
						error_log( 'AI_CATEGORY_MATCH: No categories matched' );
					}
				}
			}
		}

		// PRIORITY 4: Fallback - WordPress default_category (last resort)
		if ( empty( $category_ids ) ) {
			$default_cat = get_option( 'default_category' );
			if ( $default_cat && term_exists( (int) $default_cat, 'category' ) ) {
				$category_ids = array( (int) $default_cat );
				if ( WP_DEBUG ) {
					error_log( 'CATEGORY_EXTRACT: Using WordPress default_category: ' . $default_cat );
				}
			} else {
				// Find first available category (last resort)
				$all_categories = get_terms(
					array(
						'taxonomy'   => 'category',
						'hide_empty' => false,
						'number'     => 1,
						'orderby'    => 'name',
						'order'      => 'ASC',
					)
				);

				if ( ! is_wp_error( $all_categories ) && ! empty( $all_categories ) ) {
					$first_category = $all_categories[0];
					$category_ids   = array( (int) $first_category->term_id );
					if ( WP_DEBUG ) {
						error_log( 'CATEGORY_EXTRACT: Using first available category: "' . $first_category->name . '" (ID: ' . $first_category->term_id . ')' );
					}
				}
			}
		}

		if ( WP_DEBUG ) {
			error_log( 'CATEGORY_EXTRACT: Final category IDs for wp_insert_post: ' . implode( ', ', $category_ids ) );

			// Log category names for clarity
			foreach ( $category_ids as $cat_id ) {
				$cat = get_category( $cat_id );
				if ( $cat && ! is_wp_error( $cat ) ) {
					error_log( '  - ' . $cat->name . ' (ID: ' . $cat_id . ', Parent: ' . $cat->parent . ')' );
				}
			}
		}

		return $category_ids;
	}

	/**
	 * Ensure hierarchical parent categories are included
	 *
	 * WordPress hierarchical categories work best when both parent and child are assigned.
	 * This prevents issues with themes/plugins that expect the full category tree.
	 *
	 * Example: If assigning "Électrique" (child of "Voiture"), also assign "Voiture" parent.
	 *
	 * @param array $category_ids Original category IDs
	 * @return array Category IDs with parents included
	 */
	private function ensure_hierarchical_parents_included( array $category_ids ) {
		$complete_ids = array();

		foreach ( $category_ids as $cat_id ) {
			$cat_id = (int) $cat_id;

			// Add the original category
			if ( ! in_array( $cat_id, $complete_ids ) ) {
				$complete_ids[] = $cat_id;
			}

			// Walk up the category tree to root
			$current = get_category( $cat_id );

			while ( $current && ! is_wp_error( $current ) && $current->parent > 0 ) {
				$parent_id = (int) $current->parent;

				if ( ! in_array( $parent_id, $complete_ids ) ) {
					$complete_ids[] = $parent_id;
					if ( WP_DEBUG ) {
						$parent = get_category( $parent_id );
						if ( $parent && ! is_wp_error( $parent ) ) {
							error_log( 'CATEGORY_HIERARCHY: Auto-included parent "' . $parent->name . '" (ID: ' . $parent_id . ') for child ID: ' . $cat_id );
						}
					}
				}

				// Move to next parent up the tree
				$current = get_category( $parent_id );
			}
		}

		if ( WP_DEBUG && count( $complete_ids ) > count( $category_ids ) ) {
			error_log( 'CATEGORY_HIERARCHY: Expanded ' . count( $category_ids ) . ' categories to ' . count( $complete_ids ) . ' (with parents)' );
		}

		return $complete_ids;
	}

	/**
	 * Match article to categories using AI
	 *
	 * Uses Category_Matcher to intelligently match article content to best categories
	 * when use_ai_category_matching flag is enabled and no manual categories provided.
	 *
	 * @param array $payload Content payload with title and content
	 * @return array|WP_Error Array of category IDs or WP_Error on failure
	 */
	private function match_article_to_categories( array $payload ) {
		if ( WP_DEBUG ) {
			$title = $payload['title'] ?? $payload['post_title'] ?? 'Unknown';
			error_log( '🤖 AI_CATEGORY_MATCH: Starting AI matching for article: "' . substr( $title, 0, 50 ) . '..."' );
		}

		// Check if Category_Matcher class exists
		if ( ! class_exists( 'Wisewand\\Utils\\Category_Matcher' ) ) {
			if ( WP_DEBUG ) {
				error_log( 'AI_CATEGORY_MATCH: Category_Matcher class not found' );
			}
			return new WP_Error(
				'category_matcher_not_found',
				__( 'Category_Matcher class not available', 'wisewand-ai-content-writer-seo-content-generator' )
			);
		}

		// Instantiate Category_Matcher
		try {
			$category_matcher = new \Wisewand\Utils\Category_Matcher( $this->options, $this->logger );

			// Check if OpenAI is configured
			if ( ! $category_matcher->is_available() ) {
				if ( WP_DEBUG ) {
					error_log( 'AI_CATEGORY_MATCH: OpenAI not configured' );
				}
				return new WP_Error(
					'openai_not_configured',
					__( 'OpenAI API not configured', 'wisewand-ai-content-writer-seo-content-generator' )
				);
			}

			if ( WP_DEBUG ) {
				error_log( 'AI_CATEGORY_MATCH: Calling Category_Matcher->match_article_to_category()' );
			}

			// Extract article data
			$title   = $payload['title'] ?? $payload['post_title'] ?? '';
			$content = $payload['content'] ?? $payload['post_content'] ?? '';
			$lang    = $payload['lang'] ?? $payload['language'] ?? 'en';

			// Call AI matching
			$result = $category_matcher->match_article_to_category( $title, $content, $lang );

			if ( is_wp_error( $result ) ) {
				if ( WP_DEBUG ) {
					error_log( 'AI_CATEGORY_MATCH: Matching failed - ' . $result->get_error_message() );
				}
				return $result;
			}

			if ( WP_DEBUG ) {
				if ( ! empty( $result ) ) {
					$category_names = array();
					foreach ( $result as $cat_id ) {
						$cat = get_category( $cat_id );
						if ( $cat && ! is_wp_error( $cat ) ) {
							$category_names[] = $cat->name . ' (ID: ' . $cat_id . ')';
						}
					}
					error_log( '✅ AI_CATEGORY_MATCH: Matched to categories: ' . implode( ', ', $category_names ) );
				} else {
					error_log( 'AI_CATEGORY_MATCH: No suitable categories found' );
				}
			}

			return $result;

		} catch ( \Exception $e ) {
			if ( WP_DEBUG ) {
				error_log( 'AI_CATEGORY_MATCH: Exception - ' . $e->getMessage() );
			}
			return new WP_Error(
				'ai_matching_exception',
				sprintf(
					/* translators: %s: error message */
					__( 'AI matching failed: %s', 'wisewand-ai-content-writer-seo-content-generator' ),
					$e->getMessage()
				)
			);
		}
	}

	private function determine_author( array $payload ) {
		$content_settings = $this->options->get_content_settings();

		// Priority 1: Explicit author_id in payload
		if ( isset( $payload['author_id'] ) && is_numeric( $payload['author_id'] ) ) {
			$user = get_user_by( 'id', (int) $payload['author_id'] );
			if ( $user ) {
				return $user->ID;
			}
		}

		// Priority 2: Explicit author_email in payload
		if ( isset( $payload['author_email'] ) ) {
			$user = get_user_by( 'email', sanitize_email( $payload['author_email'] ) );
			if ( $user ) {
				return $user->ID;
			}
		}

		// Priority 3: Persona→Author mapping from settings (NEW)
		if ( ! empty( $payload['persona_id'] ) ) {
			$lang = $payload['lang'] ?? $payload['input']['lang'] ?? 'en';

			// Get author mapped to this language's persona (centralized fallback chain)
			$author_id = $this->options->get_author_for_language( $lang );

			if ( $author_id && is_numeric( $author_id ) ) {
				$user = get_user_by( 'id', (int) $author_id );
				if ( $user ) {
					$this->logger->debug(
						'Using persona→author mapping',
						array(
							'lang'        => $lang,
							'persona_id'  => $payload['persona_id'],
							'author_id'   => $author_id,
							'author_name' => $user->display_name,
						)
					);
					return $user->ID;
				}
			}
		}

		// Priority 4: User who created the calendar entry
		if ( ! empty( $payload['created_by'] ) && is_numeric( $payload['created_by'] ) ) {
			$user = get_user_by( 'id', (int) $payload['created_by'] );
			if ( $user ) {
				$this->logger->debug(
					'Using entry creator as author',
					array(
						'author_id'   => $user->ID,
						'author_name' => $user->display_name,
					)
				);
				return $user->ID;
			}
		}

		// Final fallback
		return $content_settings['fallback_author'];
	}

	private function determine_language( array $payload ) {
		if ( ! $this->options->is_wpml_active() ) {
			return null;
		}

		// Check for manual language override first
		if ( isset( $payload['wpml_language_override'] ) && ! empty( $payload['wpml_language_override'] ) ) {
			$this->logger->info(
				'Using manual language override',
				array(
					'override_language' => $payload['wpml_language_override'],
					'original_lang'     => $payload['lang'] ?? 'unknown',
				)
			);
			return $payload['wpml_language_override'];
		}

		// Use WPML Manager for smart detection
		$wpml_manager = $this->get_wpml_manager();
		if ( $wpml_manager ) {
			$input_data = array(
				'lang'    => $payload['lang'] ?? $payload['input']['lang'] ?? '',
				'country' => $payload['country'] ?? $payload['input']['country'] ?? '',
			);

			return $wpml_manager->determine_wpml_language( $input_data );
		}

		return null;
	}

	private function parse_gmdate( $date_string ) {
		$timestamp = strtotime( $date_string );
		return $timestamp ? gmdate( 'Y-m-d H:i:s', $timestamp ) : null;
	}

	private function store_wisewand_metadata( $post_id, array $payload ) {
		// Store external ID for future updates
		update_post_meta( $post_id, '_wisewand_external_id', sanitize_text_field( $payload['external_id'] ) );

		// Store original input data (without sensitive info)
		$input_data = $payload['input'] ?? array();
		unset( $input_data['api_key'], $input_data['secret'] );
		update_post_meta( $post_id, '_wisewand_input_data', $input_data );

		// Store output data for SEO processing
		$output_data = $payload['output'] ?? array();
		if ( ! empty( $output_data ) ) {
			update_post_meta( $post_id, '_wisewand_output_data', $output_data );
		}

		// Store processing timestamp
		update_post_meta( $post_id, '_wisewand_processed_at', current_time( 'mysql' ) );

		// Store import method for tracking
		update_post_meta( $post_id, '_wisewand_import_method', 'api_import' );

		// Store article version if available
		if ( isset( $payload['version'] ) ) {
			update_post_meta( $post_id, '_wisewand_article_version', $payload['version'] );
		}

		// Store schema/JSON-LD if present
		if ( isset( $payload['schema'] ) || isset( $payload['json_ld'] ) ) {
			$schema = $payload['schema'] ?? $payload['json_ld'];
			update_post_meta( $post_id, '_wisewand_schema_json', wp_json_encode( $schema ) );
		}

		// Store Wisewand article URL/slug for reference
		if ( isset( $payload['output']['url'] ) ) {
			update_post_meta( $post_id, '_wisewand_original_url', sanitize_text_field( $payload['output']['url'] ) );
		}
	}

	private function process_taxonomies( $post_id, array $payload ) {
		$content_settings = $this->options->get_content_settings();

		if ( WP_DEBUG ) {
			error_log( 'TAXONOMY: Processing taxonomies for post ' . $post_id );
			error_log( 'TAXONOMY: Payload categories: ' . ( isset( $payload['categories'] ) ? wp_json_encode( $payload['categories'] ) : 'NOT SET' ) );
		}

		// OPTIMIZED: Categories were set in wp_insert_post() via post_category parameter
		// This method now VERIFIES they were set correctly and fixes if needed
		$current_categories  = wp_get_post_categories( $post_id );
		$expected_categories = $payload['categories'] ?? array();

		if ( WP_DEBUG ) {
			error_log( 'TAXONOMY: Verifying category assignment for post ' . $post_id );
			error_log( 'TAXONOMY: Expected categories: ' . ( is_array( $expected_categories ) ? wp_json_encode( $expected_categories ) : 'NOT ARRAY' ) );
			error_log( 'TAXONOMY: Current assigned categories: ' . ( empty( $current_categories ) ? 'NONE' : implode( ', ', $current_categories ) ) );

			if ( ! empty( $current_categories ) ) {
				foreach ( $current_categories as $cat_id ) {
					$cat = get_category( $cat_id );
					if ( $cat && ! is_wp_error( $cat ) ) {
						error_log( 'TAXONOMY: - Currently assigned: ' . $cat->name . ' (ID: ' . $cat_id . ', Parent: ' . $cat->parent . ')' );
					}
				}
			}
		}

		// Re-process categories if provided in payload
		// We always re-extract to ensure we have the correct list (including hierarchy)
		$category_ids = array();

		if ( isset( $payload['categories'] ) && ! empty( $payload['categories'] ) ) {
			if ( WP_DEBUG ) {
				error_log( 'TAXONOMY: Re-processing categories from payload to verify correctness...' );
			}

			$category_ids = $this->process_category_terms( $payload['categories'], $content_settings['auto_create_categories'] );

			if ( is_wp_error( $category_ids ) ) {
				if ( WP_DEBUG ) {
					error_log( 'TAXONOMY: ERROR processing categories: ' . $category_ids->get_error_message() );
				}
				$category_ids = array();
			} else {
				// Include hierarchical parents
				$category_ids = $this->ensure_hierarchical_parents_included( $category_ids );

				if ( WP_DEBUG ) {
					error_log( 'TAXONOMY: Re-processed category IDs (with parents): ' . implode( ', ', $category_ids ) );
				}

				// CRITICAL: Check if WordPress assigned all the categories we wanted
				$missing_categories = array_diff( $category_ids, $current_categories );

				if ( ! empty( $missing_categories ) || count( $current_categories ) !== count( $category_ids ) ) {
					if ( WP_DEBUG ) {
						error_log( '⚠️  TAXONOMY: WordPress did not assign all categories correctly!' );
						error_log( '  - Expected: ' . implode( ', ', $category_ids ) );
						error_log( '  - Got: ' . implode( ', ', $current_categories ) );
						error_log( '  - Missing: ' . implode( ', ', $missing_categories ) );
						error_log( '  - Will call wp_set_post_categories to fix...' );
					}
					// Will be fixed below by wp_set_post_categories
				} elseif ( WP_DEBUG ) {
						error_log( '✅ TAXONOMY: All categories correctly assigned by wp_insert_post!' );
				}
			}
		} else {
			if ( WP_DEBUG ) {
				error_log( 'TAXONOMY: No categories in payload, keeping WordPress-assigned categories' );
			}
			$category_ids = $current_categories;
		}

		// CRITICAL FIX: If no categories assigned, ensure post has at least one category
		// This is REQUIRED for permalink structures with /%category%/
		// MUST work on ANY WordPress site (not hardcode specific category names)
		if ( empty( $category_ids ) && empty( $current_categories ) ) {
			if ( WP_DEBUG ) {
				error_log( 'TAXONOMY: No categories assigned, searching for suitable category...' );
			}

			$default_cat = get_option( 'default_category' );
			if ( WP_DEBUG ) {
				error_log( 'TAXONOMY: WordPress default_category option: "' . ( $default_cat ?: 'EMPTY' ) . '"' );
			}

			// If default_category option is not set or invalid, find ANY existing category
			if ( empty( $default_cat ) || ! term_exists( (int) $default_cat, 'category' ) ) {
				if ( WP_DEBUG ) {
					error_log( 'TAXONOMY: Default category not configured, finding first available category...' );
				}

				// Get the first available category (sorted by name)
				$all_categories = get_terms(
					array(
						'taxonomy'   => 'category',
						'hide_empty' => false,
						'number'     => 1,
						'orderby'    => 'name',
						'order'      => 'ASC',
					)
				);

				if ( ! is_wp_error( $all_categories ) && ! empty( $all_categories ) ) {
					$first_category = $all_categories[0];
					$default_cat    = $first_category->term_id;
					if ( WP_DEBUG ) {
						error_log( 'TAXONOMY: Found first category: "' . $first_category->name . '" (ID: ' . $default_cat . ')' );
					}

					// Set as WordPress default for future imports
					update_option( 'default_category', $default_cat );
					if ( WP_DEBUG ) {
						error_log( 'TAXONOMY: Set as WordPress default_category for future imports' );
					}
				} else {
					// NO categories exist on this WordPress site!
					if ( WP_DEBUG ) {
						error_log( 'TAXONOMY: No categories exist in WordPress, creating "Uncategorized"...' );
					}

					// Create standard "Uncategorized" category
					$new_cat = wp_insert_term(
						'Uncategorized',
						'category',
						array(
							'slug'        => 'uncategorized',
							'description' => 'Default category for imported content',
						)
					);

					if ( ! is_wp_error( $new_cat ) ) {
						$default_cat = $new_cat['term_id'];
						if ( WP_DEBUG ) {
							error_log( 'TAXONOMY: Created "Uncategorized" category - ID: ' . $default_cat );
						}

						// Set as WordPress default
						update_option( 'default_category', $default_cat );
						if ( WP_DEBUG ) {
							error_log( 'TAXONOMY: Set "Uncategorized" as WordPress default_category' );
						}
					} elseif ( WP_DEBUG ) {
							error_log( '❌ TAXONOMY: CRITICAL - Could not create category: ' . $new_cat->get_error_message() );
					}
				}
			}

			// Validate we have a valid category ID
			if ( $default_cat ) {
				$default_term = get_term( $default_cat, 'category' );
				if ( $default_term && ! is_wp_error( $default_term ) ) {
					$category_ids = array( (int) $default_cat );
					if ( WP_DEBUG ) {
						error_log( '✅ TAXONOMY: Will assign category "' . $default_term->name . '" (ID: ' . $default_cat . ')' );
					}
				} elseif ( WP_DEBUG ) {
						error_log( '❌ TAXONOMY: Category ID ' . $default_cat . ' is invalid after all checks!' );
				}
			} elseif ( WP_DEBUG ) {
					error_log( '❌ TAXONOMY: Could not determine any category to assign!' );
			}
		}

		// CRITICAL FIX: Always call wp_set_post_categories if we have categories to assign
		// This ensures ALL selected categories are assigned, even if wp_insert_post() was incomplete
		if ( ! empty( $category_ids ) ) {
			// Check if we need to update categories
			$needs_update = false;

			if ( empty( $current_categories ) ) {
				$needs_update = true;
				if ( WP_DEBUG ) {
					error_log( 'TAXONOMY: No categories currently assigned - needs update' );
				}
			} else {
				// Check if current categories match expected categories
				$current_sorted  = $current_categories;
				$expected_sorted = $category_ids;
				sort( $current_sorted );
				sort( $expected_sorted );

				if ( $current_sorted !== $expected_sorted ) {
					$needs_update = true;
					if ( WP_DEBUG ) {
						error_log( 'TAXONOMY: Categories mismatch - needs update' );
						error_log( '  - Current (sorted): ' . implode( ', ', $current_sorted ) );
						error_log( '  - Expected (sorted): ' . implode( ', ', $expected_sorted ) );
					}
				}
			}

			if ( $needs_update ) {
				if ( WP_DEBUG ) {
					error_log( 'TAXONOMY: Calling wp_set_post_categories with ' . count( $category_ids ) . ' categories: ' . implode( ', ', $category_ids ) );
				}

				$result = wp_set_post_categories( $post_id, $category_ids );

				if ( is_wp_error( $result ) ) {
					if ( WP_DEBUG ) {
						error_log( '❌ TAXONOMY: ERROR - wp_set_post_categories failed: ' . $result->get_error_message() );
					}
				} elseif ( WP_DEBUG ) {
						error_log( 'TAXONOMY: wp_set_post_categories returned: ' . wp_json_encode( $result ) );

						// VERIFY assignment worked
						$assigned = wp_get_post_categories( $post_id );
					if ( empty( $assigned ) ) {
						error_log( '❌ TAXONOMY: CRITICAL - Categories not assigned! Verification failed!' );
					} else {
						error_log( '✅ TAXONOMY: Categories verified - ' . count( $assigned ) . ' categories assigned: ' . implode( ', ', $assigned ) );

						// Log category names for clarity
						foreach ( $assigned as $cat_id ) {
							$cat = get_category( $cat_id );
							if ( $cat && ! is_wp_error( $cat ) ) {
								error_log( '   - ' . $cat->name . ' (ID: ' . $cat_id . ', Slug: ' . $cat->slug . ', Parent: ' . $cat->parent . ')' );
							}
						}
					}
				}
			} elseif ( WP_DEBUG ) {
					error_log( '✅ TAXONOMY: Categories already correct (' . count( $category_ids ) . ' categories), no update needed' );
			}
		} elseif ( empty( $category_ids ) && empty( $current_categories ) ) {
			if ( WP_DEBUG ) {
				error_log( '❌ TAXONOMY: CRITICAL - No categories to assign! Post will have NO categories!' );
			}
		}

		// Process tags
		if ( isset( $payload['tags'] ) ) {
			$tag_ids = $this->process_tag_terms( $payload['tags'], $content_settings['auto_create_tags'] );
			if ( ! is_wp_error( $tag_ids ) ) {
				wp_set_post_tags( $post_id, $tag_ids );
			}
		}

		// Process custom taxonomies
		$custom_taxonomies = get_object_taxonomies( get_post_type( $post_id ), 'objects' );
		foreach ( $custom_taxonomies as $taxonomy ) {
			if ( in_array( $taxonomy->name, array( 'category', 'post_tag' ), true ) ) {
				continue; // Skip built-in taxonomies already processed
			}

			if ( isset( $payload['taxonomies'][ $taxonomy->name ] ) ) {
				$term_ids = $this->process_custom_taxonomy_terms(
					$payload['taxonomies'][ $taxonomy->name ],
					$taxonomy->name,
					$content_settings['auto_create_categories'] // Use same setting
				);

				if ( ! is_wp_error( $term_ids ) ) {
					wp_set_object_terms( $post_id, $term_ids, $taxonomy->name );
				}
			}
		}

		return true;
	}

	private function process_category_terms( $categories, $auto_create ) {
		if ( ! is_array( $categories ) ) {
			$categories = array( $categories );
		}

		$category_ids = array();

		// Separate numeric IDs from names/slugs for batch processing
		$numeric_ids = array();
		$names_slugs = array();

		foreach ( $categories as $category ) {
			if ( is_numeric( $category ) ) {
				$numeric_ids[] = (int) $category;
			} else {
				$names_slugs[] = $category;
			}
		}

		// BATCH QUERY 1: Validate all numeric IDs at once (eliminates N queries)
		if ( ! empty( $numeric_ids ) ) {
			global $wpdb;
			$placeholders = implode( ',', array_fill( 0, count( $numeric_ids ), '%d' ) );
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dynamic placeholders for IN clause, direct query more efficient than get_terms()
			$valid_ids = $wpdb->get_col(
				$wpdb->prepare(
					"SELECT t.term_id FROM {$wpdb->terms} t
                 INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
                 WHERE t.term_id IN ($placeholders) AND tt.taxonomy = 'category'",
					$numeric_ids
				)
			);

			if ( ! empty( $valid_ids ) ) {
				$category_ids = array_merge( $category_ids, array_map( 'intval', $valid_ids ) );
			}
		}

		// BATCH QUERY 2: Find all names/slugs at once (eliminates 2N queries)
		if ( ! empty( $names_slugs ) ) {
			global $wpdb;
			$sanitized_names = array_map( 'sanitize_text_field', $names_slugs );
			$sanitized_slugs = array_map( 'sanitize_title', $names_slugs );

			$placeholders = implode( ',', array_fill( 0, count( $sanitized_names ), '%s' ) );

			// Single query to find terms by name OR slug
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dynamic placeholders for IN clause, direct query more efficient than get_terms()
			$found_terms = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT t.term_id, t.name, t.slug FROM {$wpdb->terms} t
                 INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
                 WHERE tt.taxonomy = 'category'
                 AND (t.name IN ($placeholders) OR t.slug IN ($placeholders))",
					array_merge( $sanitized_names, $sanitized_slugs )
				),
				OBJECT_K
			);

			// Build lookup maps for O(1) access
			$terms_by_name = array();
			$terms_by_slug = array();
			foreach ( $found_terms as $term ) {
				$terms_by_name[ strtolower( $term->name ) ] = $term->term_id;
				$terms_by_slug[ $term->slug ]               = $term->term_id;
			}

			// Match categories to found terms
			foreach ( $names_slugs as $category ) {
				$sanitized_name = sanitize_text_field( $category );
				$sanitized_slug = sanitize_title( $category );

				$found_id = null;

				// Try slug match first (more reliable)
				if ( isset( $terms_by_slug[ $sanitized_slug ] ) ) {
					$found_id = $terms_by_slug[ $sanitized_slug ];
				}
				// Try name match (case-insensitive)
				elseif ( isset( $terms_by_name[ strtolower( $sanitized_name ) ] ) ) {
					$found_id = $terms_by_name[ strtolower( $sanitized_name ) ];
				}

				if ( $found_id ) {
					$category_ids[] = (int) $found_id;
				} elseif ( $auto_create ) {
					// Create new category
					$new_term = wp_insert_term( $sanitized_name, 'category' );
					if ( ! is_wp_error( $new_term ) ) {
						$category_ids[] = $new_term['term_id'];
					}
				}
			}
		}

		return array_unique( $category_ids );
	}

	private function process_tag_terms( $tags, $auto_create ) {
		if ( ! is_array( $tags ) ) {
			$tags = array( $tags );
		}

		$tag_names = array();

		// Separate numeric IDs from names for batch processing
		$numeric_ids = array();
		$name_tags   = array();

		foreach ( $tags as $tag ) {
			if ( is_numeric( $tag ) ) {
				$numeric_ids[] = (int) $tag;
			} else {
				$name_tags[] = sanitize_text_field( $tag );
			}
		}

		// BATCH QUERY 1: Convert all numeric IDs to names at once (eliminates N queries)
		if ( ! empty( $numeric_ids ) ) {
			global $wpdb;
			$placeholders = implode( ',', array_fill( 0, count( $numeric_ids ), '%d' ) );
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dynamic placeholders for IN clause, direct query more efficient than get_terms()
			$found_tags = $wpdb->get_col(
				$wpdb->prepare(
					"SELECT t.name FROM {$wpdb->terms} t
                 INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
                 WHERE t.term_id IN ($placeholders) AND tt.taxonomy = 'post_tag'",
					$numeric_ids
				)
			);

			if ( ! empty( $found_tags ) ) {
				$tag_names = array_merge( $tag_names, $found_tags );
			}
		}

		// BATCH QUERY 2: Check if name tags exist (if not auto-creating)
		if ( ! empty( $name_tags ) ) {
			if ( $auto_create ) {
				// If auto-creating, just add all names (wp_set_post_tags handles creation)
				$tag_names = array_merge( $tag_names, $name_tags );
			} else {
				global $wpdb;
				$placeholders = implode( ',', array_fill( 0, count( $name_tags ), '%s' ) );
                // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dynamic placeholders for IN clause, direct query more efficient than get_terms()
				$existing_tags = $wpdb->get_col(
					$wpdb->prepare(
						"SELECT t.name FROM {$wpdb->terms} t
                     INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
                     WHERE tt.taxonomy = 'post_tag'
                     AND (t.name IN ($placeholders) OR t.slug IN ($placeholders))",
						array_merge( $name_tags, array_map( 'sanitize_title', $name_tags ) )
					)
				);

				if ( ! empty( $existing_tags ) ) {
					$tag_names = array_merge( $tag_names, $existing_tags );
				}
			}
		}

		return array_unique( $tag_names );
	}

	private function process_custom_taxonomy_terms( $terms, $taxonomy, $auto_create ) {
		if ( ! is_array( $terms ) ) {
			$terms = array( $terms );
		}

		$term_ids = array();

		// Separate numeric IDs from names/slugs for batch processing
		$numeric_ids = array();
		$names_slugs = array();

		foreach ( $terms as $term ) {
			if ( is_numeric( $term ) ) {
				$numeric_ids[] = (int) $term;
			} else {
				$names_slugs[] = $term;
			}
		}

		// BATCH QUERY 1: Validate all numeric IDs at once (eliminates N queries)
		if ( ! empty( $numeric_ids ) ) {
			global $wpdb;
			$placeholders = implode( ',', array_fill( 0, count( $numeric_ids ), '%d' ) );
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dynamic placeholders for IN clause, direct query more efficient than get_terms()
			$valid_ids = $wpdb->get_col(
				$wpdb->prepare(
					"SELECT t.term_id FROM {$wpdb->terms} t
                 INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
                 WHERE t.term_id IN ($placeholders) AND tt.taxonomy = %s",
					array_merge( $numeric_ids, array( $taxonomy ) )
				)
			);

			if ( ! empty( $valid_ids ) ) {
				$term_ids = array_merge( $term_ids, array_map( 'intval', $valid_ids ) );
			}
		}

		// BATCH QUERY 2: Find all names/slugs at once (eliminates 2N queries)
		if ( ! empty( $names_slugs ) ) {
			global $wpdb;
			$sanitized_names = array_map( 'sanitize_text_field', $names_slugs );
			$sanitized_slugs = array_map( 'sanitize_title', $names_slugs );

			$placeholders = implode( ',', array_fill( 0, count( $sanitized_names ), '%s' ) );

			// Single query to find terms by name OR slug
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dynamic placeholders for IN clause, direct query more efficient than get_terms()
			$found_terms = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT t.term_id, t.name, t.slug FROM {$wpdb->terms} t
                 INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
                 WHERE tt.taxonomy = %s
                 AND (t.name IN ($placeholders) OR t.slug IN ($placeholders))",
					array_merge( array( $taxonomy ), $sanitized_names, $sanitized_slugs )
				),
				OBJECT_K
			);

			// Build lookup maps for O(1) access
			$terms_by_name = array();
			$terms_by_slug = array();
			foreach ( $found_terms as $term ) {
				$terms_by_name[ strtolower( $term->name ) ] = $term->term_id;
				$terms_by_slug[ $term->slug ]               = $term->term_id;
			}

			// Match terms to found results
			foreach ( $names_slugs as $term_input ) {
				$sanitized_name = sanitize_text_field( $term_input );
				$sanitized_slug = sanitize_title( $term_input );

				$found_id = null;

				// Try slug match first
				if ( isset( $terms_by_slug[ $sanitized_slug ] ) ) {
					$found_id = $terms_by_slug[ $sanitized_slug ];
				}
				// Try name match
				elseif ( isset( $terms_by_name[ strtolower( $sanitized_name ) ] ) ) {
					$found_id = $terms_by_name[ strtolower( $sanitized_name ) ];
				}

				if ( $found_id ) {
					$term_ids[] = (int) $found_id;
				} elseif ( $auto_create ) {
					// Create new term
					$new_term = wp_insert_term( $sanitized_name, $taxonomy );
					if ( ! is_wp_error( $new_term ) ) {
						$term_ids[] = $new_term['term_id'];
					}
				}
			}
		}

		return array_unique( $term_ids );
	}

	private function process_media( $post_id, array $payload ) {
		$warnings = array();

		// Process featured image (AI metadata generated in Import_Enhancer, not here)
		// This is the fallback path for direct API imports without Import_Enhancer
		if ( isset( $payload['featured_image_url'] ) || isset( $payload['output']['cover_image'] ) ) {
			$image_url = $payload['featured_image_url'] ?? $payload['output']['cover_image'];
			if ( $image_url ) {
				// No AI metadata here - that's handled by Import_Enhancer for full imports
				$result = $this->media_manager->download_featured_image( $image_url, $post_id, array() );
				if ( is_wp_error( $result ) ) {
					$warnings[] = 'Featured image download failed: ' . $result->get_error_message();
				}
			}
		}

		// Process gallery images (AI metadata generated in Import_Enhancer, not here)
		$gallery_urls = array();
		if ( isset( $payload['cover_images'] ) && is_array( $payload['cover_images'] ) ) {
			$gallery_urls = array_merge( $gallery_urls, $payload['cover_images'] );
		}
		if ( isset( $payload['output']['cover_images'] ) && is_array( $payload['output']['cover_images'] ) ) {
			$gallery_urls = array_merge( $gallery_urls, $payload['output']['cover_images'] );
		}

		if ( ! empty( $gallery_urls ) ) {
			// No AI metadata here - that's handled by Import_Enhancer for full imports
			$gallery_result = $this->media_manager->download_gallery_images( $gallery_urls, $post_id, array() );
			foreach ( $gallery_result['errors'] as $error ) {
				$warnings[] = 'Gallery image download failed: ' . $error['error'];
			}
		}

		// Process audio
		if ( isset( $payload['audio'] ) || isset( $payload['output']['audio'] ) ) {
			$audio_url = $payload['audio'] ?? $payload['output']['audio'];
			if ( $audio_url ) {
				$result = $this->media_manager->download_audio( $audio_url, $post_id );
				if ( is_wp_error( $result ) ) {
					$warnings[] = 'Audio download failed: ' . $result->get_error_message();
				}
			}
		}

		// Process inline images and audio in content
		$post = get_post( $post_id );
		if ( $post ) {
			$updated_content = $post->post_content;

			// Process inline images with AI metadata (if enabled and context available)
			$output          = $payload['output'] ?? array();
			$updated_content = $this->media_manager->process_inline_images(
				$updated_content,
				$post_id,
				$post->post_title,
				$updated_content,
				$output
			);

			// Process inline audio
			$updated_content = $this->media_manager->process_inline_audio( $updated_content, $post_id );

			// Update post content if any changes were made
			if ( $updated_content !== $post->post_content ) {
				wp_update_post(
					array(
						'ID'           => $post_id,
						'post_content' => $updated_content,
					)
				);

				$this->logger->info(
					'Updated post content with processed media',
					array(
						'post_id'               => $post_id,
						'content_length_before' => strlen( $post->post_content ),
						'content_length_after'  => strlen( $updated_content ),
					)
				);
			}
		}

		return $warnings;
	}

	private function process_custom_fields( $post_id, array $payload ) {
		$whitelist = $this->options->get_custom_fields_whitelist();

		// Process general custom fields
		if ( isset( $payload['custom_fields'] ) && is_array( $payload['custom_fields'] ) ) {
			foreach ( $payload['custom_fields'] as $key => $value ) {
				if ( in_array( $key, $whitelist, true ) ) {
					update_post_meta( $post_id, sanitize_key( $key ), $this->sanitize_meta_value( $value ) );
				}
			}
		}

		// Process ACF fields if enabled
		if ( $this->options->is_acf_active() ) {
			$acf_settings = $this->options->get_acf_settings();
			if ( $acf_settings['enabled'] && isset( $payload['acf'] ) && is_array( $payload['acf'] ) ) {
				$this->process_acf_fields( $post_id, $payload['acf'], $acf_settings );
			}
		}

		return true;
	}

	private function process_acf_fields( $post_id, array $acf_data, array $acf_settings ) {
		foreach ( $acf_data as $field_key => $value ) {
			if ( $acf_settings['mode'] === 'field_key' ) {
				// Update by field key
				update_field( $field_key, $this->sanitize_meta_value( $value ), $post_id );
			} else {
				// Update by field name
				$field_object = get_field_object( $field_key, $post_id );
				if ( $field_object ) {
					update_field( $field_object['key'], $this->sanitize_meta_value( $value ), $post_id );
				}
			}
		}
	}

	private function process_seo_data( $post_id, array $payload ) {
		// This will be handled by the SEO_Manager via save_post hook
		// Store in meta for hook processing
		$seo_data = array();

		if ( isset( $payload['output']['meta_title'] ) ) {
			$seo_data['title'] = $payload['output']['meta_title'];
		}

		if ( isset( $payload['output']['meta_description'] ) ) {
			$seo_data['description'] = $payload['output']['meta_description'];
		}

		if ( isset( $payload['seo'] ) ) {
			$seo_data = array_merge( $seo_data, $payload['seo'] );
		}

		if ( ! empty( $seo_data ) ) {
			update_post_meta( $post_id, '_wisewand_seo_data', $seo_data );

			// Trigger save_post hook again so SEO_Manager can process the data
			// The data wasn't available during the initial wp_insert_post/wp_update_post call
			// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- Using WordPress core hook, not creating it
			// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WordPress core save_post action hook, cannot be prefixed
			do_action( 'save_post', $post_id, get_post( $post_id ), false );
		}

		return true;
	}

	private function process_language( $post_id, array $payload ) {
		if ( ! $this->options->is_wpml_active() ) {
			return null;
		}

		$language = $this->determine_language( $payload );
		if ( ! $language ) {
			return null;
		}

		// Use WPML Manager for proper language handling
		$wpml_manager = $this->get_wpml_manager();
		if ( $wpml_manager ) {
			$wpml_manager->set_post_language( $post_id, $language );

			// Handle translation linking if specified
			if ( isset( $payload['translate_of_external_id'] ) ) {
				$original_post = $wpml_manager->find_post_by_external_id( $payload['translate_of_external_id'] );
				if ( $original_post ) {
					$wpml_manager->link_as_translation( $post_id, $original_post->ID, $language );
					$this->logger->info(
						'Linked post as translation',
						array(
							'post_id'          => $post_id,
							'original_post_id' => $original_post->ID,
							'language'         => $language,
						)
					);
				}
			}
		}

		return $language;
	}

	private function get_wpml_manager() {
		$plugin = \Wisewand\Core\Plugin::instance();
		return $plugin->get_wpml_manager();
	}

	private function sanitize_meta_value( $value ) {
		if ( is_array( $value ) ) {
			return array_map( array( $this, 'sanitize_meta_value' ), $value );
		}

		if ( is_string( $value ) ) {
			return sanitize_textarea_field( $value );
		}

		return $value;
	}

	private function fetch_from_wisewand_api( $article_id ) {
		$pull_settings = $this->options->get_pull_settings();

		$url = trailingslashit( $pull_settings['base_url'] ) . 'articles/' . urlencode( $article_id ) . '/output';

		$args = array(
			'timeout' => 30,
			'headers' => array(
				'User-Agent' => 'Wisewand-plugin/' . WISEWAND_PLUGIN_VERSION,
				'Accept'     => 'application/json',
			),
		);

		if ( ! empty( $pull_settings['api_key'] ) ) {
			$args['headers']['Authorization'] = 'Bearer ' . $pull_settings['api_key'];
		}

		$response = wp_remote_get( $url, $args );

		if ( is_wp_error( $response ) ) {
			return new WP_Error(
				'wisewand_api_error',
				sprintf(
					/* translators: %s: Error message from the API request */
					__( 'API request failed: %s', 'wisewand-ai-content-writer-seo-content-generator' ),
					$response->get_error_message()
				)
			);
		}

		$response_code = wp_remote_retrieve_response_code( $response );
		if ( $response_code !== 200 ) {
			return new WP_Error(
				'wisewand_api_http_error',
				sprintf(
					/* translators: %d: HTTP response code (e.g., 404, 500) */
					__( 'API returned HTTP %d', 'wisewand-ai-content-writer-seo-content-generator' ),
					$response_code
				),
				array( 'status' => $response_code )
			);
		}

		$body = wp_remote_retrieve_body( $response );
		$data = json_decode( $body, true );

		if ( json_last_error() !== JSON_ERROR_NONE ) {
			return new WP_Error(
				'wisewand_api_invalid_json',
				__( 'API returned invalid JSON', 'wisewand-ai-content-writer-seo-content-generator' )
			);
		}

		return $data;
	}

	private function extract_output_data( $api_data, $output_index ) {
		if ( isset( $api_data['all_outputs'] ) && is_array( $api_data['all_outputs'] ) ) {
			if ( ! isset( $api_data['all_outputs'][ $output_index ] ) ) {
				return new WP_Error(
					'wisewand_invalid_output_index',
					sprintf(
						/* translators: %d: Output index number (e.g., 0, 1, 2) */
						__( 'Output index %d not found', 'wisewand-ai-content-writer-seo-content-generator' ),
						$output_index
					)
				);
			}
			$output_data = $api_data['all_outputs'][ $output_index ];
		} else {
			$output_data = $api_data;
		}

		// Ensure we have required data
		if ( ! isset( $output_data['id'] ) ) {
			return new WP_Error(
				'wisewand_missing_id',
				__( 'Article ID missing from API response', 'wisewand-ai-content-writer-seo-content-generator' )
			);
		}

		// Transform API data to internal format
		return array(
			'external_id'        => $output_data['id'],
			'title'              => $output_data['output']['h1'] ?? $output_data['input']['title'] ?? '',
			'content'            => $output_data['output']['content'] ?? '',
			'excerpt'            => $output_data['output']['meta_description'] ?? '',
			'post_status'        => $output_data['output']['publishwordpress_status'] ?? 'draft',
			'featured_image_url' => $output_data['output']['cover_image'] ?? null,
			'cover_images'       => $output_data['output']['cover_images'] ?? array(),
			'audio'              => $output_data['output']['audio'] ?? null,
			'categories'         => isset( $output_data['output']['publishwordpress_category'] ) ?
				array( $output_data['output']['publishwordpress_category'] ) : array(),
			'seo'                => array(
				'title'         => $output_data['output']['meta_title'] ?? '',
				'description'   => $output_data['output']['meta_description'] ?? '',
				'canonical_url' => $output_data['output']['url'] ?? '',
			),
			'input'              => $output_data['input'] ?? array(),
			'output'             => $output_data['output'] ?? array(),
		);
	}

	// Queue management methods for PULL mode

	private function get_queue_item( $article_id ) {
		global $wpdb;
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom plugin table query
		// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name from $wpdb->prefix is safe
		return $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$this->pull_queue_table} WHERE article_id = %s",
				$article_id
			)
		);
	}

	private function schedule_pull_retry( $article_id, $output_index = 0, $attempt = 1 ) {
		global $wpdb;

		$next_attempt = gmdate( 'Y-m-d H:i:s', time() + $this->get_next_retry_delay( $attempt ) );

		$data = array(
			'article_id'   => $article_id,
			'status'       => 'pending',
			'attempts'     => $attempt,
			'next_attempt' => $next_attempt,
			'meta'         => wp_json_encode( array( 'output_index' => $output_index ) ),
		);

        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom plugin table operations
		$existing = $this->get_queue_item( $article_id );
		if ( $existing ) {
			$wpdb->update( $this->pull_queue_table, $data, array( 'article_id' => $article_id ) );
		} else {
			$wpdb->insert( $this->pull_queue_table, $data );
		}

		// Schedule WP-Cron event
		wp_schedule_single_event( strtotime( $next_attempt ), 'wisewand_pull_retry', array( $article_id ) );
	}

	private function update_queue_item( $article_id, $status, $error_message = null, $post_id = null ) {
		global $wpdb;

		$data = array(
			'status'     => $status,
			'updated_at' => current_time( 'mysql' ),
		);

		if ( $error_message ) {
			$data['error_message'] = $error_message;
		}

		if ( $post_id ) {
			$meta            = json_decode( $this->get_queue_item( $article_id )->meta ?? '{}', true );
			$meta['post_id'] = $post_id;
			$data['meta']    = wp_json_encode( $meta );
		}

		$wpdb->update( $this->pull_queue_table, $data, array( 'article_id' => $article_id ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom plugin table update
	}

	private function increment_queue_attempts( $article_id, $error_message = null ) {
		global $wpdb;

		$queue_item   = $this->get_queue_item( $article_id );
		$new_attempts = $queue_item ? $queue_item->attempts + 1 : 1;

		$data = array(
			'attempts'   => $new_attempts,
			'updated_at' => current_time( 'mysql' ),
		);

		if ( $error_message ) {
			$data['error_message'] = $error_message;
		}

		$wpdb->update( $this->pull_queue_table, $data, array( 'article_id' => $article_id ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom plugin table update
	}

	private function schedule_next_retry( $article_id ) {
		$queue_item = $this->get_queue_item( $article_id );
		if ( ! $queue_item ) {
			return;
		}

		$next_attempt = $queue_item->attempts + 1;
		if ( $next_attempt > $queue_item->max_attempts ) {
			$this->update_queue_item( $article_id, 'failed', 'Maximum retry attempts exceeded' );
			return;
		}

		$delay             = $this->get_next_retry_delay( $next_attempt );
		$next_attempt_time = gmdate( 'Y-m-d H:i:s', time() + $delay );

		global $wpdb;
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom plugin table update
		$wpdb->update(
			$this->pull_queue_table,
			array( 'next_attempt' => $next_attempt_time ),
			array( 'article_id' => $article_id )
		);

		wp_schedule_single_event( time() + $delay, 'wisewand_pull_retry', array( $article_id ) );
	}

	private function get_next_retry_delay( $attempt ) {
		// Exponential backoff: 1min, 2min, 5min, 10min, 20min, then 30min for remaining attempts
		$delays = array( 60, 120, 300, 600, 1200 ); // in seconds
		return $delays[ min( $attempt - 1, count( $delays ) - 1 ) ] ?? 1800;
	}

	private function calculate_retry_after( $queue_item ) {
		if ( ! $queue_item->next_attempt ) {
			return null;
		}

		$next_time = strtotime( $queue_item->next_attempt );
		$now       = time();

		return max( 0, $next_time - $now );
	}

	private function determine_target_post_type( $payload ) {
		// Check for user override first
		if ( ! empty( $payload['target_post_type'] ) ) {
			return $payload['target_post_type'];
		}

		// Smart defaults based on content type
		$content_type = $payload['content_type_source'] ?? 'articles';

		switch ( $content_type ) {
			case 'articles':
				return 'post';
			case 'categorypages':
				return 'category'; // Special handling for categories
			case 'productpages':
				return class_exists( 'WooCommerce' ) ? 'product' : 'post';
			default:
				return 'post';
		}
	}

	private function find_existing_content_for_upgmdate( $payload ) {
		// Check if user wants to update existing content
		if ( ! empty( $payload['update_existing_product'] ) ) {
			$existing_post = get_post( $payload['update_existing_product'] );
			return $existing_post && $existing_post->post_type === 'product' ? $existing_post->ID : null;
		}

		if ( ! empty( $payload['update_existing_category'] ) ) {
			// For categories, we'll handle this differently as they're taxonomies, not posts
			return null;
		}

		return null;
	}

	private function handle_category_creation( $payload ) {
		// Determine taxonomy and category details
		$target_post_type = $payload['target_post_type'] ?? 'category';
		$taxonomy         = $this->get_taxonomy_for_post_type( $target_post_type );

		$category_name = $this->extract_title( $payload );

		// For categories, use content but clean it for description field
		$full_content         = $this->extract_content( $payload );
		$category_description = $this->prepare_category_description( $full_content, $payload );

		$this->logger->info(
			'Creating/updating category',
			array(
				'target_post_type'   => $target_post_type,
				'taxonomy'           => $taxonomy,
				'category_name'      => $category_name,
				'description_length' => strlen( $category_description ),
			)
		);

		// Check if updating existing category
		if ( ! empty( $payload['update_existing_category'] ) ) {
			return $this->update_existing_category( $payload, $taxonomy, $category_name, $category_description );
		}

		// Create new category
		$result = wp_insert_term(
			$category_name,
			$taxonomy,
			array(
				'description' => $category_description,
			)
		);

		if ( is_wp_error( $result ) ) {
			return $result;
		}

		$category_id = $result['term_id'];

		// Store Wisewand metadata for the category
		update_term_meta( $category_id, '_wisewand_external_id', $payload['external_id'] );
		update_term_meta( $category_id, '_wisewand_processed_at', current_time( 'mysql' ) );
		update_term_meta( $category_id, '_wisewand_import_method', 'api_import' );

		// Store full content in meta for reference (since categories only have description)
		if ( ! empty( $payload['content'] ) ) {
			update_term_meta( $category_id, '_wisewand_full_content', $payload['content'] );
		}

		// Store SEO data for the category
		if ( ! empty( $payload['seo'] ) ) {
			update_term_meta( $category_id, '_wisewand_seo_data', $payload['seo'] );
		}

		$this->logger->info(
			'Created new category from Wisewand',
			array(
				'category_id'      => $category_id,
				'category_name'    => $category_name,
				'taxonomy'         => $taxonomy,
				'external_id'      => $payload['external_id'],
				'has_seo_data'     => ! empty( $payload['seo'] ),
				'has_full_content' => ! empty( $payload['content'] ),
			)
		);

		return $category_id;
	}

	private function get_taxonomy_for_post_type( $post_type ) {
		switch ( $post_type ) {
			case 'product_cat':
				return 'product_cat'; // WooCommerce product categories
			case 'category':
			default:
				return 'category'; // WordPress categories
		}
	}

	private function update_existing_category( $payload, $taxonomy, $category_name, $category_description ) {
		$category_info = $this->parse_existing_category_id( $payload['update_existing_category'] );

		if ( ! $category_info ) {
			return new \WP_Error( 'invalid_category', 'Invalid existing category selection' );
		}

		$category_id     = $category_info['id'];
		$target_taxonomy = $category_info['taxonomy'];

		// Verify the category exists in the expected taxonomy
		$existing_term = get_term( $category_id, $target_taxonomy );
		if ( is_wp_error( $existing_term ) ) {
			return $existing_term;
		}

		$result = wp_update_term(
			$category_id,
			$target_taxonomy,
			array(
				'name'        => $category_name,
				'description' => $category_description,
			)
		);

		if ( is_wp_error( $result ) ) {
			return $result;
		}

		// Update Wisewand metadata
		update_term_meta( $category_id, '_wisewand_external_id', $payload['external_id'] );
		update_term_meta( $category_id, '_wisewand_processed_at', current_time( 'mysql' ) );

		// Store SEO data for the category
		if ( ! empty( $payload['seo'] ) ) {
			update_term_meta( $category_id, '_wisewand_seo_data', $payload['seo'] );
		}

		$this->logger->info(
			'Updated existing category',
			array(
				'category_id'   => $category_id,
				'category_name' => $category_name,
				'taxonomy'      => $target_taxonomy,
				'external_id'   => $payload['external_id'],
			)
		);

		return $category_id;
	}

	private function parse_existing_category_id( $category_selection ) {
		// Parse the category selection format: "wp_cat_123" or "woo_cat_456"
		if ( strpos( $category_selection, 'wp_cat_' ) === 0 ) {
			return array(
				'id'       => (int) str_replace( 'wp_cat_', '', $category_selection ),
				'taxonomy' => 'category',
			);
		} elseif ( strpos( $category_selection, 'woo_cat_' ) === 0 ) {
			return array(
				'id'       => (int) str_replace( 'woo_cat_', '', $category_selection ),
				'taxonomy' => 'product_cat',
			);
		}

		return null;
	}

	private function process_language_for_taxonomy( $term_id, $payload ) {
		if ( ! $this->options->is_wpml_active() ) {
			return null;
		}

		$language = $this->determine_language( $payload );
		if ( ! $language ) {
			return null;
		}

		// Set taxonomy term language in WPML
		global $sitepress;
		if ( $sitepress ) {
			$sitepress->set_element_language_details(
				$term_id,
				'tax_category',
				false,
				$language
			);

			$this->logger->info(
				'Set category language in WPML',
				array(
					'category_id' => $term_id,
					'language'    => $language,
				)
			);
		}

		return $language;
	}

	private function prepare_category_description( $content, $payload ) {
		// Clean content for use as category description
		if ( empty( $content ) ) {
			return $this->extract_excerpt( $payload );
		}

		// Load Content_Cleaner for processing
		if ( ! class_exists( 'Wisewand\\Utils\\Content_Cleaner' ) ) {
			$cleaner_file = WISEWAND_PLUGIN_DIR . 'includes/Utils/Content_Cleaner.php';
			if ( file_exists( $cleaner_file ) ) {
				require_once $cleaner_file;
			}
		}

		if ( class_exists( 'Wisewand\\Utils\\Content_Cleaner' ) ) {
			// Clean and strip HTML for category description
			$cleaned_content = \Wisewand\Utils\Content_Cleaner::clean_content(
				$content,
				array(
					'remove_h1'              => true,
					'fix_headings'           => false, // Keep original structure
					'clean_empty_paragraphs' => true,
					'fix_encoded_html'       => true,
				)
			);

			// For categories, we can include some HTML in descriptions
			// But remove complex elements and keep it clean
			$description = wp_kses(
				$cleaned_content,
				array(
					'p'      => array(),
					'br'     => array(),
					'strong' => array(),
					'em'     => array(),
					'b'      => array(),
					'i'      => array(),
					'a'      => array(
						'href'  => true,
						'title' => true,
					),
					'ul'     => array(),
					'ol'     => array(),
					'li'     => array(),
				)
			);

			// Limit length for category descriptions (WordPress recommendation)
			if ( strlen( $description ) > 1000 ) {
				$description = wp_trim_words( $description, 100 ) . '...';
			}

			return $description;
		}

		// Fallback: strip all HTML
		return wp_strip_all_tags( $content );
	}
}
