<?php

declare(strict_types=1);

namespace Maestro\Core\Support;

use Composer\InstalledVersions;
use Maestro\Core\Providers\CoreServiceProvider;

/**
 * Resolves published versions of maestro/core from the installed Composer package
 * (composer.lock / InstalledVersions) and package.json shipped with the library.
 */
final class MaestroCoreVersions
{
    /**
     * @return array{npm: string|null, composer: string|null}
     */
    public static function toArray(): array
    {
        $root = self::packageRoot();

        return [
            'npm' => self::readNpmVersion($root),
            'composer' => self::readComposerPrettyVersion($root),
        ];
    }

    private static function packageRoot(): string
    {
        return dirname((new \ReflectionClass(CoreServiceProvider::class))->getFileName(), 3);
    }

    private static function readNpmVersion(string $root): ?string
    {
        $path = $root.'/package.json';
        if (! is_readable($path)) {
            return null;
        }

        /** @var array<string, mixed>|null $json */
        $json = json_decode((string) file_get_contents($path), true);
        if (! is_array($json)) {
            return null;
        }

        $v = $json['version'] ?? null;

        return is_string($v) && $v !== '' ? $v : null;
    }

    private static function readComposerPrettyVersion(string $root): ?string
    {
        if (class_exists(InstalledVersions::class) && InstalledVersions::isInstalled('maestro/core')) {
            try {
                return InstalledVersions::getPrettyVersion('maestro/core');
            } catch (\Throwable) {
                // fall through
            }
        }

        return self::readComposerJsonDeclaredVersion($root);
    }

    private static function readComposerJsonDeclaredVersion(string $root): ?string
    {
        $path = $root.'/composer.json';
        if (! is_readable($path)) {
            return null;
        }

        /** @var array<string, mixed>|null $json */
        $json = json_decode((string) file_get_contents($path), true);
        if (! is_array($json)) {
            return null;
        }

        $v = $json['version'] ?? null;

        return is_string($v) && $v !== '' ? $v : null;
    }
}
