<?php

namespace AC_SYNC\Includes\Classes\Setting;

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

use AC_SYNC\Includes\Classes\Async\Action_Wear_Job_Queue as JobQueue;
use AC_SYNC\Includes\Classes\Async\Action_Wear_Job_Runner as JobRunner;
use AC_SYNC\Includes\Classes\Async\Action_Wear_Job_Scheduler as JobScheduler;
use AC_SYNC\Includes\Classes\Logger\Action_Wear_Log as Log;

class Action_Wear_Setting_Queue_Engine implements Action_Wear_Setting_Entity
{
    const OPTION_NAME = '_ACTIONWEAR_QUEUE_ENGINE';
    const VALID_VALUES = ['custom', 'action_scheduler'];

    public function get()
    {
        $value = get_option(self::OPTION_NAME, 'action_scheduler');
        if ($value === 'action_scheduler' && !function_exists('as_schedule_single_action')) {
            return 'custom';
        }
        return $value;
    }

    public function set($value)
    {
        if (!$this->validate($value)) {
            throw new \Exception("Invalid queue engine value. Allowed: custom, action_scheduler");
        }

        if ($value === 'action_scheduler' && !function_exists('as_schedule_single_action')) {
            throw new \Exception("Action Scheduler not available. WooCommerce is required.");
        }

        $oldValue = $this->get();
        if ($oldValue === $value) {
            return $value;
        }

        $this->switchEngine($oldValue, $value);

        update_option(self::OPTION_NAME, $value);
        JobQueue::resetBackend();

        Log::write("Queue engine switched from '{$oldValue}' to '{$value}'", Log::INFO, Log::CONTEXT_GENERAL);

        return $value;
    }

    public function validate($v): bool
    {
        return in_array($v, self::VALID_VALUES, true);
    }

    public function toggle()
    {
        $current = $this->get();
        $new = $current === 'custom' ? 'action_scheduler' : 'custom';
        return $this->set($new);
    }

    private function switchEngine(string $from, string $to): void
    {
        if ($from === 'custom' && $to === 'action_scheduler') {
            $this->switchToActionScheduler();
        } elseif ($from === 'action_scheduler' && $to === 'custom') {
            $this->switchToCustom();
        }
    }

    private function switchToActionScheduler(): void
    {
        global $wpdb;

        // Cancel all pending/claimed custom jobs
        $wpdb->query(
            "UPDATE {$wpdb->prefix}actionwear_jobs SET status = 'cancelled'
             WHERE status IN ('pending', 'claimed')"
        );

        // Release runner lock
        JobRunner::forceRelease();

        // De-register custom cron events
        $timestamp = wp_next_scheduled('actionwear_runner_hook');
        if ($timestamp) wp_unschedule_event($timestamp, 'actionwear_runner_hook');

        $timestamp = wp_next_scheduled('actionwear_scheduler_check');
        if ($timestamp) wp_unschedule_event($timestamp, 'actionwear_scheduler_check');

        Log::write("Switched to Action Scheduler: cancelled custom jobs, released lock, de-registered cron", Log::INFO, Log::CONTEXT_GENERAL);
    }

    private function switchToCustom(): void
    {
        // Cancel all AS actions in actionwear group
        if (function_exists('as_unschedule_all_actions')) {
            as_unschedule_all_actions('', null, 'actionwear');
        }

        // Re-register custom cron events
        if (!wp_next_scheduled('actionwear_runner_hook')) {
            wp_schedule_event(time(), 'actionwear_two_minutes', 'actionwear_runner_hook');
        }
        if (!wp_next_scheduled('actionwear_scheduler_check')) {
            wp_schedule_event(time(), 'weekly', 'actionwear_scheduler_check');
        }

        // Seed recurring jobs
        JobScheduler::ensureRecurringJobs();

        Log::write("Switched to Custom Queue: cancelled AS actions, re-registered cron, seeded jobs", Log::INFO, Log::CONTEXT_GENERAL);
    }
}
