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

function removeDirectory(string $path): void
{
    if (!is_dir($path)) {
        throw new InvalidArgumentException("$path must be a directory");
    }

    $items = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST
    );

    foreach ($items as $item) {
        if ($item->isDir()) {
            rmdir($item->getRealPath());
        } else {
            unlink($item->getRealPath());
        }
    }

    rmdir($path);
}

$dataPath = __DIR__ . "/../data";
$context = stream_context_create([
    "http" => [
        "header" => "User-Agent: php-licensee"
    ]
]);

echo "Downloading choosealicense.com data\n";
$tmpFile = tempnam(sys_get_temp_dir(), "licensee-update-data");
$fp = fopen($tmpFile, "w");
$req = fopen("https://api.github.com/repos/github/choosealicense.com/tarball", "r", false, $context);
stream_copy_to_stream($req, $fp);
fclose($req);
fclose($fp);

removeDirectory($dataPath . "/choosealicense.com");
mkdir($dataPath . "/choosealicense.com");

echo "Extracting choosealicense.com data\n";
$bsdTar = str_contains(explode("\n", `tar --version`)[0], "bsdtar");
$tarOpt = $bsdTar ? "" : "--wildcards";
`tar zxf ${tmpFile} -C ${dataPath}/choosealicense.com ${tarOpt} --strip-components=1 */_data/* */_licenses/*`;
unlink($tmpFile);


$include = [];
foreach (glob($dataPath . "/choosealicense.com/_licenses/*.txt") as $file) {
    $content = yaml_parse_file($file);
    $include[] = "*/src/" . $content["spdx-id"] . ".xml";
}
$include[] = "*/equivalentwords.txt";
$include = implode(" ", $include);

echo "Downloading SPDX license list data\n";
$tmpFile = tempnam(sys_get_temp_dir(), "licensee-update-data");
$fp = fopen($tmpFile, "w");
$req = fopen("https://api.github.com/repos/spdx/license-list-XML/tarball", "r", false, $context);
stream_copy_to_stream($req, $fp);
fclose($req);
fclose($fp);

removeDirectory($dataPath . "/license-list-XML");
mkdir($dataPath . "/license-list-XML");

echo "Extracting SPDX license list data\n";
`tar zxf ${tmpFile} -C ${dataPath}/license-list-XML ${tarOpt} --strip-components=1 ${include}`;
unlink($tmpFile);

function toScreamingSnakeCase(string $string): string
{
    return strtoupper(preg_replace("/[^a-zA-Z0-9]+/", "_", $string));
}

function createRulesEnumFromData(array $data, string $filename): void
{
    $template = file_get_contents(__DIR__ . "/../data/templates/Rules.php.template");
    $cases = [];
    $descriptions = [];
    $labels = [];

    foreach ($data as $item) {
        $name = toScreamingSnakeCase($item["tag"]);
        $cases[] =          "    case $name = \"{$item["tag"]}\";";
        $descriptions[] =   "            self::$name => \"{$item["description"]}\",";
        $labels[] =         "            self::$name => \"{$item["label"]}\",";
    }

    $template = str_replace("###NAME###", $filename, $template);
    $template = str_replace("###CASES###", implode("\n", $cases), $template);
    $template = str_replace("###DESCRIPTIONS###", implode("\n", $descriptions), $template);
    $template = str_replace("###LABELS###", implode("\n", $labels), $template);

    file_put_contents(__DIR__ . "/../src/Generated/$filename.php", $template);
}

function createFieldEnumFromData(array $data): void
{
    $template = file_get_contents(__DIR__ . "/../data/templates/Field.php.template");
    $cases = [];
    $descriptions = [];

    foreach ($data as $item) {
        $name = toScreamingSnakeCase($item["name"]);
        $cases[] =          "    case $name = \"{$item["name"]}\";";
        $descriptions[] =   "            self::$name => \"{$item["description"]}\",";
    }

    $template = str_replace("###CASES###", implode("\n", $cases), $template);
    $template = str_replace("###DESCRIPTIONS###", implode("\n", $descriptions), $template);

    file_put_contents(__DIR__ . "/../src/Generated/Field.php", $template);
}

function createSpdxEnum(): void
{
    $template = file_get_contents(__DIR__ . "/../data/templates/Spdx.php.template");
    $cases = [];

    foreach (scandir(__DIR__ . "/../data/choosealicense.com/_licenses") as $file) {
        if ($file === "." || $file === ".." || !str_ends_with($file, ".txt")) {
            continue;
        }

        $license = yaml_parse_file(__DIR__ . "/../data/choosealicense.com/_licenses/$file");
        $id = $license["spdx-id"];

        $name = toScreamingSnakeCase($id);
        if (str_starts_with($name, "0")) {
            $name = "ZERO_" . substr($name, 1);
        }
        $cases[] =          "    case $name = \"{$id}\";";
    }

    $template = str_replace("###CASES###", implode("\n", $cases), $template);

    file_put_contents(__DIR__ . "/../src/Generated/Spdx.php", $template);
}

function createConstants(): void
{
    $template = file_get_contents(__DIR__ . "/../data/templates/Constants.php.template");

    $equivalentWords = [];
    $data = file_get_contents(__DIR__ . "/../data/license-list-XML/equivalentwords.txt");
    foreach (explode("\n", $data) as $line) {
        $line = trim($line);
        if ($line === "") {
            continue;
        }

        [$to, $from] = explode(",", $line, 2);

        foreach ($equivalentWords as $i => $words) {
            if (in_array($to, $words) || in_array($from, $words)) {
                $equivalentWords[$i][] = $to;
                $equivalentWords[$i][] = $from;
                $equivalentWords[$i] = array_unique($equivalentWords[$i]);
                continue 2;
            }
        }

        $equivalentWords[] = [$to, $from];
    }

    $strings = [];
    foreach ($equivalentWords as $words) {
        $strings[] = "        \"" . $words[0] . "\" => [" . implode(", ", array_map(json_encode(...), array_slice($words, 1))) . "],";
    }

    $template = str_replace("###EQUIVALENT_WORDS###", implode("\n", $strings), $template);
    file_put_contents(__DIR__ . "/../src/Generated/Constants.php", $template);
}

echo "Generating rules enums\n";
$rules = yaml_parse_file(__DIR__ . "/../data/choosealicense.com/_data/rules.yml");
createRulesEnumFromData($rules["permissions"], "Permission");
createRulesEnumFromData($rules["conditions"], "Condition");
createRulesEnumFromData($rules["limitations"], "Limitation");

echo "Generating field enum\n";
$fields = yaml_parse_file(__DIR__ . "/../data/choosealicense.com/_data/fields.yml");
createFieldEnumFromData($fields);

echo "Generating SPDX enum\n";
createSpdxEnum();

echo "Generating constants\n";
createConstants();
