<?php

declare(strict_types=1);

namespace PpPhp\Core\Platform\Runtime;

final class ManifestServiceLoader
{
    /**
     * @return array<string, array<string, mixed>>
     */
    public function load(string $basePath): array
    {
        $services = [];

        foreach ($this->manifestFiles($basePath) as $manifestFile) {
            $data = json_decode((string) file_get_contents($manifestFile), true);

            if (!is_array($data)) {
                continue;
            }

            foreach ($this->extractServices($data, $manifestFile) as $service) {
                $id = trim((string) ($service['id'] ?? ''));

                if ($id === '') {
                    continue;
                }

                $services[$id] = $service;
            }
        }

        ksort($services);

        return $services;
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    private function extractServices(array $manifest, string $manifestFile): array
    {
        $services = is_array($manifest['services'] ?? null) ? $manifest['services'] : [];
        $out = [];

        foreach ($services as $service) {
            if (!is_array($service)) {
                continue;
            }

            $service['sourceManifest'] = $manifestFile;
            $service['sourcePackage'] = [
                'id' => (string) ($manifest['id'] ?? ''),
                'type' => (string) ($manifest['type'] ?? ''),
                'label' => (string) ($manifest['label'] ?? $manifest['name'] ?? ''),
                'version' => (string) ($manifest['version'] ?? ''),
            ];

            $out[] = $service;
        }

        return $out;
    }

    /**
     * @return string[]
     */
    private function manifestFiles(string $basePath): array
    {
        $files = [];

        if (!is_dir($basePath)) {
            return $files;
        }

        $skip = [
            DIRECTORY_SEPARATOR . '.git' . DIRECTORY_SEPARATOR,
            DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR,
            DIRECTORY_SEPARATOR . 'node_modules' . DIRECTORY_SEPARATOR,
            DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR,
        ];

        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($basePath, \FilesystemIterator::SKIP_DOTS)
        );

        foreach ($iterator as $file) {
            if (!$file instanceof \SplFileInfo || !$file->isFile()) {
                continue;
            }

            $path = $file->getPathname();

            foreach ($skip as $fragment) {
                if (str_contains($path, $fragment)) {
                    continue 2;
                }
            }

            if ($file->getFilename() === 'manifest.json') {
                $files[] = $path;
            }
        }

        sort($files);

        return $files;
    }
}
