<?php
declare(strict_types=1);

/**
 * بارگذاری انتخابی کنترلرها بر اساس مسیر درخواست
 */

function acc_request_path_early(): string
{
    if (!empty($_GET['rest_route'])) {
        $path = (string) $_GET['rest_route'];
        return '/' . trim(rawurldecode($path), '/');
    }

    $uriPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
    $uriPath = is_string($uriPath) ? str_replace('\\', '/', $uriPath) : '/';

    foreach (['SCRIPT_NAME', 'PHP_SELF'] as $key) {
        $script = str_replace('\\', '/', (string) ($_SERVER[$key] ?? ''));
        if ($script !== '' && str_starts_with($uriPath, $script)) {
            $uriPath = substr($uriPath, strlen($script));
            break;
        }
    }

    foreach (['api.php', 'index.php'] as $front) {
        $marker = '/' . $front . '/';
        $pos = strpos($uriPath, $marker);
        if ($pos !== false) {
            $uriPath = substr($uriPath, $pos + strlen($front) + 1);
            break;
        }
    }

    $uriPath = '/' . trim(rawurldecode($uriPath), '/');
    return preg_replace('#/+#', '/', $uriPath) ?: '/';
}

function acc_should_load_all_controllers(): bool
{
    if (isset($_GET['debug_routes']) && (string) $_GET['debug_routes'] === '1') {
        return true;
    }
    if (defined('ACC_LOAD_ALL_CONTROLLERS') && ACC_LOAD_ALL_CONTROLLERS) {
        return true;
    }
    return false;
}

/**
 * @return string[] relative paths under includes/controllers/
 */
function acc_resolve_controller_files(string $path): array
{
    if (acc_should_load_all_controllers()) {
        return acc_list_all_controller_files();
    }

    /** @var array $manifest */
    $manifest = require __DIR__ . '/controller_manifest.php';
    $files    = $manifest['always'] ?? [];

    $normalized = '/' . trim($path, '/');
    foreach ($manifest['paths'] ?? [] as $prefix => $extra) {
        if (str_starts_with($normalized, $prefix)) {
            $files = array_merge($files, $extra);
        }
    }

    $parts  = array_values(array_filter(explode('/', trim($normalized, '/'))));
    $module = $parts[2] ?? '';

    if ($module !== '' && !empty($manifest['modules'][$module])) {
        $files = array_merge($files, $manifest['modules'][$module]);
    }

    $files = array_values(array_unique($files));

    if ($module === '' || empty($manifest['modules'][$module])) {
        return acc_list_all_controller_files();
    }

    return $files;
}

function acc_list_all_controller_files(): array
{
    $base = ACC_BASE_PATH . '/includes/controllers';
    $out  = [];

    foreach (glob($base . '/*_Controller.php') ?: [] as $full) {
        $out[] = basename($full);
    }
    foreach (glob($base . '/class-acc-*-controller.php') ?: [] as $full) {
        $out[] = basename($full);
    }

    return array_values(array_unique($out));
}

/**
 * @return array{loaded: string[], errors: array<int, array{file: string, message: string}>, classes: string[]}
 */
function acc_load_controllers_for_path(string $path): array
{
    $base           = ACC_BASE_PATH . '/includes/controllers';
    $relativeFiles  = acc_resolve_controller_files($path);
    $loaded         = [];
    $errors         = [];
    $classes        = [];

    foreach ($relativeFiles as $fileName) {
        $fullPath = $base . DIRECTORY_SEPARATOR . $fileName;
        $relative = 'includes/controllers/' . $fileName;

        if (!is_file($fullPath)) {
            continue;
        }

        try {
            require_once $fullPath;
            $loaded[] = $relative;

            $baseName = basename($fileName, '.php');
            if (str_starts_with($baseName, 'class-acc-') && str_ends_with($baseName, '-controller')) {
                $inner = substr($baseName, strlen('class-acc-'), -strlen('-controller'));
                $parts = explode('-', $inner);
                $guess = 'ACC_' . implode('', array_map('ucfirst', $parts)) . 'Controller';
                if (class_exists($guess) && method_exists($guess, 'register_routes')) {
                    $classes[] = $guess;
                }
            } elseif (class_exists($baseName) && method_exists($baseName, 'register_routes')) {
                $classes[] = $baseName;
            }
        } catch (Throwable $e) {
            $errors[] = [
                'file'    => $relative,
                'message' => $e->getMessage(),
            ];
        }
    }

    return [
        'loaded'  => $loaded,
        'errors'  => $errors,
        'classes' => array_values(array_unique($classes)),
    ];
}
