<?php

declare(strict_types=1);

/**
 * Middleware для проверки авторизации в админ-панели
 * Автоматически применяется ко всем админ-маршрутам (кроме login/logout)
 *
 * @package Flowaxy\Core\Middleware
 */

namespace Flowaxy\Core\Middleware;

use Flowaxy\Support\Helpers\SecurityHelper;
use Flowaxy\Support\Helpers\RoleHelper;

use const PHP_SESSION_ACTIVE;

use function headers_sent;
use function parse_url;
use function session_start;
use function session_status;
use function str_contains;
use function str_ends_with;

final class AdminAuthMiddleware
{
    /**
     * Проверка авторизации администратора
     * Root пользователь (userId = 0) всегда имеет доступ
     *
     * @param array $params Параметры маршрута
     * @return bool true если доступ разрешен, false если нужно прервать выполнение
     */
    public static function check(array $params = []): bool
    {
        // Проверяем, не находимся ли мы уже на странице login (избегаем бесконечного редиректа)
        $currentPath = $_SERVER['REQUEST_URI'] ?? '/';
        $requestUri = parse_url($currentPath, PHP_URL_PATH) ?? $currentPath;

        // Если уже на login или logout, пропускаем проверку авторизации
        // ВАЖНО: Это должно быть первой проверкой, чтобы избежать бесконечного редиректа
        if (str_contains($requestUri, '/admin/login') ||
            str_contains($requestUri, '/admin/logout') ||
            str_ends_with($requestUri, '/login') ||
            str_ends_with($requestUri, '/logout')) {
            // Если уже на login/logout, пропускаем проверку
            return true;
        }

        // Инициализируем сессию если она еще не инициализирована
        if (function_exists('session_status')) {
            $sessionStatus = session_status();
            if ($sessionStatus !== PHP_SESSION_ACTIVE) {
                if (!headers_sent()) {
                    @session_start();
                }
            }
        }

        // Получаем userId из сессии
        $userId = self::getCurrentUserId();

        // Root пользователь (userId = 0) всегда имеет доступ
        if ($userId === 0 || $userId === '0') {
            return true;
        }

        // Если не авторизован, редирект на login
        if ($userId === null || $userId === false) {
            self::redirectToLogin();
            return false;
        }

        // Обычный пользователь - проверяем права через current_user_can
        if (function_exists('current_user_can')) {
            if (!current_user_can('admin.access')) {
                self::redirectToLogin();
                return false;
            }
        } elseif (function_exists('is_admin_logged_in')) {
            if (!is_admin_logged_in()) {
                self::redirectToLogin();
                return false;
            }
        } else {
            // Если функции проверки недоступны, редирект на login
            self::redirectToLogin();
            return false;
        }

        return true;
    }

    /**
     * Получение ID текущего пользователя из сессии
     *
     * @return int|null|false userId или null/false если не авторизован
     */
    private static function getCurrentUserId()
    {
        $userId = null;

        // Проверяем $_SESSION напрямую (самый надежный способ)
        if (function_exists('session_status') && session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['admin_user_id'])) {
            $userId = (int)$_SESSION['admin_user_id'];
        }

        // Если не получили из $_SESSION, пробуем через sessionManager
        if ($userId === null && function_exists('sessionManager')) {
            $session = sessionManager();
            if ($session !== null) {
                $sessionUserId = $session->get('admin_user_id');
                if ($sessionUserId !== null && $sessionUserId !== false) {
                    $userId = (int)$sessionUserId;
                }
            }
        }

        return $userId;
    }

    /**
     * Редирект на страницу логина
     * ВАЖНО: Должен вызывать exit для предотвращения дальнейшего выполнения
     *
     * @return never
     */
    private static function redirectToLogin(): void
    {
        // Проверяем, не находимся ли мы уже на странице login (дополнительная защита)
        $currentPath = $_SERVER['REQUEST_URI'] ?? '/';
        $requestUri = parse_url($currentPath, PHP_URL_PATH) ?? $currentPath;

        if (str_contains($requestUri, '/admin/login') ||
            str_ends_with($requestUri, '/login') ||
            str_contains($requestUri, '/admin/logout') ||
            str_ends_with($requestUri, '/logout')) {
            // Если уже на login/logout, не делаем редирект (избегаем бесконечного цикла)
            return;
        }

        // Устанавливаем заголовок редиректа
        $loginUrl = '/admin/login';
        if (function_exists('admin_url')) {
            $loginUrl = admin_url('login');
        }

        if (!headers_sent()) {
            header('Location: ' . $loginUrl, true, 302);
            // Очищаем буфер вывода перед exit
            if (ob_get_level() > 0) {
                ob_end_clean();
            }
        }

        // КРИТИЧНО: exit должен быть вызван для остановки выполнения
        exit;
    }
}
