<?php

namespace Simple_History\Services;

use Simple_History\Existing_Data_Importer;
use Simple_History\Helpers;

/**
 * Handles automatic backfill of historical data on first install.
 *
 * This service runs a one-time backfill of existing WordPress data
 * when the plugin is first installed. It creates log entries for
 * posts and pages that existed before Simple History was installed,
 * helping users see their site's history from day one.
 *
 * The backfill runs on the first admin page load after install
 * via the admin_init hook, so it works reliably in all environments
 * including those where WP-Cron is disabled or unreliable.
 */
class Auto_Backfill_Service extends Service {
	/**
	 * Option name for flagging that backfill should run.
	 */
	const PENDING_OPTION = 'simple_history_auto_backfill_pending';

	/**
	 * Option name for storing backfill status.
	 */
	const STATUS_OPTION = 'simple_history_auto_backfill_status';

	/**
	 * Default limit per post type for auto-backfill.
	 */
	const DEFAULT_LIMIT = 100;

	/**
	 * Fallback post types if get_post_types() is not available.
	 * In practice, get_auto_backfill_post_types() dynamically fetches
	 * all public post types plus attachments.
	 */
	const DEFAULT_POST_TYPES = [ 'post', 'page' ];

	/**
	 * @inheritdoc
	 */
	public function loaded() {
		add_action( 'admin_init', [ $this, 'maybe_run_auto_backfill' ] );
	}

	/**
	 * Run auto backfill if it's pending.
	 *
	 * Called on admin_init. Checks if the pending flag is set,
	 * clears it immediately to prevent re-runs, then runs the backfill.
	 */
	public function maybe_run_auto_backfill() {
		if ( ! get_option( self::PENDING_OPTION ) ) {
			return;
		}

		// Clear the pending flag first to prevent re-runs.
		// Set to 0 instead of deleting: this flag is read on every admin_init,
		// and a missing option row costs one extra query per request on sites
		// without a persistent object cache. Keeping the row autoloaded makes
		// the read free.
		update_option( self::PENDING_OPTION, 0, true );

		$this->run_auto_backfill();
	}

	/**
	 * Flag the auto backfill as pending.
	 *
	 * Called from Setup_Database when plugin is first installed.
	 * The backfill will run on the next admin_init.
	 */
	public static function set_backfill_pending() {
		// Autoload enabled because this flag is checked on every admin_init.
		update_option( self::PENDING_OPTION, true, true );
	}

	/**
	 * Run the automatic backfill process.
	 *
	 * Checks if backfill has already been completed, runs
	 * the backfill if not, and stores the results in an option
	 * for display in the admin.
	 */
	public function run_auto_backfill() {
		// Check if already completed.
		$status = get_option( self::STATUS_OPTION );
		if ( $status && isset( $status['completed'] ) && $status['completed'] ) {
			return;
		}

		// Get configurable options via filters.
		$limit      = $this->get_auto_backfill_limit();
		$post_types = $this->get_auto_backfill_post_types();
		$days_back  = Helpers::get_clear_history_interval();

		// Create importer and run backfill.
		$importer = new Existing_Data_Importer( $this->simple_history );
		$results  = $importer->import_all(
			[
				'post_types'   => $post_types,
				'import_users' => true,
				'limit'        => $limit,
				'days_back'    => $days_back,
			]
		);

		// Store status with results.
		$status = [
			'completed'           => true,
			'completed_at'        => current_time( 'mysql', true ),
			'days_back'           => $days_back,
			'posts_imported'      => $results['posts_imported'] ?? 0,
			'users_imported'      => $results['users_imported'] ?? 0,
			'post_events_created' => $results['post_events_created'] ?? 0,
			'user_events_created' => $results['user_events_created'] ?? 0,
			'posts_skipped'       => ( $results['posts_skipped_imported'] ?? 0 ) + ( $results['posts_skipped_logged'] ?? 0 ),
			'users_skipped'       => ( $results['users_skipped_imported'] ?? 0 ) + ( $results['users_skipped_logged'] ?? 0 ),
			'errors'              => $results['errors'] ?? [],
			'type_stats'          => $results['type_stats'] ?? [],
		];

		update_option( self::STATUS_OPTION, $status, false );

		// Fire action for SimpleHistory_Logger to log completion.
		$status['type'] = 'auto';
		do_action( 'simple_history/backfill/completed', $status );
	}

	/**
	 * Get the limit for auto-backfill per post type.
	 *
	 * @return int Number of items to import per type.
	 */
	private function get_auto_backfill_limit() {
		/**
		 * Filter the limit for auto-backfill per post type.
		 *
		 * @param int $limit Default limit (100).
		 */
		return (int) apply_filters( 'simple_history/auto_backfill/limit', self::DEFAULT_LIMIT );
	}

	/**
	 * Get the post types to auto-backfill.
	 *
	 * By default, includes all public post types plus attachments.
	 * This gives new users a rich first impression with posts, pages,
	 * custom post types, and media all visible in the log.
	 *
	 * @return array Array of post type names.
	 */
	private function get_auto_backfill_post_types() {
		// Get all public post types.
		$post_types = get_post_types( [ 'public' => true ], 'names' );

		// Add attachment (not public by default but valuable for visual logs).
		$post_types['attachment'] = 'attachment';

		// Convert to simple array of names.
		$post_types = array_values( $post_types );

		/**
		 * Filter the post types to auto-backfill.
		 *
		 * @param array $post_types Post types to backfill (default: all public + attachment).
		 */
		return (array) apply_filters( 'simple_history/auto_backfill/post_types', $post_types );
	}

	/**
	 * Get the auto-backfill status.
	 *
	 * @return array|false Status array or false if not run yet.
	 */
	public static function get_status() {
		return get_option( self::STATUS_OPTION );
	}

	/**
	 * Check if auto-backfill has been completed.
	 *
	 * @return bool True if completed, false otherwise.
	 */
	public static function is_completed() {
		$status = self::get_status();
		return $status && isset( $status['completed'] ) && $status['completed'];
	}

	/**
	 * Reset the auto-backfill status (useful for testing).
	 */
	public static function reset_status() {
		delete_option( self::STATUS_OPTION );
	}
}
