<?php
/**
 * Audit Scanner.
 *
 * Walks all published posts in small chunks, gathers on-page health +
 * cached Search Console metrics, scores each post, and upserts the result.
 * Chunked on purpose: WP Engine never sees a long-running request.
 *
 * @package Platform\Helm\Modules\Content_Auditor
 */

declare( strict_types = 1 );

namespace Platform\Helm\Modules\Content_Auditor;

use Platform\Helm\Modules\GSC\GscStore;

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

final class AuditScanner {

	public const POST_TYPE = 'post';

	public function __construct(
		private AuditStore $store,
		private GscStore $gsc
	) {}

	public function total_posts(): int {
		$counts = wp_count_posts( self::POST_TYPE );
		return isset( $counts->publish ) ? (int) $counts->publish : 0;
	}

	/**
	 * Process one chunk starting at $offset.
	 *
	 * @return array{processed:int,offset:int}
	 */
	public function scan_chunk( int $offset, int $limit = 100 ): array {
		$limit = max( 10, min( 200, $limit ) );

		$ids = get_posts( [
			'post_type'        => self::POST_TYPE,
			'post_status'      => 'publish',
			'fields'           => 'ids',
			'posts_per_page'   => $limit,
			'offset'           => max( 0, $offset ),
			'orderby'          => 'ID',
			'order'            => 'ASC',
			'no_found_rows'    => true,
			'suppress_filters' => true,
			'cache_results'    => false,
		] );

		if ( empty( $ids ) ) {
			return [ 'processed' => 0, 'offset' => $offset ];
		}

		$metrics = $this->gsc->get_for_posts( $ids );
		$now     = time();
		$rows    = [];

		foreach ( $ids as $id ) {
			$id   = (int) $id;
			$post = get_post( $id );
			if ( ! $post ) {
				continue;
			}

			$words    = str_word_count( wp_strip_all_tags( (string) $post->post_content ) );
			$has_img  = has_post_thumbnail( $id );
			$has_meta = '' !== (string) get_post_meta( $id, '_yoast_wpseo_metadesc', true )
				|| '' !== (string) get_post_meta( $id, 'rank_math_description', true );
			$modified = strtotime( (string) $post->post_modified_gmt . ' UTC' );
			$age_days = $modified ? (int) floor( ( $now - $modified ) / DAY_IN_SECONDS ) : 0;

			$g = $metrics[ $id ] ?? [];
			$m = [
				'words'       => (int) $words,
				'has_image'   => (bool) $has_img,
				'has_meta'    => (bool) $has_meta,
				'age_days'    => $age_days,
				'clicks'      => (int) ( $g['clicks'] ?? 0 ),
				'impressions' => (int) ( $g['impressions'] ?? 0 ),
				'ctr'         => (float) ( $g['ctr'] ?? 0 ),
				'position'    => (float) ( $g['position'] ?? 0 ),
			];

			$verdict = AuditScorer::evaluate( $m );

			$rows[] = [
				'post_id'        => $id,
				'title'          => get_the_title( $id ),
				'url'            => (string) get_permalink( $id ),
				'recommendation' => $verdict['recommendation'],
				'score'          => $verdict['score'],
				'word_count'     => $m['words'],
				'has_image'      => $m['has_image'] ? 1 : 0,
				'has_meta'       => $m['has_meta'] ? 1 : 0,
				'age_days'       => $m['age_days'],
				'clicks'         => $m['clicks'],
				'impressions'    => $m['impressions'],
				'ctr'            => $m['ctr'],
				'position'       => $m['position'],
				'reasons'        => $verdict['reasons'],
			];
		}

		$this->store->upsert( $rows );

		return [ 'processed' => count( $ids ), 'offset' => $offset + count( $ids ) ];
	}
}
