#!/usr/bin/env php
<?php

if (! class_exists(ZipArchive::class)) {
    echo 'This script requires zip PHP extension.' . PHP_EOL;

    exit(1);
}

function checkRequiredFiles(string $pluginRootDir): void
{
    if (! is_file(sprintf('%s/manifest.json', $pluginRootDir))) {
        echo sprintf('Manifest file not found in "%s".', $pluginRootDir) . PHP_EOL;

        exit(1);
    }

    // treat missing main.php only as a warning as it's not required for successful completion of this script
    if (! is_file(sprintf('%s/main.php', $pluginRootDir))) {
        echo sprintf('WARNING: Plugin does not have required main.php file in "%s".', $pluginRootDir) . PHP_EOL;
    }
}

function getPluginRootDir(?string $rootDir): string
{
    if ($rootDir === null) {
        $rootDir = realpath(__DIR__ . '/../../../..');

        echo sprintf('Plugin root dir not given, trying to find automatically: "%s"', $rootDir) . PHP_EOL;
    } else {
        if (! is_dir($rootDir)) {
            echo 'Given directory does not exist.' . PHP_EOL;

            exit(1);
        }

        $rootDir = realpath($rootDir);
    }

    return $rootDir;
}

function getPluginName(string $pluginRootDir): string
{
    $manifest = json_decode(file_get_contents($pluginRootDir . '/manifest.json'), true, 512, JSON_BIGINT_AS_STRING);
    $error = json_last_error();
    if ($error !== JSON_ERROR_NONE) {
        echo sprintf('Could not decode manifest: "%s"', $error) . PHP_EOL;

        exit(1);
    }

    $name = $manifest['information']['name'] ?? null;
    if ($name === null) {
        echo 'Could not get plugin\'s name from manifest.' . PHP_EOL;

        exit(1);
    }

    if (! preg_match('~^[a-z0-9_-]+$~', $name)) {
        echo 'Plugin\'s name contains invalid characters. Valid characters are: a-z, 0-9, _ (underscore) and - (hyphen).' . PHP_EOL;

        exit(1);
    }

    return $name;
}

$pluginRootDir = getPluginRootDir($argv[1] ?? null);
checkRequiredFiles($pluginRootDir);
$pluginName = getPluginName($pluginRootDir);
$zipName = sprintf('%s.zip', $pluginName);

// If the plugin's structure matches UBNT repository, create the zip next to the src directory.
// Otherwise create it in plugin's root directory.
if (file_exists(sprintf('%s/../README.md', $pluginRootDir)) && is_dir(sprintf('%s/../src', $pluginRootDir))) {
    $zipPath = sprintf('%s/../%s', $pluginRootDir, $zipName);
} else {
    $zipPath = sprintf('%s/%s', $pluginRootDir, $zipName);
}

// Delete old ZIP archive.
if (file_exists($zipPath)) {
    unlink($zipPath);
}

// Install composer dependencies.
shell_exec('composer install --classmap-authoritative --no-dev --no-interaction --quiet');

// Create the ZIP archive.
$zip = new ZipArchive();

if ($zip->open($zipPath, ZipArchive::CREATE) !== true) {
    echo 'Can\'t open zip file.' . PHP_EOL;

    exit(1);
}

$files = new CallbackFilterIterator(
    new \RecursiveIteratorIterator(
        new \RecursiveDirectoryIterator($pluginRootDir)
    ),
    function (SplFileInfo $fileInfo) {
        return $fileInfo->isFile();
    }
);

$ignoredFiles = [
    'ucrm.json',
    '.ucrm-plugin-running',
    '.ucrm-plugin-execution-requested',
    $zipName,
];

$ignoredDirectories = [
    '.git/',
    '.idea/',
];

/** @var SplFileInfo $fileInfo */
foreach ($files as $fileInfo) {
    $filename = substr(str_replace('\\', '/', $fileInfo->getPathname()), strlen($pluginRootDir));
    $filename = ltrim($filename, '/');

    if (in_array($filename, $ignoredFiles, true)) {
        echo sprintf('Skipping ignored file "%s".', $filename) . PHP_EOL;

        continue;
    }

    foreach ($ignoredDirectories as $ignoredDirectory) {
        if (strncmp($filename, $ignoredDirectory, strlen($ignoredDirectory)) === 0) {
            echo sprintf('Skipping ignored file "%s".', $filename) . PHP_EOL;

            continue 2;
        }
    }

    if (! $zip->addFile($fileInfo->getPathname(), $filename)) {
        echo sprintf('Unable to add file "%s".', $filename) . PHP_EOL;

        exit(1);
    }
}

$zip->close();

echo sprintf('Created plugin ZIP archive: "%s"', realpath($zipPath)) . PHP_EOL;
