<?php
/**
 * Scheduled database cleanup.
 *
 * @package DatabaseCleanup
 */

namespace DatabaseCleanup\Includes;

use DatabaseCleanup\Module;

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

class Scheduler {

	public const CRON_HOOK           = 'wpps_dc_scheduled_cleanup';
	public const CRON_CONTINUE_HOOK  = 'wpps_dc_scheduled_cleanup_continue';
	public const CRON_MAX_STEPS      = 25;
	public const SCHEDULED_JOB_OPTION = 'wpps_dc_active_scheduled_job';

	public static function register_hooks(): void {
		add_filter( 'cron_schedules', [ self::class, 'add_schedules' ] );
		add_action( self::CRON_HOOK, [ self::class, 'run_scheduled_cleanup' ] );
		add_action( self::CRON_CONTINUE_HOOK, [ self::class, 'run_scheduled_cleanup' ] );
	}

	/**
	 * @param array<string, array<string, int|string>> $schedules
	 * @return array<string, array<string, int|string>>
	 */
	public static function add_schedules( array $schedules ): array {
		$schedules['wpps_dc_monthly'] = [
			'interval' => MONTH_IN_SECONDS,
			'display'  => __( 'Once Monthly (Database Cleanup)', 'wppowersuite-lite' ),
		];

		return $schedules;
	}

	/**
	 * @param array<string, mixed> $settings
	 */
	public static function sync_schedule( array $settings ): void {
		wp_clear_scheduled_hook( self::CRON_HOOK );
		wp_clear_scheduled_hook( self::CRON_CONTINUE_HOOK );

		if ( empty( $settings['schedule_enabled'] ) || ! Module::is_schedule_allowed() ) {
			return;
		}

		$frequency  = (string) ( $settings['schedule_frequency'] ?? 'weekly' );
		$recurrence = match ( $frequency ) {
			'hourly'     => 'hourly',
			'twicedaily' => 'twicedaily',
			'daily'      => 'daily',
			'monthly'    => 'wpps_dc_monthly',
			default      => 'weekly',
		};

		if ( ! wp_next_scheduled( self::CRON_HOOK ) ) {
			wp_schedule_event( time() + HOUR_IN_SECONDS, $recurrence, self::CRON_HOOK );
		}
	}

	public static function clear_schedule(): void {
		wp_clear_scheduled_hook( self::CRON_HOOK );
		wp_clear_scheduled_hook( self::CRON_CONTINUE_HOOK );
		delete_option( self::SCHEDULED_JOB_OPTION );
	}

	public static function run_scheduled_cleanup(): void {
		if ( ! Module::is_schedule_allowed() ) {
			return;
		}

		$settings = Module::getStoredSettings();

		if ( empty( $settings['schedule_enabled'] ) ) {
			self::clear_scheduled_job_pointer();
			return;
		}

		$cleaner = new Database_Cleaner();
		$job_id  = (string) get_option( self::SCHEDULED_JOB_OPTION, '' );

		if ( $job_id === '' || ! $cleaner->get_job( $job_id ) ) {
			$task_ids = $settings['schedule_tasks'] ?? [];
			if ( ! is_array( $task_ids ) || $task_ids === [] ) {
				$task_ids = Cleanup_Task_Registry::safe_task_ids();
			}

			$job_id = $cleaner->create_job( $task_ids, $settings, true );
			if ( $job_id === '' ) {
				return;
			}

			update_option( self::SCHEDULED_JOB_OPTION, $job_id, false );
		}

		$guard = 0;

		while ( $guard < self::CRON_MAX_STEPS ) {
			++$guard;
			$step = $cleaner->run_step( $job_id, $settings );

			if ( ! empty( $step['error'] ) ) {
				self::clear_scheduled_job_pointer();
				wp_clear_scheduled_hook( self::CRON_CONTINUE_HOOK );
				return;
			}

			if ( ! empty( $step['done'] ) ) {
				self::clear_scheduled_job_pointer();
				wp_clear_scheduled_hook( self::CRON_CONTINUE_HOOK );
				return;
			}
		}

		if ( ! wp_next_scheduled( self::CRON_CONTINUE_HOOK ) ) {
			wp_schedule_single_event( time() + MINUTE_IN_SECONDS, self::CRON_CONTINUE_HOOK );
		}
	}

	public static function clear_scheduled_job_pointer(): void {
		delete_option( self::SCHEDULED_JOB_OPTION );
	}

	/**
	 * @return int|null Next run timestamp.
	 */
	public static function next_run(): ?int {
		$next = wp_next_scheduled( self::CRON_HOOK );

		return $next ? (int) $next : null;
	}
}
