<?php

/**
 * Фасад для роботи з хуками
 *
 * @package Flowaxy\Support\Facades
 */

declare(strict_types=1);

namespace Flowaxy\Support\Facades;

use Flowaxy\Core\Contracts\HookManagerInterface;
use Flowaxy\Core\System\PathResolver;
use Flowaxy\Core\Hooks\HookType;
use Flowaxy\Support\Managers\PluginManager;
use Flowaxy\Core\Hooks\HookManager;

use RuntimeException;
use Throwable;

use function class_exists;
use function interface_exists;
use function function_exists;
use function method_exists;
use function file_exists;
use function is_readable;

final class Hooks extends Facade
{
    protected static function getFacadeAccessor(): string
    {
        return HookManagerInterface::class;
    }

    /**
     * Виконання події (action)
     */
    public static function dispatch(string $hookName, mixed ...$args): void
    {
        // Завантажуємо HookType перед використанням
        if (!class_exists(HookType::class)) {
            $flowaxyDir = PathResolver::flowaxy();
            $hookTypeFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookType.php';
            if (file_exists($hookTypeFile) && is_readable($hookTypeFile)) {
                require_once $hookTypeFile;
            }
        }

        // Завантажуємо PluginManager, якщо він ще не завантажений
        if (!class_exists(PluginManager::class)) {
            $flowaxyDir = PathResolver::flowaxy();
            $pluginManagerFile = $flowaxyDir . DS . 'Support' . DS . 'Managers' . DS . 'PluginManager.php';
            if (file_exists($pluginManagerFile) && is_readable($pluginManagerFile)) {
                require_once $pluginManagerFile;
            }
        }

        $pluginManager = null;
        $pluginManagerFunc = 'pluginManager';
        if (function_exists($pluginManagerFunc)) {
            /** @var PluginManager|null $pluginManager */
            $pluginManager = $pluginManagerFunc();
        }

        if ($pluginManager === null && class_exists(PluginManager::class)) {
            // Fallback: используем PluginManager напрямую
            $pluginManager = PluginManager::getInstance();
        }

        if ($pluginManager instanceof PluginManager && method_exists($pluginManager, 'prepareHook')) {
            $pluginManager->prepareHook($hookName, HookType::Action, $args);
        }

        // Отримуємо HookManager через контейнер або fallback
        $instance = null;
        try {
            $instance = static::getFacadeRoot();
        } catch (RuntimeException $e) {
            // Fallback: створюємо HookManager напрямую, якщо контейнер недоступний
            $flowaxyDir = PathResolver::flowaxy();

            // Завантажуємо необхідні інтерфейси та класи
            if (!interface_exists('Flowaxy\Core\Contracts\HookRegistryInterface')) {
                $hookRegistryInterfaceFile = $flowaxyDir . DS . 'Core' . DS . 'Contracts' . DS . 'HookRegistryInterface.php';
                if (file_exists($hookRegistryInterfaceFile) && is_readable($hookRegistryInterfaceFile)) {
                    require_once $hookRegistryInterfaceFile;
                }
            }

            if (!interface_exists('Flowaxy\Core\Contracts\HookManagerInterface')) {
                $hookManagerInterfaceFile = $flowaxyDir . DS . 'Core' . DS . 'Contracts' . DS . 'HookManagerInterface.php';
                if (file_exists($hookManagerInterfaceFile) && is_readable($hookManagerInterfaceFile)) {
                    require_once $hookManagerInterfaceFile;
                }
            }

            if (!class_exists('Flowaxy\Core\Hooks\HookRegistry')) {
                $hookRegistryFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookRegistry.php';
                if (file_exists($hookRegistryFile) && is_readable($hookRegistryFile)) {
                    require_once $hookRegistryFile;
                }
            }

            if (!class_exists('Flowaxy\Core\Hooks\HookPerformanceMonitor')) {
                $hookPerformanceMonitorFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookPerformanceMonitor.php';
                if (file_exists($hookPerformanceMonitorFile) && is_readable($hookPerformanceMonitorFile)) {
                    require_once $hookPerformanceMonitorFile;
                }
            }

            if (!class_exists(HookManager::class)) {
                $hookManagerFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookManager.php';
                if (file_exists($hookManagerFile) && is_readable($hookManagerFile)) {
                    require_once $hookManagerFile;
                }
            }

            if (class_exists(HookManager::class)) {
                $instance = new HookManager();
            }
        }

        if ($instance instanceof HookManagerInterface) {
            $instance->dispatch($hookName, ...$args);
        }
    }

