<?php
/**
 * Bounded event-cache jobs.
 *
 * @package VoidPulse
 */

namespace VoidPulse\Infrastructure;

use VoidPulse\Notifications\RecentSaleCollector;

defined( 'ABSPATH' ) || exit;

final class Jobs {
	/**
	 * Register hooks and schedule once.
	 *
	 * @return void
	 */
	public function register() {
		add_action( 'voidpulse_refresh_events', array( $this, 'refresh' ) );
		add_action( 'voidpulse_cleanup_events', array( $this, 'cleanup' ) );
		add_filter( 'cron_schedules', array( $this, 'schedules' ) );
		add_action( 'init', array( $this, 'ensure_scheduled' ), 30 );
	}

	/**
	 * Add fifteen-minute schedule.
	 *
	 * @param array<string,mixed> $schedules Schedules.
	 * @return array<string,mixed>
	 */
	public function schedules( $schedules ) {
		$schedules['voidpulse_fifteen_minutes'] = array(
			'interval' => 15 * MINUTE_IN_SECONDS,
			'display'  => __( 'Every 15 minutes', 'voidpulse-social-proof-for-woocommerce' ),
		);
		return $schedules;
	}

	/**
	 * Schedule idempotently, preferring Action Scheduler.
	 *
	 * @return void
	 */
	public function ensure_scheduled() {
		if ( function_exists( 'as_has_scheduled_action' ) && function_exists( 'as_schedule_recurring_action' ) ) {
			if ( ! as_has_scheduled_action( 'voidpulse_refresh_events', array(), 'voidpulse' ) ) {
				as_schedule_recurring_action( time() + MINUTE_IN_SECONDS, 15 * MINUTE_IN_SECONDS, 'voidpulse_refresh_events', array(), 'voidpulse' );
			}
			if ( ! as_has_scheduled_action( 'voidpulse_cleanup_events', array(), 'voidpulse' ) ) {
				as_schedule_recurring_action( time() + HOUR_IN_SECONDS, DAY_IN_SECONDS, 'voidpulse_cleanup_events', array(), 'voidpulse' );
			}
			return;
		}
		if ( ! wp_next_scheduled( 'voidpulse_refresh_events' ) ) {
			wp_schedule_event( time() + MINUTE_IN_SECONDS, 'voidpulse_fifteen_minutes', 'voidpulse_refresh_events' );
		}
		if ( ! wp_next_scheduled( 'voidpulse_cleanup_events' ) ) {
			wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'voidpulse_cleanup_events' );
		}
	}

	/**
	 * Return the next refresh from Action Scheduler or WP-Cron.
	 *
	 * @return int
	 */
	public function next_refresh() {
		if ( function_exists( 'as_next_scheduled_action' ) ) {
			$next = as_next_scheduled_action( 'voidpulse_refresh_events', array(), 'voidpulse' );
			if ( is_numeric( $next ) ) {
				return absint( $next );
			}
		}
		return (int) wp_next_scheduled( 'voidpulse_refresh_events' );
	}

	/**
	 * Repair missing schedules and return the resolved refresh time.
	 *
	 * @return int
	 */
	public function repair_schedule() {
		$this->ensure_scheduled();
		return $this->next_refresh();
	}

	/**
	 * Refresh active notification events with an expiring lock.
	 *
	 * @return void
	 */
	public function refresh() {
		$lock = absint( get_option( 'voidpulse_refresh_lock', 0 ) );
		if ( $lock && $lock < time() - 10 * MINUTE_IN_SECONDS ) {
			delete_option( 'voidpulse_refresh_lock' );
			$lock = 0;
		}
		if ( $lock || ! add_option( 'voidpulse_refresh_lock', time(), '', false ) ) {
			return;
		}
		try {
			$campaign = ( new NotificationSettings() )->get();
			if ( $campaign && 'active' === $campaign['status'] ) {
				( new RecentSaleCollector() )->collect( $campaign );
				update_option( 'voidpulse_last_cache_refresh', time(), false );
			}
		} finally {
			delete_option( 'voidpulse_refresh_lock' );
		}
	}

	/**
	 * Cleanup bounded records.
	 *
	 * @return void
	 */
	public function cleanup() {
		$campaign = ( new NotificationSettings() )->get();
		$maximum  = $campaign ? $campaign['performance']['event_cache_size'] : 100;
		( new EventRepository() )->cleanup( $maximum );
	}
}
