<?php

/**
 * Cron functions.
 *
 * @package northmill-online-shared
 */
declare (strict_types=1);
namespace Northmill_Online_Shared_Sync\Northmill_Online_Shared\Modules;

use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Abstracts\Hub_API\Hub_Accounts\Hub_Account_Setup;
use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Helpers\Hook_Helpers;
use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Modules\Admin\Pages\Page\Admin_Sync_Settings;
use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Modules\Admin\Settings\Settings_Fields_Module;
use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Modules\Cron\Models\Cron_Event;
defined('ABSPATH') || exit;
/**
 * Debug class.
 */
class Cron_Module extends Abstract_Module
{
    public const CORE_SCHEDULE_HOURLY = 'hourly';
    public const CORE_SCHEDULE_TWICE_DAILY = 'twicedaily';
    public const CORE_SCHEDULE_DAILY = 'daily';
    public const CORE_SCHEDULE_WEEKLY = 'weekly';
    public const SCHEDULE_ONE_MINUTE = 'nm_every_minute';
    public const SCHEDULE_FIVE_MINUTES = 'nm_every_five_minutes';
    public const SCHEDULE_FIFTEEN_MINUTES = 'nm_every_fifteen_minutes';
    public const CRON_EVENT_SYNC = 'sync';
    public const CRON_EVENT_SYNC_SETTINGS = 'sync_settings';
    public const CRON_EVENT_SYNC_CHECKER = 'sync_checker';
    /**
     * All constructed cron events.
     *
     * @var Cron_Event[]
     */
    private array $cron_events = array();
    /**
     * Module setup.
     *
     * @return void
     */
    public function setup(): void
    {
        $this->shared->globals->add_unique_filter('cron_schedules', array($this, 'cron_schedules'), 5, 4);
        if (Hub_Account_Setup::is_setting_up_hub_accounts()) {
            $recurrence = $this->shared->admin->settings->get_setting(Settings_Fields_Module::SYNC_INTERVAL, self::SCHEDULE_FIVE_MINUTES);
            $is_enabled = $this->shared->admin->settings->is_setting_enabled(Settings_Fields_Module::AUTO_SYNC);
            $this->add_cron_event(self::CRON_EVENT_SYNC, $recurrence, $is_enabled);
        }
        if (Admin_Sync_Settings::get_syncer_class()) {
            /**
             * Sync settings admin page.
             *
             * @var Admin_Sync_Settings $admin_sync_settings_page
             */
            $admin_sync_settings_page = $this->shared->admin->pages->get_page($this->shared->package_info->get_service_name(), 'sync-settings');
            $this->add_cron_event(self::CRON_EVENT_SYNC_SETTINGS, self::SCHEDULE_FIVE_MINUTES, $admin_sync_settings_page?->syncer->is_sync_enabled() ?? \false, array(array($admin_sync_settings_page->syncer, 'sync')));
        }
        Hook_Helpers::do_scoped_action('northmill_online_shared_add_cron_events');
        if (!empty($this->cron_events)) {
            $this->add_cron_event(self::CRON_EVENT_SYNC_CHECKER, self::SCHEDULE_FIVE_MINUTES, \true, array(array($this, 'check_event_statuses')));
        }
    }
    /**
     * Register plugin cron schedules.
     *
     * @param array $schedules Array of cron schedules.
     *
     * @return array
     */
    public static function cron_schedules(array $schedules): array
    {
        $schedules[self::SCHEDULE_ONE_MINUTE] = array('interval' => \MINUTE_IN_SECONDS, 'display' => __('Every minute (Northmill)', 'northmill-online-shared'));
        $schedules[self::SCHEDULE_FIVE_MINUTES] = array('interval' => \MINUTE_IN_SECONDS * 5, 'display' => __('Every 5 minutes (Northmill)', 'northmill-online-shared'));
        $schedules[self::SCHEDULE_FIFTEEN_MINUTES] = array('interval' => \MINUTE_IN_SECONDS * 15, 'display' => __('Every 15 minutes (Northmill)', 'northmill-online-shared'));
        return $schedules;
    }
    /**
     * Add multiple cron events.
     *
     * @param array $event_configs An array of event configurations.
     *
     * @return void
     */
    public function add_cron_events(array $event_configs): void
    {
        foreach ($event_configs as $key => $event_config) {
            $this->add_cron_event($key, $event_config['recurrence'], $event_config['is_enabled'], $event_config['functions'] ?? array(), $event_config['event'] ?? null);
        }
    }
    /**
     * Add cron event.
     *
     * @param string      $key        The unique key of the event.
     * @param string      $recurrence The recurrence of the event.
     * @param bool        $is_enabled Whether the event is enabled or not.
     * @param array       $functions  An array of functions to be added to the event.
     * @param string|null $event      Optional name of the event. Defaults to service name underscored and key.
     *
     * @return void
     */
    public function add_cron_event(string $key, string $recurrence, bool $is_enabled, array $functions = array(), ?string $event = null): void
    {
        $this->cron_events[$key] = new Cron_Event($event ?? $this->shared->package_info->get_service_name_underscored() . '_' . $key, $recurrence, $is_enabled, $functions);
    }
    /**
     * Retrieve all cron events.
     *
     * @return Cron_Event[] An array of cron events.
     */
    public function get_all_cron_events(): array
    {
        return $this->cron_events;
    }
    /**
     * Get cron event by name.
     *
     * @param string $key Cron event name.
     *
     * @return Cron_Event|null
     */
    public function get_cron_event(string $key): ?Cron_Event
    {
        return $this->cron_events[$key] ?? null;
    }
    /**
     * Check if all cron events are running, and try to fix if something is wrong.
     */
    public function check_event_statuses(): void
    {
        foreach ($this->cron_events as $event) {
            $event->check_status();
        }
    }
    /**
     * Deactivate all cron events.
     */
    public function deactivate(): void
    {
        foreach ($this->cron_events as $event) {
            $event->clear();
        }
    }
}
