<?php

namespace App\Service;

use Symfony\Component\DependencyInjection\Attribute\Autowire;

/**
 * Suivi de progression des imports de la page Paramètres (référentiel des
 * concessions, photo du stock) : l'action d'import écrit son avancement dans un
 * fichier JSON sous var/import_progress/ (NFS partagé entre les nœuds OVH), que
 * le navigateur interroge pendant le traitement. Best-effort : aucune erreur de
 * suivi ne doit faire échouer l'import lui-même.
 */
final class ImportProgressTracker
{
    /** Durée de vie des fichiers de suivi (nettoyés en fin d'import). */
    private const TTL_SECONDS = 3600;

    private readonly string $dir;

    public function __construct(
        #[Autowire('%kernel.project_dir%')] string $projectDir,
    ) {
        $this->dir = $projectDir . '/var/import_progress';
    }

    /** Le jeton est fourni par le navigateur : format strictement contraint. */
    public static function isValidToken(?string $token): bool
    {
        return null !== $token && 1 === preg_match('/^[A-Za-z0-9-]{8,64}$/', $token);
    }

    public function update(string $token, string $label, ?int $current = null, ?int $total = null, bool $done = false, bool $error = false): void
    {
        if (!self::isValidToken($token)) {
            return;
        }
        if (!is_dir($this->dir) && !@mkdir($this->dir, 0775, true) && !is_dir($this->dir)) {
            return;
        }
        $payload = json_encode([
            'label' => $label,
            'current' => $current,
            'total' => $total,
            'done' => $done,
            'error' => $error,
        ]);
        if (false === $payload) {
            return;
        }
        // Écriture atomique (fichier temporaire puis rename) pour que le
        // navigateur ne lise jamais un JSON tronqué.
        $tmp = $this->dir . '/' . uniqid($token . '_', true) . '.tmp';
        if (false !== @file_put_contents($tmp, $payload)) {
            @rename($tmp, $this->path($token));
        }
        if ($done) {
            $this->prune();
        }
    }

    /**
     * @return array{label: string, current: ?int, total: ?int, done: bool, error: bool}|null
     */
    public function read(string $token): ?array
    {
        if (!self::isValidToken($token)) {
            return null;
        }
        $raw = @file_get_contents($this->path($token));
        if (false === $raw) {
            return null;
        }
        $data = json_decode($raw, true);

        return \is_array($data) ? $data : null;
    }

    private function path(string $token): string
    {
        return $this->dir . '/' . $token . '.json';
    }

    /** Supprime les fichiers de suivi expirés (le dossier reste minuscule). */
    private function prune(): void
    {
        $limit = time() - self::TTL_SECONDS;
        foreach (glob($this->dir . '/*') ?: [] as $file) {
            $mtime = @filemtime($file);
            if (false !== $mtime && $mtime < $limit) {
                @unlink($file);
            }
        }
    }
}
