<?php
use PHPUnit\Framework\TestCase;
require_once __DIR__ . '/../src/db.php';
require_once __DIR__ . '/../src/filieres.php';
require_once __DIR__ . '/../src/candidatures.php';
require_once __DIR__ . '/../src/export.php';

final class ExportTest extends TestCase {
    public function testLignesExportDepuisBdd(): void {
        $pdo = db_test();
        require_once __DIR__ . '/../src/filieres.php'; require_once __DIR__ . '/../src/candidatures.php';
        enregistrer_candidature($pdo, ['nom'=>'Koné','prenoms'=>'Awa','date_naissance'=>'2007-03-12',
            'lieu_naissance'=>'Korhogo','sexe'=>'F','nationalite'=>'CI','telephone'=>'0102030405','ville'=>'Korhogo',
            'tuteur_nom'=>'K. Issa','tuteur_telephone'=>'0506070809','bac_serie'=>'D','bac_annee'=>'2026',
            'etablissement_origine'=>'Lycée','filiere1'=>'INFO'], 2026);
        $lignes = lignes_export($pdo, []);
        $this->assertSame('Numéro', $lignes[0][0]);
        $this->assertSame('ISIT-2026-0001', $lignes[1][0]);
        $this->assertContains('Koné', $lignes[1]);
    }

    public function testFiltreStatut(): void {
        $pdo = db_test();
        $this->assertCount(1, lignes_export($pdo, ['statut' => 'accepte'])); // en-têtes seules
    }

    // ---- Ajouts même round TDD (revue Task 11) : q et filiere doivent se comporter
    // exactement comme filtrer_candidatures() (liste admin), puisque le bouton Exporter
    // Excel transporte les mêmes filtres GET que la liste. ----

    private function candidatureKone(): array {
        return ['nom'=>'Koné','prenoms'=>'Awa','date_naissance'=>'2007-03-12',
            'lieu_naissance'=>'Korhogo','sexe'=>'F','nationalite'=>'CI','telephone'=>'0102030405','ville'=>'Korhogo',
            'tuteur_nom'=>'K. Issa','tuteur_telephone'=>'0506070809','bac_serie'=>'D','bac_annee'=>'2026',
            'etablissement_origine'=>'Lycée','filiere1'=>'INFO'];
    }

    public function testFiltreQPourcentEstLitteral(): void {
        $pdo = db_test();
        enregistrer_candidature($pdo, $this->candidatureKone(), 2026);
        // Même sémantique que filtrer_candidatures() : « % » est échappé (LIKE littéral),
        // ce n'est pas un joker qui matcherait tout.
        $this->assertCount(1, lignes_export($pdo, ['q' => '%'])); // en-têtes seules, 0 ligne ne matche
    }

    public function testFiltreQPartielRetourneLaLigne(): void {
        $pdo = db_test();
        enregistrer_candidature($pdo, $this->candidatureKone(), 2026);
        $lignes = lignes_export($pdo, ['q' => 'Kon']);
        $this->assertCount(2, $lignes); // en-têtes + 1 ligne
        $this->assertContains('Koné', $lignes[1]);
    }

    public function testFiltreFiliere(): void {
        $pdo = db_test();
        enregistrer_candidature($pdo, $this->candidatureKone(), 2026);
        $this->assertCount(2, lignes_export($pdo, ['filiere' => 'INFO'])); // en-têtes + 1 ligne
        $this->assertCount(1, lignes_export($pdo, ['filiere' => 'GES'])); // en-têtes seules, aucune correspondance
    }

    // ---- Revue Task 11 : neutralisation du mini-langage de balisage de SimpleXLSXGen.
    // La lib interprète toute cellule contenant '<' : <f>…</f> devient une formule
    // Excel vivante, <a href> un hyperlien au texte trompeur, <!-- --> un commentaire,
    // et tout autre balisage est passé à strip_tags (perte de données). Le préfixe NUL
    // "\0" (« RAW value » documenté par la lib) force la chaîne brute. ----

    public function testBalisageNeutraliseParPrefixeNul(): void {
        $pdo = db_test();
        $d = $this->candidatureKone();
        $d['nom'] = '<f>2+2</f>';                               // deviendrait une formule vivante
        $d['etablissement_origine'] = 'Collège <Les Palmiers>'; // serait tronqué par strip_tags
        enregistrer_candidature($pdo, $d, 2026);
        $lignes = lignes_export($pdo, []);
        $this->assertSame("\0<f>2+2</f>", $lignes[1][1]);              // nom : chaîne brute préfixée NUL
        $this->assertSame("\0Collège <Les Palmiers>", $lignes[1][10]); // établissement : idem
        $this->assertSame('Awa', $lignes[1][2]);                       // sans '<' : pas de préfixe
    }

    public function testTelephonesToujoursEnChaineBrute(): void {
        $pdo = db_test();
        $d = $this->candidatureKone();
        $d['telephone'] = '+2250102030405'; // sans chaîne brute : cellule numérique, « + » de tête perdu
        enregistrer_candidature($pdo, $d, 2026);
        $lignes = lignes_export($pdo, []);
        $this->assertSame("\0+2250102030405", $lignes[1][5]);   // telephone
        $this->assertSame("\0" . '0506070809', $lignes[1][14]); // tuteur_telephone : brut même sans « + »
    }

    public function testXlsxGenereSansFormuleNiLienNiPerte(): void {
        $pdo = db_test();
        $d = $this->candidatureKone(); // sans email : aucun hyperlien mailto légitime attendu
        $d['nom'] = '<f>2+2</f>';
        $d['ville'] = '<a href="https://exemple.test">Cliquer ici</a>';
        $d['etablissement_origine'] = 'Collège <Les Palmiers>';
        enregistrer_candidature($pdo, $d, 2026);
        require_once __DIR__ . '/../vendor-lib/SimpleXLSXGen.php';
        $tmp = tempnam(sys_get_temp_dir(), 'isit_export_test_');
        \Shuchkin\SimpleXLSXGen::fromArray(lignes_export($pdo, []))->saveAs($tmp);
        $zip = new ZipArchive();
        $this->assertTrue($zip->open($tmp) === true);
        $sheet = (string)$zip->getFromName('xl/worksheets/sheet1.xml');
        $rels = (string)$zip->getFromName('xl/worksheets/_rels/sheet1.xml.rels');
        $shared = (string)$zip->getFromName('xl/sharedStrings.xml');
        $zip->close();
        unlink($tmp);
        $this->assertStringNotContainsString('<f>', $sheet);       // aucune cellule formule
        $this->assertStringNotContainsString('hyperlink', $sheet); // aucun lien dans la feuille
        $this->assertStringNotContainsString('hyperlink', $rels);  // ni dans ses relations
        // Tout est exporté littéralement (échappé XML), rien n'est interprété ni perdu :
        $this->assertStringContainsString('&lt;f&gt;2+2&lt;/f&gt;', $shared);
        $this->assertStringContainsString('Collège &lt;Les Palmiers&gt;', $shared);
    }
}
