<?php

declare(strict_types=1);

namespace ShieldX\Core;

defined('ABSPATH') || exit;

final class SchedulerBridge
{
    public const ADDON_ID = 'shieldx-scheduler';
    public const TASKS_FILTER = 'shieldx_scheduler_tasks';
    public const ACTIVE_FILTER = 'shieldx_scheduler_active';
    public const CONTROLS_FILTER = 'shieldx_scheduler_controls_task';
    public const REFRESH_ACTION = 'shieldx_scheduler_refresh';
    public const SELF_HEAL_ACTION = 'shieldx_scheduler_self_heal';
    public const TASK_DISPLAY_FILTER = 'shieldx_scheduler_task_display';

    public static function active(): bool
    {
        return (bool) self::applyFilters(self::ACTIVE_FILTER, false);
    }

    public static function controlsTask(string $taskId): bool
    {
        if (!self::active()) {
            return false;
        }

        if (!function_exists('apply_filters')) {
            return true;
        }

        try {
            // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- SchedulerBridge constants are SHIELD-X-prefixed hooks; the indirection keeps scheduler integration centralized.
            return (bool) apply_filters(self::CONTROLS_FILTER, true, self::sanitizeTaskId($taskId));
        } catch (\Throwable $error) {
            \ShieldX\Support\ErrorLog::write(sprintf('SHIELD-X scheduler filter %s failed: %s', self::CONTROLS_FILTER, $error->getMessage()));

            return false;
        }
    }

    /**
     * @return array<int,array<string,mixed>>
     */
    public static function tasks(): array
    {
        return self::normalizeTasks((array) self::applyFilters(self::TASKS_FILTER, []));
    }

    /**
     * Returns scheduler tasks enriched only for an explicit scheduler display.
     *
     * Reconciliation callers must use tasks() so routine cron registration does
     * not trigger status providers, filesystem scans, or reporting work.
     *
     * @return array<int,array<string,mixed>>
     */
    public static function tasksForDisplay(): array
    {
        $tasks = self::tasks();
        return self::normalizeTasks((array) self::applyFilters(self::TASK_DISPLAY_FILTER, $tasks));
    }

    public static function refresh(): void
    {
        self::doAction(self::REFRESH_ACTION);
    }

    public static function selfHeal(): void
    {
        self::doAction(self::SELF_HEAL_ACTION);
    }

    public static function sanitizeTaskId(string $taskId): string
    {
        $taskId = strtolower(trim($taskId));

        return preg_match('/^[a-z0-9][a-z0-9_.-]{1,100}$/', $taskId) === 1 ? $taskId : '';
    }

    /**
     * @param array<int,array<string,mixed>> $tasks
     * @return array<int,array<string,mixed>>
     */
    private static function normalizeTasks(array $tasks): array
    {
        $clean = [];
        $seen = [];

        foreach ($tasks as $task) {
            if (!is_array($task)) {
                continue;
            }

            $id = self::sanitizeTaskId((string) ($task['id'] ?? ''));
            if ($id === '' || isset($seen[$id])) {
                continue;
            }

            $task['id'] = $id;
            $clean[] = $task;
            $seen[$id] = true;
        }

        return $clean;
    }

    /**
     * @param mixed $value
     * @param mixed ...$args
     * @return mixed
     */
    private static function applyFilters(string $hook, $value, ...$args)
    {
        if (!function_exists('apply_filters')) {
            return $value;
        }

        try {
            // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- SchedulerBridge only receives SHIELD-X-prefixed hook constants through this helper.
            return apply_filters($hook, $value, ...$args);
        } catch (\Throwable $error) {
            \ShieldX\Support\ErrorLog::write(sprintf('SHIELD-X scheduler filter %s failed: %s', $hook, $error->getMessage()));

            return $value;
        }
    }

    /**
     * @param mixed ...$args
     */
    private static function doAction(string $hook, ...$args): void
    {
        if (!function_exists('do_action')) {
            return;
        }

        try {
            // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- SchedulerBridge only receives SHIELD-X-prefixed action constants through this helper.
            do_action($hook, ...$args);
        } catch (\Throwable $error) {
            \ShieldX\Support\ErrorLog::write(sprintf('SHIELD-X scheduler action %s failed: %s', $hook, $error->getMessage()));
        }
    }
}
