<?php
/**
 * Full-site batched content scan — Pro overlay only.
 *
 * Secure design (rafter-secure-design / auth):
 * - Identity: REST/CLI/cron already gated by module capabilities.
 * - AuthZ: This file is absent from the wordpress.org Lite zip. Lite keeps
 *   the quick scan. Overlay + license unlocks the full-site batch runner.
 *
 * @package AIAltTextGenerator
 * @since 2.5.3
 */

namespace AIAltTextGenerator;

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

/**
 * Full-site content scan runner. Not loaded in Lite.
 *
 * @since 2.5.3
 */
final class PremiumFullScan {

	/**
	 * @return array<string, mixed>
	 */
	public static function start(): array {
		if ( ! FeatureGate::isPro() ) {
			return [
				'status'  => 'failed',
				'message' => __( 'Full-site content scans are available in Pro.', 'wp-powersuite' ),
			];
		}

		$post_types = ContentScanner::getPostTypes();
		$total      = ContentScanner::countPosts( $post_types );

		$progress = [
			'status'               => 'running',
			'scan_mode'            => 'full',
			'offset'               => 0,
			'total_posts'          => $total,
			'posts_scanned'        => 0,
			'posts_with_issues'    => 0,
			'images_missing_alt'   => 0,
			'issue_attachment_ids' => [],
			'sample_issues'        => [],
			'started_at'           => gmdate( 'Y-m-d H:i:s' ),
			'last_scan'            => gmdate( 'Y-m-d H:i:s' ),
		];

		update_option( ContentScanner::PROGRESS_OPTION, $progress, false );
		ContentScanner::invalidateCache();
		self::scheduleBatch();

		return [
			'status'   => 'started',
			'message'  => __( 'Full-site content scan started.', 'wp-powersuite' ),
			'progress' => $progress,
		];
	}

	/**
	 * @return array{processed: int, remaining: int, complete: bool}
	 */
	public static function processBatch(): array {
		$progress = ContentScanner::getProgress();
		if ( ( $progress['status'] ?? '' ) !== 'running' ) {
			return [
				'processed' => 0,
				'remaining' => 0,
				'complete'  => true,
			];
		}

		$post_types = ContentScanner::getPostTypes();
		$posts      = get_posts(
			[
				'post_type'              => $post_types,
				'post_status'            => [ 'publish', 'draft', 'pending', 'future', 'private' ],
				'posts_per_page'         => ContentScanner::BATCH_SIZE,
				'offset'                 => (int) ( $progress['offset'] ?? 0 ),
				'orderby'                => 'ID',
				'order'                  => 'ASC',
				'no_found_rows'          => true,
				'update_post_meta_cache' => false,
				'update_post_term_cache' => false,
			]
		);

		if ( $posts === [] ) {
			$progress['status'] = 'complete';
			update_option( ContentScanner::PROGRESS_OPTION, $progress, false );
			$summary = ContentScanner::formatSummary( $progress );
			set_transient( ContentScanner::CACHE_KEY, $summary, ContentScanner::CACHE_TTL );
			wp_clear_scheduled_hook( ContentScanner::CRON_HOOK );

			return [
				'processed' => 0,
				'remaining' => 0,
				'complete'  => true,
			];
		}

		$batch_start = microtime( true );
		$id_set      = [];
		foreach ( (array) ( $progress['issue_attachment_ids'] ?? [] ) as $existing_id ) {
			$id_set[ (int) $existing_id ] = true;
		}

		foreach ( $posts as $post ) {
			if ( ! $post instanceof \WP_Post ) {
				continue;
			}

			$post_issues = ContentScanner::findIssuesInPost( $post );
			++$progress['posts_scanned'];

			if ( $post_issues === [] ) {
				continue;
			}

			$progress['images_missing_alt'] += count( $post_issues );
			++$progress['posts_with_issues'];

			foreach ( $post_issues as $issue ) {
				$id = (int) ( $issue['attachment_id'] ?? 0 );
				if ( $id > 0 ) {
					$id_set[ $id ] = true;
				}
			}

			if ( count( $progress['sample_issues'] ) < 20 ) {
				$progress['sample_issues'][] = [
					'post_id'  => $post->ID,
					'title'    => $post->post_title,
					'edit_url' => get_edit_post_link( $post->ID, 'raw' ) ?: '',
					'issues'   => $post_issues,
				];
			}
		}

		$progress['offset']               = (int) ( $progress['offset'] ?? 0 ) + count( $posts );
		$progress['issue_attachment_ids'] = array_map( 'intval', array_keys( $id_set ) );
		$progress['last_scan']            = gmdate( 'Y-m-d H:i:s' );

		$total    = (int) ( $progress['total_posts'] ?? 0 );
		$done     = (int) $progress['posts_scanned'];
		$complete = $total > 0 && $done >= $total;

		if ( $complete || count( $posts ) < ContentScanner::BATCH_SIZE ) {
			$progress['status'] = 'complete';
			$summary            = ContentScanner::formatSummary( $progress );
			set_transient( ContentScanner::CACHE_KEY, $summary, ContentScanner::CACHE_TTL );
			wp_clear_scheduled_hook( ContentScanner::CRON_HOOK );
		} else {
			self::scheduleBatch();
		}

		update_option( ContentScanner::PROGRESS_OPTION, $progress, false );

		Performance::record(
			'content_scan_batch',
			( microtime( true ) - $batch_start ) * 1000,
			[ 'processed' => count( $posts ) ]
		);

		return [
			'processed' => count( $posts ),
			'remaining' => max( 0, $total - $done ),
			'complete'  => $complete,
		];
	}

	public static function cancel(): void {
		delete_option( ContentScanner::PROGRESS_OPTION );
		wp_clear_scheduled_hook( ContentScanner::CRON_HOOK );
	}

	public static function scheduleBatch(): void {
		if ( ! wp_next_scheduled( ContentScanner::CRON_HOOK ) ) {
			wp_schedule_single_event( time() + 15, ContentScanner::CRON_HOOK );
		}
	}
}
