<?php
declare(strict_types=1);

/**
 * Formation Laravel — Module 01 : PHP 8.x Moderne
 * Exercices pratiques — 6 TODO à compléter
 *
 * Exécuter : php exercices.php
 */

echo "=== Exercices PHP 8.x Moderne ===\n\n";

/* ─────────────────────────────────────────────────────────
   EXERCICE 1 — readonly + constructor promotion
   Créer une classe Produit avec :
   - readonly properties : id, nom, prix, stock
   - constructor promotion
   - méthode estDisponible(): bool
   - méthode appliquerRemise(float $pct): static (retourne nouveau Produit)
   ───────────────────────────────────────────────────────── */
echo "--- Exercice 1 : readonly + constructor promotion ---\n";

// TODO : définir la classe Produit ici
// class Produit { ... }

// Tests attendus :
// $p = new Produit(1, 'Clavier', 49.99, 10);
// echo $p->nom;           // 'Clavier'
// echo $p->estDisponible() ? 'Dispo' : 'Rupture'; // Dispo
// $soldes = $p->appliquerRemise(20); // prix = 39.99, meme stock
// $p->prix = 50; // Error: readonly property


/* ─────────────────────────────────────────────────────────
   EXERCICE 2 — Enum backed string
   Créer enum Statut: string avec cases :
   - Todo = 'todo', InProgress = 'in_progress', Done = 'done'
   - méthode label(): string (FR)
   - méthode isComplete(): bool
   - méthode nextStatus(): static|null (Done → null)
   ───────────────────────────────────────────────────────── */
echo "\n--- Exercice 2 : Enum Statut ---\n";

// TODO : définir l'enum Statut ici
// enum Statut: string { ... }

// Tests attendus :
// $s = Statut::Todo;
// echo $s->label();        // 'À faire'
// echo $s->value;          // 'todo'
// $next = $s->nextStatus();
// echo $next->label();     // 'En cours'


/* ─────────────────────────────────────────────────────────
   EXERCICE 3 — match() pour calculer la TVA
   Créer une fonction calculerTVA(string $categorie, float $prix): float
   Taux par catégorie :
   - 'alimentaire', 'medicament' → 5.5%
   - 'livre', 'presse' → 2.1%
   - 'restauration' → 10%
   - 'standard' et autres → 20%
   ───────────────────────────────────────────────────────── */
echo "\n--- Exercice 3 : match() TVA ---\n";

// TODO : implémenter calculerTVA()
// function calculerTVA(string $categorie, float $prix): float { ... }

// Tests attendus :
// echo calculerTVA('alimentaire', 100); // 5.5
// echo calculerTVA('livre', 100);       // 2.1
// echo calculerTVA('standard', 100);    // 20.0
// echo calculerTVA('inconnu', 100);     // 20.0 (fallback)


/* ─────────────────────────────────────────────────────────
   EXERCICE 4 — Trait Timestampable
   Créer un trait Timestampable avec :
   - propriétés : createdAt, updatedAt (DateTimeImmutable|null)
   - méthode initTimestamps(): void (init createdAt si null)
   - méthode touch(): void (met à jour updatedAt)
   - méthode getAge(): string (ex: "créé il y a 3 jours")
   ───────────────────────────────────────────────────────── */
echo "\n--- Exercice 4 : Trait Timestampable ---\n";

// TODO : définir le trait Timestampable ici
// trait Timestampable { ... }

// Classe de test utilisant le trait
// class Article {
//     use Timestampable;
//     public function __construct(public readonly string $titre) {
//         $this->initTimestamps();
//     }
// }

// Tests attendus :
// $a = new Article('Mon article');
// echo $a->getCreatedAt()->format('Y-m-d'); // date d'aujourd'hui
// sleep(1); $a->touch();
// var_dump($a->getUpdatedAt() !== $a->getCreatedAt()); // true


/* ─────────────────────────────────────────────────────────
   EXERCICE 5 — Interface Serializable + implémentation JSON
   Créer :
   - interface JsonSerializable avec toJson(): string et static fromJson(string): static
   - classe Config implements JsonSerializable
   - Config stocke des paires clé/valeur
   - sérialisé en JSON : {"key":"value",...}
   ───────────────────────────────────────────────────────── */
echo "\n--- Exercice 5 : Interface + JSON ---\n";

// TODO : définir l'interface et la classe
// interface JsonSerializable { ... }
// class Config implements JsonSerializable { ... }

// Tests attendus :
// $c = new Config(['debug' => true, 'env' => 'production', 'version' => '1.0']);
// $json = $c->toJson();
// echo $json; // {"debug":true,"env":"production","version":"1.0"}
// $c2 = Config::fromJson($json);
// var_dump($c2->get('env')); // 'production'


/* ─────────────────────────────────────────────────────────
   EXERCICE 6 — Fiber : générateur de suite
   Créer une fonction makePrimeGenerator(): Fiber qui :
   - génère les nombres premiers à la demande via Fiber::suspend()
   - s'arrête quand resume(false) est appelé
   ───────────────────────────────────────────────────────── */
echo "\n--- Exercice 6 : Fiber générateur de premiers ---\n";

// TODO : implémenter makePrimeGenerator()
// function makePrimeGenerator(): Fiber { ... }
// function isPrime(int $n): bool { ... }

// Tests attendus :
// $gen = makePrimeGenerator();
// $gen->start();
// for ($i = 0; $i < 10; $i++) {
//     echo $gen->resume(true) . ' '; // 2 3 5 7 11 13 17 19 23 29
// }
// $gen->resume(false); // arrêt propre


echo "\n\n=== Termine les exercices, puis compare avec solutions.php ===\n";
