<?php

declare(strict_types=1);

header("Content-Type: application/json; charset=utf-8");
header("Cache-Control: no-store");

$baseDir = __DIR__;
$manifestFile = $baseDir . "/manifest.json";

function updateServerRespond(int $status, array $payload): void
{
    http_response_code($status);
    echo json_encode(
        $payload,
        JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE,
    );
    exit;
}

function updateServerValidateVersion(string $version): bool
{
    return preg_match('/^v\d+\.\d+\.\d+$/', $version) === 1;
}

function updateServerNormalizePackageUrl(string $version): string
{
    $scheme = "http";
    if (
        (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off") ||
        (isset($_SERVER["SERVER_PORT"]) && (int) $_SERVER["SERVER_PORT"] === 443) ||
        strtolower((string) ($_SERVER["HTTP_X_FORWARDED_PROTO"] ?? "")) === "https"
    ) {
        $scheme = "https";
    }

    $host = $_SERVER["HTTP_HOST"] ?? "localhost";
    $scriptDir = rtrim(str_replace("\\", "/", dirname($_SERVER["SCRIPT_NAME"] ?? "")), "/");

    return $scheme .
        "://" .
        $host .
        ($scriptDir === "" ? "" : $scriptDir) .
        "/package.php?version=" .
        rawurlencode($version);
}

if (!is_file($manifestFile)) {
    updateServerRespond(500, ["error" => "Manifest file is missing."]);
}

$decoded = json_decode((string) file_get_contents($manifestFile), true);
if (!is_array($decoded)) {
    updateServerRespond(500, ["error" => "Manifest file is not valid JSON."]);
}

$latest = trim((string) ($decoded["latest"] ?? ""));
$releases = isset($decoded["releases"]) && is_array($decoded["releases"])
    ? $decoded["releases"]
    : [];

if ($latest === "" || !updateServerValidateVersion($latest)) {
    updateServerRespond(404, ["error" => "No valid latest release is configured."]);
}

if (!isset($releases[$latest]) || !is_array($releases[$latest])) {
    updateServerRespond(404, ["error" => "Latest release entry is missing."]);
}

$release = $releases[$latest];
$version = trim((string) ($release["version"] ?? $latest));
$package = trim((string) ($release["package"] ?? ""));
$sha256 = strtolower(trim((string) ($release["sha256"] ?? "")));
$publishedAt = trim((string) ($release["published_at"] ?? ""));
$size = isset($release["size"]) ? (int) $release["size"] : 0;

if ($version !== $latest || !updateServerValidateVersion($version)) {
    updateServerRespond(500, ["error" => "Latest release version is invalid."]);
}

if ($package === "" || str_contains($package, "\0") || str_starts_with($package, "/")) {
    updateServerRespond(500, ["error" => "Latest release package path is invalid."]);
}

if (!preg_match('/^[a-f0-9]{64}$/', $sha256)) {
    updateServerRespond(500, ["error" => "Latest release checksum is invalid."]);
}

$packagePath = realpath($baseDir . "/" . $package);
$packagesDir = realpath($baseDir . "/packages");
if (
    $packagePath === false ||
    $packagesDir === false ||
    !str_starts_with($packagePath, $packagesDir . DIRECTORY_SEPARATOR) ||
    !is_file($packagePath)
) {
    updateServerRespond(404, ["error" => "Latest release package is missing."]);
}

if ($size <= 0) {
    $size = filesize($packagePath) ?: 0;
}

updateServerRespond(200, [
    "latest" => $latest,
    "version" => $version,
    "package_url" => updateServerNormalizePackageUrl($version),
    "sha256" => $sha256,
    "size" => $size,
    "published_at" => $publishedAt,
]);
