<?php

/**
 * Sync cron functions.
 *
 * @package northmill-online-shared
 */
declare (strict_types=1);
namespace Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstracts\Hub_API\Sync\Cron\Models;

use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstract_Shared_Base;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Cron\Models\Cron_Event;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Cron\Models\Lock_Model;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstracts\Hub_API\Sync\Abstract_Syncer;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Helpers\Time_Helpers;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Cron_Module;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Loggers\Log_Level_Enum;
defined('ABSPATH') || exit;
/**
 * Sync cron class.
 */
class Cron_Sync_Model
{
    /**
     * Lock object.
     *
     * @var Lock_Model
     */
    protected Lock_Model $lock;
    /**
     * Name of inheriting class.
     * Used for lock name.
     *
     * @var string $cron_name
     */
    protected string $cron_name;
    /**
     * Event for this cron sync.
     *
     * @var Cron_Event $cron_event
     */
    protected Cron_Event $cron_event;
    /**
     * Cron action priority.
     *
     * @var int
     */
    protected int $cron_priority = 10;
    /**
     * Subclass of NMFS\Sync\Abstract_Syncer
     *
     * @var Abstract_Syncer $syncer
     */
    public Abstract_Syncer $syncer;
    /**
     * Array of parameters to send with API request.
     *
     * @var array $api_params
     */
    protected array $api_params = array();
    /**
     * Constructor.
     *
     * @param int             $cron_priority Priority of cron.
     * @param Abstract_Syncer $syncer Syncer object.
     */
    public function __construct(int $cron_priority, Abstract_Syncer $syncer)
    {
        $this->cron_priority = $cron_priority;
        $this->syncer = $syncer;
        $this->cron_name = get_class($this->syncer) . '_cron';
        $this->cron_event = Abstract_Shared_Base::base_instance()->cron->get_cron_event(Cron_Module::CRON_EVENT_SYNC);
        $this->cron_event->add_function(array($this, 'cron_sync'), $this->cron_priority);
    }
    /**
     * Loop sync function for cron sync.
     *
     * @return void
     */
    public function cron_sync(): void
    {
        if (!$this->syncer->is_enabled()) {
            Abstract_Shared_Base::base_instance()->logger->log('cron', "Cron Skipped - {$this->cron_name}", array(), Log_Level_Enum::NOTICE);
            return;
        }
        // Logging occurs inside if cron is locked.
        if (!$this->is_unlocked()) {
            return;
        }
        Abstract_Shared_Base::base_instance()->logger->log('cron', "Cron Started - {$this->cron_name}", array(), Log_Level_Enum::NOTICE);
        $sync_start_time = Time_Helpers::get_current_api_time();
        $last_update_api_parameter = $this->syncer->get_last_synced_api_parameter();
        if (!empty($last_update_api_parameter)) {
            $this->api_params[$last_update_api_parameter] = $this->syncer->get_last_synced_wp_option();
        }
        $all_syncs_successful = $this->syncer->sync_loop($this->api_params);
        if ($all_syncs_successful) {
            $this->syncer->set_last_synced_wp_option($sync_start_time, 'cron');
            if (method_exists($this->syncer, 'clean')) {
                Abstract_Shared_Base::base_instance()->logger->log('cron', "Cron Started - Clean {$this->cron_name}", array(), Log_Level_Enum::NOTICE);
                $this->syncer->clean(\false);
                Abstract_Shared_Base::base_instance()->logger->log('cron', "Cron Ended - Clean {$this->cron_name}", array(), Log_Level_Enum::NOTICE);
            }
        } else {
            Abstract_Shared_Base::base_instance()->logger->log('cron', 'All Syncs were not successful', array('event' => $this), Log_Level_Enum::ERROR);
        }
        $this->clear_lock();
        Abstract_Shared_Base::base_instance()->logger->log('cron', "Cron Ended - {$this->cron_name}", array(), Log_Level_Enum::NOTICE);
    }
    /**
     * Check if there is a lock for the current function.
     *
     * @return bool
     */
    protected function is_unlocked(): bool
    {
        if (empty($this->cron_name)) {
            Abstract_Shared_Base::base_instance()->logger->log('cron', 'Lock name is not set', array('cron_model' => $this), Log_Level_Enum::ERROR);
            return \false;
        }
        $this->lock = new Lock_Model($this->cron_name);
        if (!$this->lock->lock()) {
            Abstract_Shared_Base::base_instance()->logger->log('cron', 'Cron lock in place, skipping.', array('cron_model' => $this), Log_Level_Enum::WARNING);
            return \false;
        }
        return \true;
    }
    /**
     * Clear the current lock if set.
     */
    protected function clear_lock(): void
    {
        if (isset($this->lock) && is_a($this->lock, Lock_Model::class)) {
            $this->lock->clear_lock();
        }
    }
}
