<?php
/**
 * Registers and dispatches all WordPress actions and filters.
 *
 * @package Donatico
 */

declare(strict_types=1);

namespace Donatico;

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

/**
 * Maintains a queue of actions and filters and registers them all
 * with WordPress in a single pass when run() is called.
 * This decouples hook registration from actual execution.
 */
class Loader {

	/**
	 * Queued action registrations.
	 *
	 * @var array<int, array{hook: string, component: object|string, callback: string, priority: int, accepted_args: int}>
	 */
	private array $actions = array();

	/**
	 * Queued filter registrations.
	 *
	 * @var array<int, array{hook: string, component: object|string, callback: string, priority: int, accepted_args: int}>
	 */
	private array $filters = array();

	/**
	 * Queue a WordPress action.
	 *
	 * @param string         $hook          The action hook name.
	 * @param object|string  $component     The object (or class name for static) that owns the callback.
	 * @param string         $callback      Method name on $component.
	 * @param int            $priority      Hook priority. Default 10.
	 * @param int            $accepted_args Number of arguments passed to the callback. Default 1.
	 * @return void
	 */
	public function addAction(
		string $hook,
		$component,
		string $callback,
		int $priority = 10,
		int $accepted_args = 1
	): void {
		$this->actions[] = compact( 'hook', 'component', 'callback', 'priority', 'accepted_args' );
	}

	/**
	 * Queue a WordPress filter.
	 *
	 * @param string         $hook          The filter hook name.
	 * @param object|string  $component     The object (or class name for static) that owns the callback.
	 * @param string         $callback      Method name on $component.
	 * @param int            $priority      Hook priority. Default 10.
	 * @param int            $accepted_args Number of arguments passed to the callback. Default 1.
	 * @return void
	 */
	public function addFilter(
		string $hook,
		$component,
		string $callback,
		int $priority = 10,
		int $accepted_args = 1
	): void {
		$this->filters[] = compact( 'hook', 'component', 'callback', 'priority', 'accepted_args' );
	}

	/**
	 * Register all queued actions and filters with WordPress.
	 *
	 * @return void
	 */
	public function run(): void {
		foreach ( $this->filters as $hook ) {
			\add_filter(
				$hook['hook'],
				array( $hook['component'], $hook['callback'] ),
				$hook['priority'],
				$hook['accepted_args']
			);
		}

		foreach ( $this->actions as $hook ) {
			\add_action(
				$hook['hook'],
				array( $hook['component'], $hook['callback'] ),
				$hook['priority'],
				$hook['accepted_args']
			);
		}
	}
}
