<?php

namespace App\Services;

use function config;

class ComposerWorkspace
{
    protected const PATH_REPOSITORY_URL = '/var/www/packages/package-*';

    public static function createThemeComposerFile(): string
    {
        $themeDir = sprintf('%s/theme', config('project.directory'));
        $baseComposerFile = sprintf('%s/composer.json', $themeDir);
        $workspaceComposerFile = sprintf('%s/.composer.workspace.json', $themeDir);

        if (!file_exists($baseComposerFile)) {
            throw new \RuntimeException(sprintf('Could not find %s', $baseComposerFile));
        }

        $composer = json_decode(file_get_contents($baseComposerFile), true, 512, JSON_THROW_ON_ERROR);
        $repositories = $composer['repositories'] ?? [];

        array_unshift($repositories, self::pathRepositoryDefinition($composer));

        $composer['repositories'] = $repositories;

        file_put_contents(
            $workspaceComposerFile,
            json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL,
        );

        return $workspaceComposerFile;
    }

    public static function cleanupThemeComposerFile(): void
    {
        $workspaceComposerFile = sprintf('%s/theme/.composer.workspace.json', config('project.directory'));

        if (file_exists($workspaceComposerFile)) {
            unlink($workspaceComposerFile);
        }
    }

    protected static function pathRepositoryDefinition(array $composer): array
    {
        return [
            'type' => 'path',
            'url' => self::PATH_REPOSITORY_URL,
            'canonical' => false,
            'options' => [
                'symlink' => true,
                'versions' => self::workspacePackageVersions($composer),
            ],
        ];
    }

    protected static function workspacePackageVersions(array $composer): array
    {
        $versions = [];

        foreach (['require', 'require-dev'] as $section) {
            foreach ($composer[$section] ?? [] as $package => $constraint) {
                if (!str_starts_with($package, 'probots/wordpress-package-')) {
                    continue;
                }

                $versions[$package] = self::normalizeConstraintToWorkspaceVersion($constraint);
            }
        }

        $versions['probots/wordpress-package-cli'] ??= '0.0.999';
        $versions['probots/wordpress-package-debug'] ??= '0.0.999';

        ksort($versions);

        return $versions;
    }

    protected static function normalizeConstraintToWorkspaceVersion(string $constraint): string
    {
        $constraint = trim($constraint);

        if ($constraint === '' || $constraint === '*') {
            return '9999999-dev';
        }

        if (preg_match('/^(\d+)\.(\d+)\.\*$/', $constraint, $matches) === 1) {
            return sprintf('%s.%s.999', $matches[1], $matches[2]);
        }

        if (preg_match('/^(\d+)\.\*$/', $constraint, $matches) === 1) {
            return sprintf('%s.999.999', $matches[1]);
        }

        if (preg_match('/^[~^]?(\d+)\.(\d+)(?:\.(\d+))?$/', $constraint, $matches) === 1) {
            return sprintf('%s.%s.%s', $matches[1], $matches[2], $matches[3] ?? '999');
        }

        return '9999999-dev';
    }
}
