<?php
/**
 * BatchProcessor — processes one batch of post IDs.
 *
 * Per post:
 *   1. Strip matching <a> elements from post_content via DOM.
 *   2. Decode _elementor_data JSON; walk widget settings; strip matching
 *      <a> elements from any HTML field; re-encode.
 *   3. If anything changed, write a backup row, then save the post.
 *
 * @package Platform\Helm\Modules\LinkAssassin
 */

declare( strict_types = 1 );

namespace Platform\Helm\Modules\LinkAssassin;

use Platform\Helm\Support\ElementorDataProcessor;
use Platform\Helm\Support\HtmlLinkStripper;

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

final class BatchProcessor {

	private HtmlLinkStripper $stripper;
	private ElementorDataProcessor $elementor;

	public function __construct( private BackupManager $backups ) {
		$this->stripper  = new HtmlLinkStripper();
		$this->elementor = new ElementorDataProcessor();
	}

	/**
	 * Process a batch of post IDs.
	 *
	 * @param int[]    $post_ids
	 * @param string[] $urls
	 * @return array{posts_processed:int,posts_modified:int,links_removed:int,errors:string[],elementor_dirty:bool}
	 */
	public function process_batch( array $post_ids, array $urls ): array {
		$result = [
			'posts_processed' => 0,
			'posts_modified'  => 0,
			'links_removed'   => 0,
			'errors'          => [],
			'elementor_dirty' => false,
		];

		if ( empty( $post_ids ) || empty( $urls ) ) {
			return $result;
		}

		wp_suspend_cache_addition( true );

		foreach ( $post_ids as $post_id ) {
			$post_id = (int) $post_id;
			$post    = get_post( $post_id );
			if ( ! $post ) {
				continue;
			}
			$result['posts_processed']++;

			$original_content = (string) $post->post_content;
			$original_em      = get_post_meta( $post_id, '_elementor_data', true );
			$original_em_str  = is_string( $original_em ) ? $original_em : '';

			try {
				[ $new_content, $content_count ] = $this->stripper->strip( $original_content, $urls, false );
			} catch ( \Throwable $e ) {
				$result['errors'][] = sprintf( 'Post %d content: %s', $post_id, $e->getMessage() );
				continue;
			}

			$new_em      = $original_em_str;
			$em_count    = 0;
			if ( '' !== $original_em_str ) {
				try {
					[ $new_em, $em_count ] = $this->elementor->process(
						$original_em_str,
						fn( string $html ): array => $this->stripper->strip( $html, $urls, false ),
						false
					);
				} catch ( \Throwable $e ) {
					$result['errors'][] = sprintf( 'Post %d elementor: %s', $post_id, $e->getMessage() );
					$new_em             = $original_em_str;
					$em_count           = 0;
				}
			}

			$content_changed = ( $content_count > 0 ) && ( $new_content !== $original_content );
			$em_changed      = ( $em_count > 0 )      && ( $new_em      !== $original_em_str );

			if ( ! $content_changed && ! $em_changed ) {
				continue;
			}

			$this->backups->create_backup( $post_id, $original_content, $original_em_str, $urls );

			if ( $content_changed ) {
				$updated = wp_update_post(
					[ 'ID' => $post_id, 'post_content' => $new_content ],
					true
				);
				if ( is_wp_error( $updated ) ) {
					$result['errors'][] = sprintf( 'Post %d save: %s', $post_id, $updated->get_error_message() );
					continue;
				}
			}

			if ( $em_changed ) {
				update_post_meta( $post_id, '_elementor_data', wp_slash( $new_em ) );
				$result['elementor_dirty'] = true;
			}

			$result['posts_modified']++;
			$result['links_removed'] += ( $content_count + $em_count );
		}

		wp_suspend_cache_addition( false );
		return $result;
	}
}
