<?php
declare(strict_types=1);

namespace App\Services\Package;

use RuntimeException;
use ZipArchive;

final class PackageDescriptor
{
    /** @param array<string,mixed> $manifest */
    private function __construct(
        private readonly string $zipPath,
        private readonly array $manifest,
        private readonly ?int $packageId = null
    ) {
    }

    public static function fromZip(string $zipPath, ?int $packageId = null): self
    {
        if (!is_file($zipPath)) {
            throw new RuntimeException('Archive du package introuvable.');
        }
        $zip = new ZipArchive();
        if ($zip->open($zipPath) !== true) {
            throw new RuntimeException('Archive ZIP illisible.');
        }
        try {
            $raw = $zip->getFromName('manifest.json');
        } finally {
            $zip->close();
        }
        $manifest = is_string($raw) ? json_decode($raw, true) : null;
        if (!is_array($manifest)) {
            throw new RuntimeException('Manifeste du package invalide.');
        }
        foreach (['package', 'version', 'files'] as $required) {
            if (!array_key_exists($required, $manifest)) {
                throw new RuntimeException('Champ manifeste manquant : '.$required);
            }
        }
        return new self($zipPath, $manifest, $packageId && $packageId > 0 ? $packageId : null);
    }

    public function zipPath(): string { return $this->zipPath; }
    /** @return array<string,mixed> */
    public function manifest(): array { return $this->manifest; }
    public function packageId(): ?int { return $this->packageId; }
    public function name(): string { return trim((string)($this->manifest['package'] ?? '')); }
    public function version(): string { return trim((string)($this->manifest['version'] ?? '')); }
    public function publisher(): string { return trim((string)($this->manifest['publisher'] ?? '')); }
    public function trustLevel(): string { return strtolower(trim((string)($this->manifest['trust_level'] ?? ''))); }
    public function checksum(): string { return hash_file('sha256', $this->zipPath) ?: ''; }

    /** @return array<string,mixed> */
    public function packageRecord(): array
    {
        return [
            'id' => $this->packageId,
            'nom_package' => $this->name(),
            'version_package' => $this->version(),
            'version_cible' => $this->version(),
            'checksum_sha256' => $this->checksum(),
            'statut' => $this->packageId === null ? 'pre_import' : 'importe',
            'fichier_original' => basename($this->zipPath),
        ];
    }
}
