<?php
/**
 * GSC historical backfill — 12-month window, 13-month retention, top-N posts + tagged.
 *
 * @package Newsroom_AI_Assistant
 */

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

if ( ! defined( 'NEWSAI_GSC_RETENTION_DAYS' ) ) {
	define( 'NEWSAI_GSC_RETENTION_DAYS', 395 );
}

if ( ! defined( 'NEWSAI_GSC_BACKFILL_DAYS' ) ) {
	define( 'NEWSAI_GSC_BACKFILL_DAYS', 365 );
}

if ( ! function_exists( 'newsai_gsc_retention_days' ) ) {
	function newsai_gsc_retention_days() {
		$days = (int) apply_filters( 'newsai_gsc_retention_days', NEWSAI_GSC_RETENTION_DAYS );
		return max( 180, min( 450, $days ) );
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_days' ) ) {
	function newsai_gsc_backfill_days() {
		$days = (int) apply_filters( 'newsai_gsc_backfill_days', NEWSAI_GSC_BACKFILL_DAYS );
		return max( 90, min( 400, $days ) );
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_top_posts_limit' ) ) {
	function newsai_gsc_backfill_top_posts_limit() {
		$lim = (int) apply_filters( 'newsai_gsc_backfill_top_posts', 150 );
		return max( 20, min( 500, $lim ) );
	}
}

if ( ! function_exists( 'newsai_gsc_prune_cutoff_date' ) ) {
	function newsai_gsc_prune_cutoff_date() {
		return gmdate( 'Y-m-d', strtotime( '-' . newsai_gsc_retention_days() . ' days' ) );
	}
}

if ( ! function_exists( 'newsai_gsc_prune_post_rows' ) ) {
	function newsai_gsc_prune_post_rows() {
		global $wpdb;
		if ( ! function_exists( 'newsai_gsc_table_exists' ) || ! newsai_gsc_table_exists() ) {
			return 0;
		}
		$table  = newsai_gsc_table_name();
		$cutoff = newsai_gsc_prune_cutoff_date();
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		return (int) $wpdb->query( $wpdb->prepare( "DELETE FROM {$table} WHERE data_date < %s", $cutoff ) );
	}
}

if ( ! function_exists( 'newsai_gsc_prune_site_daily_rows' ) ) {
	function newsai_gsc_prune_site_daily_rows() {
		global $wpdb;
		if ( ! function_exists( 'newsai_gsc_site_daily_table_exists' ) || ! newsai_gsc_site_daily_table_exists() ) {
			return 0;
		}
		$table  = newsai_gsc_site_daily_table_name();
		$cutoff = newsai_gsc_prune_cutoff_date();
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		return (int) $wpdb->query( $wpdb->prepare( "DELETE FROM {$table} WHERE data_date < %s", $cutoff ) );
	}
}

if ( ! function_exists( 'newsai_gsc_prune_device_rows' ) ) {
	function newsai_gsc_prune_device_rows() {
		global $wpdb;
		if ( ! function_exists( 'newsai_gsc_device_table_exists' ) || ! newsai_gsc_device_table_exists() ) {
			return 0;
		}
		$table  = newsai_gsc_device_table_name();
		$cutoff = newsai_gsc_prune_cutoff_date();
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		return (int) $wpdb->query( $wpdb->prepare( "DELETE FROM {$table} WHERE data_date < %s", $cutoff ) );
	}
}

if ( ! function_exists( 'newsai_gsc_prune_all_gsc_data' ) ) {
	/**
	 * Drop rows older than retention window across all GSC tables.
	 *
	 * @return array{posts:int,queries:int,site:int,device:int}
	 */
	function newsai_gsc_prune_all_gsc_data() {
		$out = [
			'posts'   => newsai_gsc_prune_post_rows(),
			'queries' => function_exists( 'newsai_gsc_prune_query_rows' ) ? newsai_gsc_prune_query_rows() : 0,
			'site'    => newsai_gsc_prune_site_daily_rows(),
			'device'  => newsai_gsc_prune_device_rows(),
		];
		if ( function_exists( 'newsai_gsc_bump_cache_gen' ) ) {
			newsai_gsc_bump_cache_gen();
		}
		delete_transient( 'newsai_gsc_row_count' );
		if ( function_exists( 'newsai_admin_analytics_cache_stamp' ) ) {
			$stamp = newsai_admin_analytics_cache_stamp();
			global $wpdb;
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->query(
				$wpdb->prepare(
					"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
					$wpdb->esc_like( '_transient_newsai_chief_insights_' ) . '%',
					$wpdb->esc_like( '_transient_newsai_pro_authors_grid_' ) . '%'
				)
			);
		}
		return $out;
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_state_key' ) ) {
	function newsai_gsc_backfill_state_key() {
		return 'newsai_gsc_backfill_state';
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_get_state' ) ) {
	/**
	 * @return array<string, mixed>
	 */
	function newsai_gsc_backfill_get_state() {
		$state = get_option( newsai_gsc_backfill_state_key(), [] );
		return is_array( $state ) ? $state : [];
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_set_state' ) ) {
	/**
	 * @param array<string, mixed> $state State payload.
	 */
	function newsai_gsc_backfill_set_state( array $state ) {
		update_option( newsai_gsc_backfill_state_key(), $state, false );
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_is_running' ) ) {
	function newsai_gsc_backfill_is_running() {
		$state = newsai_gsc_backfill_get_state();
		return isset( $state['status'] ) && $state['status'] === 'running';
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_safe_end_ymd' ) ) {
	function newsai_gsc_backfill_safe_end_ymd() {
		return gmdate( 'Y-m-d', strtotime( '-3 days' ) );
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_build_chunks' ) ) {
	/**
	 * Monthly chunks covering the backfill window.
	 *
	 * @param string $end_ymd Y-m-d.
	 * @return list<array{start:string,end:string,label:string}>
	 */
	function newsai_gsc_backfill_build_chunks( $end_ymd ) {
		$end_ts   = strtotime( $end_ymd . ' UTC' );
		$start_ts = strtotime( '-' . newsai_gsc_backfill_days() . ' days', $end_ts );
		if ( ! $end_ts || ! $start_ts || $start_ts >= $end_ts ) {
			return [];
		}

		$chunks   = [];
		$cursor   = $start_ts;
		$guard    = 0;
		while ( $cursor <= $end_ts && $guard < 24 ) {
			++$guard;
			$chunk_start = gmdate( 'Y-m-d', $cursor );
			$next_month  = strtotime( '+1 month', strtotime( gmdate( 'Y-m-01', $cursor ) . ' UTC' ) );
			$chunk_end_ts = min( $end_ts, $next_month - DAY_IN_SECONDS );
			if ( $chunk_end_ts < $cursor ) {
				$chunk_end_ts = $end_ts;
			}
			$chunk_end = gmdate( 'Y-m-d', $chunk_end_ts );
			$chunks[]  = [
				'start' => $chunk_start,
				'end'   => $chunk_end,
				'label' => gmdate( 'M Y', $cursor ),
			];
			$cursor = $chunk_end_ts + DAY_IN_SECONDS;
		}

		return $chunks;
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_collect_tagged_urls' ) ) {
	/**
	 * Permalinks for published posts that have at least one tag.
	 *
	 * @return list<string>
	 */
	function newsai_gsc_backfill_collect_tagged_urls() {
		global $wpdb;
		$ids = $wpdb->get_col(
			"SELECT DISTINCT p.ID
			 FROM {$wpdb->posts} p
			 INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id = p.ID
			 INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id AND tt.taxonomy = 'post_tag'
			 WHERE p.post_type = 'post' AND p.post_status = 'publish'
			 LIMIT 500"
		);
		$urls = [];
		foreach ( (array) $ids as $id ) {
			$url = get_permalink( (int) $id );
			if ( ! is_string( $url ) || $url === '' ) {
				continue;
			}
			if ( function_exists( 'newsai_gsc_normalize_page_url' ) ) {
				$url = newsai_gsc_normalize_page_url( $url );
			}
			if ( $url !== '' ) {
				$urls[ $url ] = true;
			}
		}
		return array_keys( $urls );
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_collect_top_urls' ) ) {
	/**
	 * Top traffic URLs per GSC channel for the full backfill window.
	 *
	 * @return list<string>
	 */
	function newsai_gsc_backfill_collect_top_urls( $token, $property, $start, $end ) {
		$limit  = newsai_gsc_backfill_top_posts_limit();
		$merged = [];
		$types  = [ 'web', 'discover', 'googleNews' ];

		foreach ( $types as $type ) {
			if ( ! function_exists( 'newsai_gsc_fetch_analytics_rows' ) ) {
				continue;
			}
			$rows = newsai_gsc_fetch_analytics_rows( $token, $property, $start, $end, $type, [ 'page' ], 25000, 90 );
			if ( is_wp_error( $rows ) ) {
				continue;
			}
			$n = 0;
			foreach ( (array) $rows as $row ) {
				if ( $n >= $limit ) {
					break;
				}
				$url = isset( $row['keys'][0] ) ? (string) $row['keys'][0] : '';
				if ( $url === '' ) {
					continue;
				}
				if ( function_exists( 'newsai_gsc_normalize_page_url' ) ) {
					$url = newsai_gsc_normalize_page_url( $url );
				}
				if ( $url === '' ) {
					continue;
				}
				$merged[ $url ] = (int) ( $merged[ $url ] ?? 0 ) + (int) ( $row['clicks'] ?? 0 );
				++$n;
			}
		}

		arsort( $merged );
		return array_slice( array_keys( $merged ), 0, $limit + 50 );
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_merge_urls' ) ) {
	/**
	 * @param list<string> $top_urls
	 * @param list<string> $tagged_urls
	 * @return list<string>
	 */
	function newsai_gsc_backfill_merge_urls( array $top_urls, array $tagged_urls ) {
		$map = [];
		foreach ( array_merge( $top_urls, $tagged_urls ) as $url ) {
			$url = trim( (string) $url );
			if ( $url !== '' ) {
				$map[ $url ] = true;
			}
		}
		return array_keys( $map );
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_sync_posts_for_urls' ) ) {
	/**
	 * @param list<string> $urls Page URLs.
	 * @return array{processed:int,skipped:int}
	 */
	function newsai_gsc_backfill_sync_posts_for_urls( $token, $property, $start, $end, array $urls ) {
		$out = [ 'processed' => 0, 'skipped' => 0 ];
		if ( $urls === [] || ! function_exists( 'newsai_gsc_fetch_analytics_rows' ) ) {
			return $out;
		}

		$types = [ 'web', 'discover', 'googleNews' ];
		$batch_size = (int) apply_filters( 'newsai_gsc_backfill_url_batch_size', 6 );
		$batch_size = max( 3, min( 12, $batch_size ) );
		foreach ( array_chunk( $urls, $batch_size ) as $url_batch ) {
			foreach ( $types as $type ) {
				$rows = newsai_gsc_fetch_analytics_rows( $token, $property, $start, $end, $type, [ 'page', 'date' ], 25000, 90, $url_batch );
				if ( is_wp_error( $rows ) ) {
					continue;
				}
				foreach ( (array) $rows as $row ) {
					$url  = isset( $row['keys'][0] ) ? (string) $row['keys'][0] : '';
					$date = isset( $row['keys'][1] ) ? (string) $row['keys'][1] : '';
					if ( $url === '' || $date === '' ) {
						++$out['skipped'];
						continue;
					}
					if ( ! function_exists( 'newsai_gsc_resolve_post' ) ) {
						continue;
					}
					$resolved = newsai_gsc_resolve_post( $url );
					if ( ! $resolved ) {
						++$out['skipped'];
						continue;
					}
					newsai_gsc_upsert_row(
						$resolved['post_id'],
						$resolved['author_id'],
						$date,
						$type,
						(int) ( $row['clicks'] ?? 0 ),
						(int) ( $row['impressions'] ?? 0 ),
						(float) ( $row['ctr'] ?? 0 ),
						(float) ( $row['position'] ?? 0 )
					);
					++$out['processed'];
				}
			}
		}

		return $out;
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_sync_queries_range' ) ) {
	/**
	 * @return int Rows stored.
	 */
	function newsai_gsc_backfill_sync_queries_range( $token, $property, $start, $end ) {
		if ( ! function_exists( 'newsai_gsc_query_sync_enabled' ) || ! newsai_gsc_query_sync_enabled() ) {
			return 0;
		}
		if ( ! function_exists( 'newsai_gsc_fetch_analytics_rows' ) || ! function_exists( 'newsai_gsc_upsert_query_row' ) ) {
			return 0;
		}

		$rows = newsai_gsc_fetch_analytics_rows( $token, $property, $start, $end, 'web', [ 'query', 'date' ], 25000, 90 );
		if ( is_wp_error( $rows ) ) {
			return 0;
		}

		$max_rows = (int) apply_filters( 'newsai_gsc_query_sync_max_rows', 12000 );
		$stored   = 0;
		foreach ( (array) $rows as $row ) {
			if ( $stored >= $max_rows ) {
				break;
			}
			$query = isset( $row['keys'][0] ) ? (string) $row['keys'][0] : '';
			$date  = isset( $row['keys'][1] ) ? (string) $row['keys'][1] : '';
			if ( $query === '' || $date === '' ) {
				continue;
			}
			$clicks = (int) ( $row['clicks'] ?? 0 );
			$impr   = (int) ( $row['impressions'] ?? 0 );
			if ( $clicks < 1 && $impr < 5 ) {
				continue;
			}
			newsai_gsc_upsert_query_row( $query, $date, $clicks, $impr, (float) ( $row['position'] ?? 0 ) );
			++$stored;
		}
		return $stored;
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_start' ) ) {
	/**
	 * Initialize backfill state and URL list.
	 *
	 * @return array{ok:bool,message:string}
	 */
	function newsai_gsc_backfill_start() {
		if ( ! function_exists( 'newsai_gsc_is_pro_active' ) || ! newsai_gsc_is_pro_active() ) {
			return [ 'ok' => false, 'message' => __( 'Pro license required.', 'newsroom-ai-assistant' ) ];
		}
		if ( newsai_gsc_backfill_is_running() ) {
			return [ 'ok' => false, 'message' => __( 'Backfill is already running.', 'newsroom-ai-assistant' ) ];
		}
		if ( get_transient( 'newsai_gsc_sync_lock' ) ) {
			return [ 'ok' => false, 'message' => __( 'Daily GSC sync is running. Try again in a few minutes.', 'newsroom-ai-assistant' ) ];
		}

		$token_error = '';
		$token       = function_exists( 'newsai_gsc_get_access_token' ) ? newsai_gsc_get_access_token( $token_error ) : '';
		$property    = function_exists( 'newsai_gsc_get_property' ) ? newsai_gsc_get_property() : '';
		if ( $token === '' || $property === '' ) {
			return [ 'ok' => false, 'message' => $token_error !== '' ? $token_error : __( 'GSC not configured.', 'newsroom-ai-assistant' ) ];
		}

		$end_ymd = newsai_gsc_backfill_safe_end_ymd();
		$start   = gmdate( 'Y-m-d', strtotime( '-' . newsai_gsc_backfill_days() . ' days', strtotime( $end_ymd . ' UTC' ) ) );
		$chunks  = newsai_gsc_backfill_build_chunks( $end_ymd );
		if ( $chunks === [] ) {
			return [ 'ok' => false, 'message' => __( 'Could not build backfill windows.', 'newsroom-ai-assistant' ) ];
		}

		$top_urls    = newsai_gsc_backfill_collect_top_urls( $token, $property, $start, $end_ymd );
		$tagged_urls = newsai_gsc_backfill_collect_tagged_urls();
		$urls        = newsai_gsc_backfill_merge_urls( $top_urls, $tagged_urls );

		newsai_gsc_backfill_set_state(
			[
				'status'       => 'running',
				'chunk_index'  => 0,
				'chunks'       => $chunks,
				'urls'         => $urls,
				'url_count'    => count( $urls ),
				'rows_total'   => 0,
				'started_at'   => time(),
				'range_start'  => $start,
				'range_end'    => $end_ymd,
				'last_message' => '',
				'substep'      => 'queries',
				'url_batch_index' => 0,
			]
		);

		return [
			'ok'      => true,
			'message' => sprintf(
				/* translators: 1: months count, 2: URL count */
				__( 'Backfill started — %1$d monthly chunks, %2$d article URLs.', 'newsroom-ai-assistant' ),
				count( $chunks ),
				count( $urls )
			),
		];
	}
}

if ( ! function_exists( 'newsai_gsc_backfill_run_step' ) ) {
	/**
	 * Process one monthly chunk (queries + site + filtered posts).
	 *
	 * @return array{ok:bool,done:bool,message:string,progress:array<string,mixed>}
	 */
	function newsai_gsc_backfill_run_step() {
		if ( function_exists( 'set_time_limit' ) ) {
			@set_time_limit( 180 );
		}

		$state = newsai_gsc_backfill_get_state();
		if ( ( $state['status'] ?? '' ) !== 'running' ) {
			return [
				'ok'       => false,
				'done'     => true,
				'message'  => __( 'No backfill in progress.', 'newsroom-ai-assistant' ),
				'progress' => $state,
			];
		}

		set_transient( 'newsai_gsc_backfill_lock', '1', 60 * MINUTE_IN_SECONDS );

		$chunks = isset( $state['chunks'] ) && is_array( $state['chunks'] ) ? $state['chunks'] : [];
		$index  = (int) ( $state['chunk_index'] ?? 0 );
		if ( ! isset( $chunks[ $index ] ) ) {
			$state['status']       = 'done';
			$state['finished_at']  = time();
			$state['last_message'] = __( 'Backfill complete.', 'newsroom-ai-assistant' );
			newsai_gsc_backfill_set_state( $state );
			update_option( 'newsai_gsc_backfill_completed_at', time(), false );
			newsai_gsc_prune_all_gsc_data();
			if ( function_exists( 'newsai_seasonal_radar_compute' ) && function_exists( 'newsai_seasonal_radar_enabled' ) && newsai_seasonal_radar_enabled() ) {
				newsai_seasonal_radar_compute();
			}
			if ( function_exists( 'newsai_gsc_bump_cache_gen' ) ) {
				newsai_gsc_bump_cache_gen();
			}
			return [
				'ok'       => true,
				'done'     => true,
				'message'  => (string) $state['last_message'],
				'progress' => $state,
			];
		}

		$token_error = '';
		$token       = function_exists( 'newsai_gsc_get_access_token' ) ? newsai_gsc_get_access_token( $token_error ) : '';
		$property    = function_exists( 'newsai_gsc_get_property' ) ? newsai_gsc_get_property() : '';
		if ( $token === '' || $property === '' ) {
			$state['status']       = 'error';
			$state['last_message'] = $token_error !== '' ? $token_error : __( 'GSC token failed.', 'newsroom-ai-assistant' );
			newsai_gsc_backfill_set_state( $state );
			return [ 'ok' => false, 'done' => true, 'message' => (string) $state['last_message'], 'progress' => $state ];
		}

		$chunk   = $chunks[ $index ];
		$start   = (string) ( $chunk['start'] ?? '' );
		$end     = (string) ( $chunk['end'] ?? '' );
		$label   = (string) ( $chunk['label'] ?? $start );
		$urls    = isset( $state['urls'] ) && is_array( $state['urls'] ) ? $state['urls'] : [];
		$substep = (string) ( $state['substep'] ?? 'queries' );
		$added   = 0;

		if ( $substep === 'queries' ) {
			$added += newsai_gsc_backfill_sync_queries_range( $token, $property, $start, $end );
			$state['substep'] = 'site';
		} elseif ( $substep === 'site' ) {
			if ( function_exists( 'newsai_gsc_sync_site_metrics' ) ) {
				$site = newsai_gsc_sync_site_metrics( $token, $property, $start, $end );
				$added += (int) ( $site['site_rows'] ?? 0 ) + (int) ( $site['device_rows'] ?? 0 );
			}
			$state['substep']          = 'posts';
			$state['url_batch_index']  = 0;
		} else {
			$batch_size   = (int) apply_filters( 'newsai_gsc_backfill_url_batch_size', 6 );
			$batch_size   = max( 3, min( 12, $batch_size ) );
			$url_batches  = $urls !== [] ? array_chunk( $urls, $batch_size ) : [];
			$batch_index  = (int) ( $state['url_batch_index'] ?? 0 );
			if ( isset( $url_batches[ $batch_index ] ) ) {
				$post = newsai_gsc_backfill_sync_posts_for_urls( $token, $property, $start, $end, $url_batches[ $batch_index ] );
				$added += (int) ( $post['processed'] ?? 0 );
				$state['url_batch_index'] = $batch_index + 1;
			}
			if ( empty( $url_batches ) || $state['url_batch_index'] >= count( $url_batches ) ) {
				$state['chunk_index']     = $index + 1;
				$state['substep']         = 'queries';
				$state['url_batch_index'] = 0;
			}
		}

		$state['rows_total']   = (int) ( $state['rows_total'] ?? 0 ) + $added;
		$state['last_message'] = sprintf(
			/* translators: 1: chunk label, 2: sub-step name, 3: rows stored this step */
			__( 'Imported %1$s · %2$s (%3$d rows).', 'newsroom-ai-assistant' ),
			$label,
			$substep,
			$added
		);
		newsai_gsc_backfill_set_state( $state );

		$done = $state['chunk_index'] >= count( $chunks );
		if ( $done ) {
			$state['status']       = 'done';
			$state['finished_at']  = time();
			$state['last_message'] = __( 'Backfill complete.', 'newsroom-ai-assistant' );
			newsai_gsc_backfill_set_state( $state );
			update_option( 'newsai_gsc_backfill_completed_at', time(), false );
			newsai_gsc_prune_all_gsc_data();
			if ( function_exists( 'newsai_seasonal_radar_compute' ) && function_exists( 'newsai_seasonal_radar_enabled' ) && newsai_seasonal_radar_enabled() ) {
				newsai_seasonal_radar_compute();
			}
			if ( function_exists( 'newsai_gsc_bump_cache_gen' ) ) {
				newsai_gsc_bump_cache_gen();
			}
		}

		return [
			'ok'       => true,
			'done'     => $done,
			'message'  => (string) $state['last_message'],
			'progress' => newsai_gsc_backfill_get_state(),
		];
	}
}

if ( ! function_exists( 'newsai_gsc_ajax_backfill_start' ) ) {
	function newsai_gsc_ajax_backfill_start() {
		check_ajax_referer( 'newsai_ajax_nonce', 'nonce' );
		if ( ! current_user_can( 'edit_others_posts' ) ) {
			wp_send_json_error( [ 'message' => 'forbidden' ], 403 );
		}
		set_transient( 'newsai_gsc_backfill_lock', '1', 60 * MINUTE_IN_SECONDS );
		$result = newsai_gsc_backfill_start();
		if ( empty( $result['ok'] ) ) {
			delete_transient( 'newsai_gsc_backfill_lock' );
			wp_send_json_error( [ 'message' => (string) ( $result['message'] ?? '' ) ], 400 );
		}
		wp_send_json_success( [ 'message' => (string) ( $result['message'] ?? '' ), 'progress' => newsai_gsc_backfill_get_state() ] );
	}
}
add_action( 'wp_ajax_newsai_gsc_backfill_start', 'newsai_gsc_ajax_backfill_start' );

if ( ! function_exists( 'newsai_gsc_ajax_backfill_step' ) ) {
	function newsai_gsc_ajax_backfill_step() {
		check_ajax_referer( 'newsai_ajax_nonce', 'nonce' );
		if ( ! current_user_can( 'edit_others_posts' ) ) {
			wp_send_json_error( [ 'message' => 'forbidden' ], 403 );
		}
		$result = newsai_gsc_backfill_run_step();
		if ( ! empty( $result['done'] ) ) {
			delete_transient( 'newsai_gsc_backfill_lock' );
		}
		if ( empty( $result['ok'] ) && ! empty( $result['done'] ) ) {
			wp_send_json_error(
				[
					'message'  => (string) ( $result['message'] ?? '' ),
					'progress' => (array) ( $result['progress'] ?? [] ),
				],
				400
			);
		}
		wp_send_json_success(
			[
				'message'  => (string) ( $result['message'] ?? '' ),
				'done'     => ! empty( $result['done'] ),
				'progress' => (array) ( $result['progress'] ?? [] ),
			]
		);
	}
}
add_action( 'wp_ajax_newsai_gsc_backfill_step', 'newsai_gsc_ajax_backfill_step' );

if ( ! function_exists( 'newsai_gsc_ajax_backfill_status' ) ) {
	function newsai_gsc_ajax_backfill_status() {
		check_ajax_referer( 'newsai_ajax_nonce', 'nonce' );
		if ( ! current_user_can( 'edit_others_posts' ) ) {
			wp_send_json_error( [ 'message' => 'forbidden' ], 403 );
		}
		wp_send_json_success( [ 'progress' => newsai_gsc_backfill_get_state() ] );
	}
}
add_action( 'wp_ajax_newsai_gsc_backfill_status', 'newsai_gsc_ajax_backfill_status' );
