<?php
declare(strict_types=1);

use Isolated\Symfony\Component\Finder\Finder;
//use Symfony\Component\Finder\Finder;

////////////////////
// Configuration
////////////////////

$apiFolder = getcwd() . '/inc/api/';
$whitelistFolders = ['vendor/symfony/polyfill*'];
$whiteListNamespaces = [
    // Do not scope polyfills
    'Symfony\\Polyfill',
];

////////////////////

// Obtain original namespace (must be the first entry in autoload.psr-4)
$composerJson = json_decode(file_get_contents('composer.json'), true);
$psr4 = array_keys($composerJson['autoload']['psr-4'])[0];

// Obtain stubs generated by scope.ts
$stubsJson = json_decode(file_get_contents('php-scoper.php.json'), true);

// Whitelist all available monorepo-plugins (e.g. Real Physical Media can access functions of Real Media Library)
foreach (glob('../../../*', GLOB_ONLYDIR) as $key => $plugin) {
    $composerJson = json_decode(file_get_contents($plugin . '/composer.json'), true);
    $whiteListNamespaces[] = trim(array_keys($composerJson['autoload']['psr-4'])[0], '\\');
}

// Expand all files from folders to absolute file pathes
$whitelistFoldersFiles = [];
foreach ($whitelistFolders as $whitelistFolder) {
    try {
        $whitelistFoldersFiles = array_merge(
            $whitelistFoldersFiles,
            array_map(
                'realpath',
                array_keys(iterator_to_array(Finder::create()->files()->ignoreUnreadableDirs()->in($whitelistFolder)))
            )
        );
    } catch (Exception $e) {
        // Silence is golden.
    }
}

return [
    'prefix' => $psr4 . 'Vendor',
    'finders' => [
        Finder::create()->files()->in('inc'),
        Finder::create()
            ->files()
            ->notName('/LICENSE|.*\\.md|.*\\.dist|Makefile|composer\\.json|composer\\.lock/')
            ->exclude(['doc', 'test', 'test_old', 'tests', 'Tests', 'vendor-bin'])
            ->in('vendor'),
        Finder::create()->append(['composer.json']),
    ],
    'patchers' => [
        /**
         * Allow to remove namespace for a file, when the defined functions should be globally available.
         * This is useful for plugin APIs. See also documentation above `expose-global-functions`.
         *
         * This is part of the global API handling vs. `expose-global-functions`.
         */
        function ($filePath, $prefix, $content) use ($apiFolder) {
            if (strpos($filePath, $apiFolder, 0) === 0) {
                $prefixDoubleSlashed = str_replace('\\', '\\\\', $prefix);
                return preg_replace(
                    sprintf('/^(namespace %s;)$/m', $prefixDoubleSlashed),
                    '// $1 // excluded from scope due to API exposing',
                    $content,
                    1
                );
            }
            return $content;
        },
        /**
         * PHP Scoper also scopes strings representing a namespace, e.g. the following code block gets prefixed:
         *
         * From:
         *
         * ```
         * array(
         *      'Plugin\\UpdateChecker' => Plugin\UpdateChecker::class,
         *      'Theme\\UpdateChecker'  => Theme\UpdateChecker::class
         * )
         * ```
         *
         * To:
         *
         * ```
         * array(
         *      'Scoped\\Plugin\\UpdateChecker' => Plugin\UpdateChecker::class,
         *      'Scoped\\Theme\\UpdateChecker'  => Theme\UpdateChecker::class
         * )
         * ```
         *
         * For this, we need to implement a custom patcher.
         *
         * @see https://github.com/YahnisElsts/plugin-update-checker/blob/5f251be064949ddce8a040a2bb9e4e1747000d95/load-v5p3.php#L16-L26
         * @see https://regex101.com/r/VKYu7F/1
         */
        function ($filePath, $prefix, $content) {
            if (preg_match('/plugin-update-checker\/load-v\d+p\d\.php/', $filePath)) {
                return preg_replace('/\'[^\']+\\\\\\\\([^\\\\]+\\\\\\\\\w*UpdateChecker)\'/m', "'$1'", $content);
            }
            return $content;
        },
        /**
         * > Cannot declare class DevOwl\...\Vendor\Composer\InstalledVersions
         *
         * Unfortunately, after running `composer dump-autoload --classmap-authoritative`, the autoloader removes the prefix
         * of the `InstalledVersions` class in `autoload_classmap.php` and `autoload_static.php`:
         * `DevOwl\...\Vendor\Composer\InstalledVersions` to `Composer\InstalledVersions`.
         *
         * -> This does not work as described in the Github Issue as `composer dump-autoload` overrides the file again with
         * the wrong prefix. I have moved it to the Taskfile.yml process.
         *
         * @see https://github.com/humbug/php-scoper/issues/841
         */
        /*function ($filePath, $prefix, $contents) {
            if (preg_match('/vendor\/composer\/autoload_(classmap|static)\.php$/', $filePath)) {
                return preg_replace(
                    '/\'(Composer\\\\\\\\InstalledVersions)\'/',
                    $prefix . '$1',
                    $contents
                );
            }

            return $contents;
        },*/
    ],
    'exclude-namespaces' => $whiteListNamespaces,
    'exclude-classes' => array_values(array_merge($stubsJson['class'], $stubsJson['interface'], $stubsJson['trait'])),
    'exclude-functions' => $stubsJson['function'],
    'exclude-files' => array_merge(
        $whitelistFoldersFiles,
        array_map(
            'realpath',
            array_keys(iterator_to_array(Finder::create()->files()->in('inc/base/others')->notName('start.php')))
        )
    ),
    /**
     * We still cannot use `expose-global-functions` as this would also lead to exposing functions
     * like `json5_decode` (global vendor functions). That's why we add `inc/api/` to the list of stub functions
     * and remove the namespace from those files (as they get also namespaced by PHP Scoper).
     *
     * This is part of the global API handling vs. `expose-global-functions`.
     */
    'expose-global-constants' => true,
    'expose-global-classes' => false,
    'expose-global-functions' => false,
];
