<?php

namespace Kylin\Excel\Events;

use Kylin\Excel\Concerns\WithEvents;

/**
 * 事件调度器
 * 
 * 负责管理和触发Excel导入导出过程中的各种事件
 */
class EventDispatcher
{
    /**
     * 注册的事件监听器
     * 
     * @var array
     */
    protected array $listeners = [];

    /**
     * 注册事件监听器
     * 
     * @param string $event 事件类名
     * @param callable $listener 监听器回调函数
     * @return void
     */
    public function listen(string $event, callable $listener): void
    {
        $this->listeners[$event][] = $listener;
    }

    /**
     * 批量注册事件监听器
     * 
     * @param array $listeners 事件监听器数组
     * @return void
     */
    public function registerListeners(array $listeners): void
    {
        foreach ($listeners as $event => $listener) {
            $this->listen($event, $listener);
        }
    }

    /**
     * 触发事件
     * 
     * @param Event $event 事件实例
     * @return void
     */
    public function dispatch(Event $event): void
    {
        $eventName = get_class($event);

        if (!isset($this->listeners[$eventName])) {
            return;
        }

        foreach ($this->listeners[$eventName] as $listener) {
            call_user_func($listener, $event);
        }
    }

    /**
     * 从WithEvents对象注册事件监听器
     * 
     * @param WithEvents $withEvents 实现WithEvents接口的对象
     * @return void
     */
    public function registerFromWithEvents(WithEvents $withEvents): void
    {
        $events = $withEvents->registerEvents();
        $this->registerListeners($events);
    }

    /**
     * 检查事件是否有监听器
     * 
     * @param string $event 事件类名
     * @return bool
     */
    public function hasListeners(string $event): bool
    {
        return !empty($this->listeners[$event]);
    }

    /**
     * 清除所有监听器
     * 
     * @return void
     */
    public function clearListeners(): void
    {
        $this->listeners = [];
    }
}
