<?php
declare(strict_types=1);

namespace PSLauncher\Admin;

/**
 * Registre des channels de distribution. Stocké dans manifest/channels.json
 * pour rester portable / pas dépendre de la DB pour cette config simple.
 *
 * Une entrée a 3 champs :
 *   - name        : identifiant ASCII utilisé en code partout (whitelist a-z0-9_-)
 *   - label       : libellé human-friendly affiché dans les UI admin
 *   - description : contexte libre pour l'admin (optionnel)
 *
 * Le channel "default" est implicite et toujours présent : il représente les
 * versions publiques (vues par toutes les licenses, peu importe leur tag). Les
 * versions sans tag explicite sont implicitement dans "default".
 *
 * Les licenses pointent vers UN channel — elles voient les versions taggées
 * avec ce channel ET celles taggées "default" (sémantique additive).
 */
final class Channels
{
    /** @return array{channels: array<int, array{name:string,label:string,description?:string}>} */
    public static function load(string $manifestDir): array
    {
        $path = $manifestDir . '/channels.json';
        $base = ['channels' => []];
        if (is_file($path)) {
            $raw  = file_get_contents($path);
            $json = json_decode((string)$raw, true);
            if (is_array($json) && isset($json['channels']) && is_array($json['channels'])) {
                $base['channels'] = $json['channels'];
            }
        }

        // Garantit que "default" est toujours présent en tête (immutable depuis la UI).
        $hasDefault = false;
        foreach ($base['channels'] as $c) {
            if (($c['name'] ?? '') === 'default') { $hasDefault = true; break; }
        }
        if (!$hasDefault) {
            array_unshift($base['channels'], [
                'name'        => 'default',
                'label'       => 'Public',
                'description' => 'Versions publiques visibles par tous les clients',
            ]);
        }

        return $base;
    }

    public static function save(string $manifestDir, array $registry): void
    {
        $path = $manifestDir . '/channels.json';
        if (!is_dir($manifestDir)) mkdir($manifestDir, 0755, true);
        file_put_contents(
            $path,
            json_encode($registry, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n"
        );
    }

    /**
     * Retourne true si <code>$name</code> est un identifiant de channel valide :
     * lowercase, chiffres, tirets et underscores, 1 à 64 caractères.
     */
    public static function isValidName(string $name): bool
    {
        return (bool)preg_match('/^[a-z0-9_-]{1,64}$/', $name);
    }

    /**
     * Normalise un nom saisi par l'admin : lowercase, espaces → tirets, retire
     * les chars hors whitelist, compresse les tirets multiples, trim.
     * Identique à ps_normalize_channel() dans versions.php — centralisé ici
     * pour les futurs ajouts.
     */
    public static function normalizeName(string $raw): string
    {
        $s = strtolower(trim($raw));
        $s = (string)preg_replace('/[\s\x{2010}-\x{2015}]+/u', '-', $s);
        $s = (string)preg_replace('/[^a-z0-9_-]/', '', $s);
        $s = (string)preg_replace('/-+/', '-', $s);
        $s = trim($s, '-_');
        return substr($s, 0, 64);
    }

    /**
     * @return list<string> Liste des noms de channel pour les dropdowns.
     */
    public static function listNames(string $manifestDir): array
    {
        $reg = self::load($manifestDir);
        return array_map(fn($c) => (string)($c['name'] ?? ''), $reg['channels']);
    }
}