    /**
     * Застосування фільтра (filter)
     *
     * @param string $hookName
     * @param mixed $value
     * @param array<string, mixed> $context
     * @return mixed
     */
    public static function apply(string $hookName, mixed $value = null, array $context = []): mixed
    {
        // Завантажуємо HookType перед використанням
        if (!class_exists(HookType::class)) {
            $flowaxyDir = PathResolver::flowaxy();
            $hookTypeFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookType.php';
            if (file_exists($hookTypeFile) && is_readable($hookTypeFile)) {
                require_once $hookTypeFile;
            }
        }

        // Завантажуємо PluginManager, якщо він ще не завантажений
        if (!class_exists(PluginManager::class)) {
            $flowaxyDir = PathResolver::flowaxy();
            $pluginManagerFile = $flowaxyDir . DS . 'Support' . DS . 'Managers' . DS . 'PluginManager.php';
            if (file_exists($pluginManagerFile) && is_readable($pluginManagerFile)) {
                require_once $pluginManagerFile;
            }
        }

        $pluginManager = null;
        $pluginManagerFunc = 'pluginManager';
        if (function_exists($pluginManagerFunc)) {
            /** @var PluginManager|null $pluginManager */
            $pluginManager = $pluginManagerFunc();
        }

        if ($pluginManager === null && class_exists(PluginManager::class)) {
            // Fallback: используем PluginManager напрямую
            $pluginManager = PluginManager::getInstance();
        }

        if ($pluginManager instanceof PluginManager && method_exists($pluginManager, 'prepareHook')) {
            $value = $pluginManager->prepareHook($hookName, HookType::Filter, $value);
        }

        // Отримуємо HookManager через контейнер або fallback
        $instance = null;
        try {
            $instance = static::getFacadeRoot();
        } catch (RuntimeException $e) {
            // Fallback: створюємо HookManager напрямую, якщо контейнер недоступний
            $flowaxyDir = PathResolver::flowaxy();

            // Завантажуємо необхідні інтерфейси та класи
            if (!interface_exists('Flowaxy\Core\Contracts\HookRegistryInterface')) {
                $hookRegistryInterfaceFile = $flowaxyDir . DS . 'Core' . DS . 'Contracts' . DS . 'HookRegistryInterface.php';
                if (file_exists($hookRegistryInterfaceFile) && is_readable($hookRegistryInterfaceFile)) {
                    require_once $hookRegistryInterfaceFile;
                }
            }

            if (!interface_exists('Flowaxy\Core\Contracts\HookManagerInterface')) {
                $hookManagerInterfaceFile = $flowaxyDir . DS . 'Core' . DS . 'Contracts' . DS . 'HookManagerInterface.php';
                if (file_exists($hookManagerInterfaceFile) && is_readable($hookManagerInterfaceFile)) {
                    require_once $hookManagerInterfaceFile;
                }
            }

            if (!class_exists('Flowaxy\Core\Hooks\HookRegistry')) {
                $hookRegistryFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookRegistry.php';
                if (file_exists($hookRegistryFile) && is_readable($hookRegistryFile)) {
                    require_once $hookRegistryFile;
                }
            }

            if (!class_exists('Flowaxy\Core\Hooks\HookPerformanceMonitor')) {
                $hookPerformanceMonitorFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookPerformanceMonitor.php';
                if (file_exists($hookPerformanceMonitorFile) && is_readable($hookPerformanceMonitorFile)) {
                    require_once $hookPerformanceMonitorFile;
                }
            }

            if (!class_exists(HookManager::class)) {
                $hookManagerFile = $flowaxyDir . DS . 'Core' . DS . 'Hooks' . DS . 'HookManager.php';
                if (file_exists($hookManagerFile) && is_readable($hookManagerFile)) {
                    require_once $hookManagerFile;
                }
            }

            if (class_exists(HookManager::class)) {
                $instance = new HookManager();
            }
        }

        if ($instance instanceof HookManagerInterface) {
            return $instance->apply($hookName, $value, $context);
        }

        return $value;
    }
}
