<?php

declare(strict_types=1);

$version = $argv[1] ?? '';
if (!preg_match('/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/', $version)) {
    fwrite(STDERR, "Usage: php generate_release.php <version>\n");
    exit(1);
}

$root = dirname(__DIR__);
$package = generateDistributionPackage($root, $version);
echo $package . PHP_EOL;

function generateDistributionPackage(string $root, string $version): string
{
    if (!class_exists(ZipArchive::class)) {
        throw new RuntimeException('ZipArchive is not available.');
    }

    $release = $root . '/releases/' . $version;
    if (!is_dir($release)) {
        throw new RuntimeException('Release folder is missing: releases/' . $version);
    }

    $package = $root . '/packages/blockwriteai-' . $version . '.zip';
    if (is_file($package)) {
        unlink($package);
    }

    $zip = new ZipArchive();
    if ($zip->open($package, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
        throw new RuntimeException('Could not create package: ' . $package);
    }

    addFileIfExists($zip, $root . '/.htaccess', '.htaccess');
    addFileIfExists($zip, $root . '/admin.php', 'admin.php');
    addDirectory($zip, $root . '/api', 'api', ['config.local.php']);
    addDirectory($zip, $root . '/tools', 'tools');
    addDirectory($zip, $root . '/versions', 'versions');
    addDirectory($zip, $root . '/cdn/' . $version, 'cdn/' . $version);
    addDirectory($zip, $root . '/cdn/latest', 'cdn/latest');
    addDirectory($zip, $root . '/cdn/vendor', 'cdn/vendor');
    addDirectory($zip, $release . '/vendor', 'vendor');
    addDirectory($zip, $release . '/plugins', 'plugins');
    addDirectory($zip, $release . '/assets', 'assets');
    addDirectory($zip, $release, 'releases/' . $version, ['vendor', 'plugins', 'assets']);
    addEmptyDir($zip, 'logs');
    addEmptyDir($zip, 'temp');
    addEmptyDir($zip, 'packages');

    $zip->close();

    return $package;
}

function addDirectory(ZipArchive $zip, string $source, string $target, array $skip = []): void
{
    if (!is_dir($source)) {
        return;
    }

    $skip = array_flip($skip);
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($source, FilesystemIterator::SKIP_DOTS),
        RecursiveIteratorIterator::SELF_FIRST
    );

    foreach ($iterator as $item) {
        $name = $item->getFilename();
        if (isset($skip[$name]) || str_ends_with($name, '.map')) {
            continue;
        }

        $relative = str_replace('\\', '/', substr($item->getPathname(), strlen($source) + 1));
        foreach (explode('/', $relative) as $segment) {
            if (isset($skip[$segment])) {
                continue 2;
            }
        }

        $zipPath = trim($target . '/' . $relative, '/');
        if ($item->isDir()) {
            addEmptyDir($zip, $zipPath);
        } else {
            $zip->addFile($item->getPathname(), $zipPath);
        }
    }
}

function addFileIfExists(ZipArchive $zip, string $source, string $target): void
{
    if (is_file($source) && !str_ends_with($source, '.map')) {
        $zip->addFile($source, $target);
    }
}

function addEmptyDir(ZipArchive $zip, string $path): void
{
    $path = trim($path, '/');
    if ($path !== '') {
        $zip->addEmptyDir($path);
    }
}
