<?php

/**
 * Централизованное управление путями в системе
 *
 * @package Flowaxy\Core\System
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Core\System;

use function array_filter;
use function array_pop;
use function constant;
use function defined;
use function dirname;
use function explode;
use function implode;
use function preg_match;
use function realpath;
use function rtrim;
use function str_replace;
use function str_starts_with;
use function trim;

class PathResolver
{
    private static array $cache = [];

    /**
     * Получить корень проекта (workbench/)
     */
    public static function root(): string
    {
        return self::getCached('root', function() {
            // Используем существующую константу ROOT_DIR если определена
            if (defined('ROOT_DIR')) {
                return (string) constant('ROOT_DIR');
            }
            // Fallback: вычисляем от текущего файла
            // PathResolver.php находится в flowaxy/Core/System/
            // __DIR__ = flowaxy/Core/System/
            // dirname(__DIR__, 1) = flowaxy/Core/
            // dirname(__DIR__, 2) = flowaxy/
            // dirname(__DIR__, 3) = workbench/
            return dirname(__DIR__, 3);
        });
    }

    /**
     * Получить путь к ядру системы (engine/)
     */
    public static function engine(): string
    {
        return self::getCached('engine', function() {
            // Используем существующую константу ENGINE_DIR если определена
            if (defined('ENGINE_DIR')) {
                return (string) constant('ENGINE_DIR');
            }
            // Fallback: вычисляем от корня
            return self::root() . DS . 'engine';
        });
    }

    /**
     * Получить путь к новой структуре (flowaxy/)
     */
    public static function flowaxy(): string
    {
        return self::getCached('flowaxy', function() {
            if (defined('FLOWAXY_DIR')) {
                return (string) constant('FLOWAXY_DIR');
            }
            return self::root() . DS . 'flowaxy';
        });
    }

    /**
     * Получить путь к плагинам
     */
    public static function plugins(): string
    {
        return self::getCached('plugins', function() {
            if (defined('ENGINE_PLUGINS_DIR')) {
                return (string) constant('ENGINE_PLUGINS_DIR');
            }
            return self::root() . DS . 'content' . DS . 'plugins';
        });
    }

    /**
     * Получить путь к конкретному плагину
     */
    public static function plugin(string $pluginSlug): string
    {
        return self::plugins() . DS . $pluginSlug;
    }

    /**
     * Получить путь к темам
     */
    public static function themes(): string
    {
        return self::getCached('themes', function() {
            if (defined('ENGINE_THEMES_DIR')) {
                return (string) constant('ENGINE_THEMES_DIR');
            }
            return self::root() . DS . 'content' . DS . 'themes';
        });
    }

    /**
     * Получить путь к конкретной теме
     */
    public static function theme(string $themeSlug): string
    {
        return self::themes() . DS . $themeSlug;
    }

    /**
     * Получить путь к storage
     */
    public static function storage(): string
    {
        return self::getCached('storage', function() {
            if (defined('ENGINE_STORAGE_DIR')) {
                return (string) constant('ENGINE_STORAGE_DIR');
            }
            return self::root() . DS . 'storage';
        });
    }

    /**
     * Получить путь к кешу
     */
    public static function cache(): string
    {
        return self::getCached('cache', function() {
            if (defined('CACHE_DIR')) {
                return (string) constant('CACHE_DIR');
            }
            if (defined('ENGINE_STORAGE_CACHE_DIR')) {
                return (string) constant('ENGINE_STORAGE_CACHE_DIR');
            }
            return self::storage() . DS . 'cache';
        });
    }

    /**
     * Получить путь к логам
     */
    public static function logs(): string
    {
        return self::getCached('logs', function() {
            if (defined('LOGS_DIR')) {
                return (string) constant('LOGS_DIR');
            }
            if (defined('ENGINE_STORAGE_LOGS_DIR')) {
                return (string) constant('ENGINE_STORAGE_LOGS_DIR');
            }
            return self::storage() . DS . 'logs';
        });
    }

    /**
     * Получить путь к uploads
     */
    public static function uploads(): string
    {
        return self::getCached('uploads', function() {
            if (defined('UPLOADS_DIR')) {
                return (string) constant('UPLOADS_DIR');
            }
            if (defined('ENGINE_UPLOADS_DIR')) {
                return (string) constant('ENGINE_UPLOADS_DIR');
            }
            return self::root() . DS . 'uploads';
        });
    }

    /**
     * Получить путь к сессиям
     */
    public static function sessions(): string
    {
        return self::getCached('sessions', function() {
            if (defined('ENGINE_STORAGE_SESSIONS_DIR')) {
                return (string) constant('ENGINE_STORAGE_SESSIONS_DIR');
            }
            return self::storage() . DS . 'sessions';
        });
    }

    /**
     * Получить путь к конфигурации storage
     */
    public static function storageConfig(): string
    {
        return self::getCached('storageConfig', function() {
            if (defined('ENGINE_STORAGE_CONFIG_DIR')) {
                return (string) constant('ENGINE_STORAGE_CONFIG_DIR');
            }
            return self::storage() . DS . 'config';
        });
    }

    /**
     * Получить путь к core директории
     */
    public static function core(): string
    {
        return self::getCached('core', function() {
            if (defined('ENGINE_CORE_DIR')) {
                return (string) constant('ENGINE_CORE_DIR');
            }
            return self::engine() . DS . 'core';
        });
    }

    /**
     * Получить путь к bootstrap
     */
    public static function bootstrap(): string
    {
        return self::getCached('bootstrap', function() {
            return self::flowaxy() . DS . 'Bootstrap';
        });
    }

    /**
     * Получить путь к системным модулям фреймворка (Base, Auth, Errors)
     */
    public static function modules(): string
    {
        return self::getCached('modules', function() {
            return self::flowaxy() . DS . 'Core' . DS . 'System';
        });
    }

    /**
     * Получить путь к внешним модулям (API, Installer)
     */
    public static function externalModules(): string
    {
        return self::getCached('externalModules', function() {
            if (defined('MODULES_DIR')) {
                return (string) constant('MODULES_DIR');
            }
            return self::root() . DS . 'modules';
        });
    }

    /**
     * Получить путь к тестам
     */
    public static function testing(): string
    {
        return self::getCached('testing', function() {
            if (defined('TESTING_DIR')) {
                return (string) constant('TESTING_DIR');
            }
            return self::root() . DS . 'testing';
        });
    }

    /**
     * Получить путь к админке
     */
    public static function admin(): string
    {
        return self::getCached('admin', function() {
            if (defined('ADMIN_DIR')) {
                return (string) constant('ADMIN_DIR');
            }
            return self::root() . DS . 'content' . DS . 'admin';
        });
    }

    /**
     * Получить путь к content/
     */
    public static function content(): string
    {
        return self::getCached('content', function() {
            if (defined('CONTENT_DIR')) {
                return (string) constant('CONTENT_DIR');
            }
            return self::root() . DS . 'content';
        });
    }

    /**
     * Получить путь к content/admin/
     */
    public static function contentAdmin(): string
    {
        return self::getCached('contentAdmin', function() {
            return self::content() . DS . 'admin';
        });
    }

    /**
     * Получить путь к content/admin/resources/
     */
    public static function contentAssets(): string
    {
        return self::getCached('contentAssets', function() {
            return self::contentAdmin() . DS . 'resources';
        });
    }


    /**
     * Построить путь относительно корня проекта
     */
    public static function join(string ...$parts): string
    {
        $path = self::root();
        foreach ($parts as $part) {
            $path .= DS . trim($part, '/\\');
        }
        return $path;
    }

    /**
     * Нормализовать путь (убрать относительные части)
     */
    public static function normalize(string $path): string
    {
        $path = str_replace(['/', '\\'], DS, $path);
        $parts = array_filter(explode(DS, $path), function($part) {
            return $part !== '.' && $part !== '';
        });

        $normalized = [];
        foreach ($parts as $part) {
            if ($part === '..') {
                if (!empty($normalized)) {
                    array_pop($normalized);
                }
            } else {
                $normalized[] = $part;
            }
        }

        return implode(DS, $normalized);
    }

    /**
     * Получить реальный путь (resolve symlinks)
     */
    public static function real(string $path): ?string
    {
        $realPath = realpath($path);
        return $realPath ?: null;
    }

    /**
     * Проверить, является ли путь абсолютным
     */
    public static function isAbsolute(string $path): bool
    {
        // Windows: C:\ или \\server
        if (preg_match('/^([A-Z]:[\\\\\/]|\\\\\\\\)/i', $path)) {
            return true;
        }
        // Unix: начинается с /
        return str_starts_with($path, '/');
    }

    /**
     * Кеширование путей
     */
    private static function getCached(string $key, callable $resolver): string
    {
        if (!isset(self::$cache[$key])) {
            self::$cache[$key] = rtrim($resolver(), '/\\') . DS;
        }
        return rtrim(self::$cache[$key], '/\\');
    }

    /**
     * Очистить кеш путей (для тестов)
     */
    public static function clearCache(): void
    {
        self::$cache = [];
    }
}
