# Script d'Audit Firewall - Network Reputation Service
# Auteur: Hubert Cornet
# Date: 03/09/2025
# Version: 1.2

Clear-Host

# Configuration globale
$ErrorActionPreference = "Continue"
$WarningPreference     = "SilentlyContinue"

# Couleurs pour les grades
$GradeColors = @{
    'A+' = '#28a745'
    'A'  = '#52b83a'
    'B+' = '#7ac92e'
    'B'  = '#a3da23'
    'C+' = '#cceb17'
    'C'  = '#f5f90c'
    'D+' = '#f7d808'
    'D'  = '#f9b604'
    'E+' = '#fb9500'
    'E'  = '#fd7300'
    'F+' = '#ff5100'
    'F'  = '#dc3545'
}

### Functions ###

## Function Write-ColorOutput : pour afficher du texte en couleur
Function Write-ColorOutput {
    Param(
        [string]$Text,
        [string]$Color = "White"
    )

    Try{
        Write-Host $Text -ForegroundColor $Color
    }
    Catch {
        Write-Host $Text
    }
}

## Function Prerequisites : vérifie les prérequis
Function Prerequisites {
    Write-ColorOutput "`n === Vérification des prérequis ===" "Cyan"
    
    # Vérification du fichier JSON
    $JsonFile = Join-Path $PSScriptRoot "file-nrs.json"

    If(-not (Test-Path $JsonFile)) {
        Write-ColorOutput "ERREUR: Le fichier 'file-nrs.json' n'existe pas!" "Red"
        Write-ColorOutput "Veuillez télécharger ou créer le fichier depuis:" "Yellow"
        Write-ColorOutput "https://gitea.tips-of-mine.com/Tips-Of-Mine/Powershell/src/branch/main/cybersecurity/Network%20Reputation%20Service/file-nrs.json" "Blue"
        Write-ColorOutput "Le fichier doit être placé dans le même dossier que ce script." "Yellow"

        Return $false
    }

    Write-ColorOutput "✓ Fichier 'file-nrs.json' trouvé" "Green"
    
    # Vérification/Installation des modules requis
    $RequiredModules = @('PSWriteHTML', 'PSWriteColor')

    Foreach($Module in $RequiredModules) {
        If(-not (Get-Module -ListAvailable -Name $Module)) {
            Write-ColorOutput "Installation du module $Module..." "Yellow"

            Try{
                Install-Module -Name $Module -Force -Scope CurrentUser -AllowClobber

                Write-ColorOutput "✓ Module $Module installé" "Green"
            }
            Catch {
                Write-ColorOutput "ERREUR: Impossible d'installer le module $Module : $($_.Exception.Message)" "Red"

                Return $false
            }
        }
        Else {
            Write-ColorOutput "✓ Module $Module disponible" "Green"
        }

        Import-Module $Module -Force
    }
    
    Return $True
}

## Function Check-Categories : pour tester les catégories et URLs
Function Check-Categories {
    Param(
        [array]$Categories,
        [string]$ProxyUrl = "",
        [System.Management.Automation.PSCredential]$ProxyCredential = $null,
        [int]$TimeoutSeconds = 10
    )
    
    $AllResults    = @()
    $CategoryCount = 0

    $BlockKeywors = @("site bloqué", "access denied", "filtrage web", "Access Denied", "Site Blocked") # Définir les mots-clés des page des blocage
        
    Foreach($Category in $Categories.Categorie) {
        $CategoryCount++

        Show-ProgressBar -Id 1 -Current $CategoryCount -Total $Categories.Categorie.Count -Activity "Test des catégories" -Status "Catégorie: $($category.Categorie.nom)"
        
        Write-ColorOutput "`n === Test de la catégorie: $($Category.nom) ===" "Cyan"
        #Write-ColorOutput "`nDescription: $($Category.description)" "Gray"
        
        $CategoryResults = @()
        $UrlCount        = 0
        
        Foreach($UrlObj in $Category.urls) {
            $UrlCount++
            
            Show-ProgressBar -Id 2 -Current $UrlCount -Total $Category.urls.Count -Activity "Test des URLs de '$($Category.nom)'" -Status $UrlObj.url
            
            Write-ColorOutput "Test de: $($UrlObj.url)" "Yellow"
            
            #$Result = Get-UrlStatus -Url $UrlObj.url -ProxyUrl $ProxyUrl -ProxyCredential $ProxyCredential -TimeoutSeconds $TimeoutSeconds -BlockPageKeywords $BlockPageKeywords

            $Result = Get-UrlStatus $UrlObj.url $UrlObj.expected_action $BlockPageKeywords

            $TestResult = [PSCustomObject]@{
                Category       = $category.nom
                CategoryId     = $category.id
                Url            = $urlObj.url
                Reputation     = $urlObj.reputation
                ExpectedAction = $urlObj.expected_action
                Status         = $result.ActualResult
                StatusCode     = $result.StatusCode
                ResponseTime   = $result.ResponseTime
                Error          = $result.Details
                Score          = $result.Score
                IsCorrect      = (($TestResult.Status -eq "Bloqué" -and $UrlObj.expected_action -eq "block") -or ($TestResult.Status -eq "Autorisé" -and $UrlObj.expected_action -eq "allow"))
            }
          
            $StatusColor = If($TestResult.IsCorrect) { "Green" } Else { "Red" }
            Write-ColorOutput "  → Résultat: $($TestResult.Status) | Attendu: $($TestResult.ExpectedAction) | Correct: $($TestResult.IsCorrect)" $statusColor

            $CategoryResults += $TestResult
            $AllResults      += $TestResult
        }
        
        $CategoryScore = Calculate-CategoryScore -Results $CategoryResults
        $CategoryGrade = Convert-ScoreToGrade -Score $CategoryScore
        
        Write-ColorOutput "Score de la catégorie '$($Category.nom)': $CategoryScore% (Note: $CategoryGrade)" "Magenta"
    }
    
    Write-Progress -Id 1 -Activity "Test des catégories" -Completed
    Write-Progress -Id 2 -Activity "Test des URLs" -Completed
    
    return $AllResults
}

## Function Show-ProgressBar : affiche une barre de progression
Function Show-ProgressBar {
    Param(
        [int]$Current,
        [int]$Total,
        [int]$Id,
        [string]$Activity,
        [string]$Status = ""
    )
    
    $Percent = [math]::Round(($Current / $Total) * 100, 1)

    Write-Progress -Id $Id -Activity $Activity -Status "$Status ($Current/$Total)" -PercentComplete $Percent
}

## FunctionCalculate-CategoryScore : calcule le score d'une catégorie
Function Calculate-CategoryScore {
    Param(
        [array]$Results
    )
    
    $TotalUrls = $Results.Count
    $CorrectResults = 0
    
    Foreach($Result in $Results) {
        $IsBlocked = $Result.Status -eq "Bloqué"
        $ShouldBeBlocked = $result.ExpectedAction -eq "block"
        
        If(($IsBlocked -and $ShouldBeBlocked) -or (-not $IsBlocked -and -not $ShouldBeBlocked)) {
            $CorrectResults++
        }
    }
    
    If($TotalUrls -eq 0) {
        Return 0
    }

    Return [math]::Round(($CorrectResults / $TotalUrls) * 100, 2)
}

## Function Convert-ScoreToGrade : convertit un score en une note
Function Convert-ScoreToGrade {
    Param([double]$Score)
    
    switch ($Score) {
        {$_ -ge 95} { return 'A+' }
        {$_ -ge 90} { return 'A' }
        {$_ -ge 85} { return 'B+' }
        {$_ -ge 80} { return 'B' }
        {$_ -ge 75} { return 'C+' }
        {$_ -ge 70} { return 'C' }
        {$_ -ge 65} { return 'D+' }
        {$_ -ge 60} { return 'D' }
        {$_ -ge 55} { return 'E+' }
        {$_ -ge 50} { return 'E' }
        {$_ -ge 45} { return 'F+' }
        default { return 'F' }
    }
}

## Function Get-UrlStatus : teste une URL et détermine si elle est bloquée ou autorisée
Function Get-UrlStatus {
    Param(
        [string]$Url,
        [string]$ExpectedAction,                  # 'allow' ou 'block'
        [string[]]$BlockPageKeywords,             # Exemple: @("Access Denied", "Site Blocked")
        [string]$ProxyAddress  = $null,
        [string]$ProxyUseAuthentication = $null,
        [int]$Timeout = 10
    )

    $Result = [PSCustomObject]@{
        Url          = $Url
        Expected     = $ExpectedAction
        ActualResult = "Indéterminé"   # Ce qui s'est réellement passé (Bloqué/Autorisé)
        TestStatus   = "Échec" # Le statut du test (Conforme/Non Conforme)
        Score        = $Null
        StatusCode   = ""
        Details      = ""
        ResponseTime = ""
    }

    # Préparation des paramètres pour Invoke-WebRequest (Splatting)
    $IWRParams = @{
        Uri             = $Url
        UseBasicParsing = $True
        TimeoutSec      = $Timeout
        ErrorAction     = 'Stop'
    }

    $Response = $Null

    # Ajout des paramètres du proxy s'ils sont fournis
    If(-not [string]::IsNullOrEmpty($ProxyAddress)) {
        $IWRParams.Add('Proxy', $ProxyAddress)

        If($ProxyUseAuthentication) {
            # Demande les identifiants de manière sécurisée et les ajoute à la commande
            $Creds = Get-Credential -Message "Veuillez saisir les identifiants pour le proxy $ProxyAddress"
            $IWRParams.Add('ProxyCredential', $Creds)
        }
    }

    # -- Exécution du test --
    Try{
        # Exécution de la requête en utilisant les paramètres définis dans la hashtable
        $Response = Invoke-WebRequest @IWRParams

        # On vérifie si la réponse contient des mots-clés de la page de blocage
        $KeywordFound = $False

        Foreach($Keyword in $BlockPageKeywords) {
            If($Response.Content -match $Keyword) {
                $KeywordFound = $True

                break
            }
        }

        If($KeywordFound) {
            $Result.ActualResult  = "Bloqué"
            $Result.Details = "Page de blocage détectée."
            $Result.StatusCode   = $Response.StatusCode
        }
        Else {
            $Result.ActualResult = "Autorisé"
            $Result.Details      = "Le site a été atteint sans blocage."
            $Result.StatusCode   = $Response.StatusCode
        }

    }
    Catch [System.Net.WebException] {
        If($_.Exception.Status -eq 'Timeout') {
            $Result.ActualResult = "Bloqué (Timeout)"

            $Result.Details      = "La requête a expiré, indiquant un blocage probable par le pare-feu ou le proxy."
            $Result.StatusCode   = $Response.StatusCode
            $Result.ResponseTime = "$Timeout"
        }
        Else {
            # On considère les autres erreurs réseau comme un blocage aussi
            $Result.ActualResult = "Erreur de Connexion"
            $Result.Details      = "Impossible de joindre le serveur : $($_.Exception.Status)"
            $Result.StatusCode   = $Response.StatusCode
        }
    }
    Catch {
        $Result.ActualResult = "Erreur Script"
        $Result.Details      = "Erreur inattendue: $($_.Exception.Message)"

        # Un test en erreur ne doit pas donner de point
        return $result
    }

    # Le test est réussi si l'action attendue correspond au résultat réel.
    If(($Result.Expected -eq 'block' -and $Result.ActualResult -eq 'Bloqué') -or ($Result.Expected -eq 'allow' -and $Result.ActualResult -eq 'Autorisé')) {
        $Result.TestStatus = "Conforme"
        $Result.Score      = 1 # Le test est un succès !
        $Result.Details    += " (Résultat conforme à l'attendu)"
    }
    Else {
        $Result.TestStatus   = "Non Conforme"
        $Result.Score        = 0 # Le test est un échec !
        $Result.Details      += " (Résultat NON CONFORME; Attendu: $($Result.Expected); Obtenu: $($Result.ActualResult))"
    }

    Return $Result
}

## Function Generate-HtmlReport : génère le rapport HTML
Function Generate-HtmlReport {
    Param(
        [array]$Results,
        [string]$OutputPath
    )
    
    Write-ColorOutput "Génération du rapport HTML..." "Yellow"
    
    # Calcul des scores
    $Categories = $Results | Group-Object Category
    $CategoryScores = @()
    
    Foreach($Cat in $Categories) {
        $Score = Calculate-CategoryScore -Results $Cat.Group
        $Grade = Convert-ScoreToGrade -Score $Score
        
        $CategoryScores += [PSCustomObject]@{
            Category       = $Cat.Name
            Score          = $Score
            Grade          = $Grade
            Color          = $GradeColors[$grade]
            TotalUrls      = $Cat.Group.Count
            CorrectResults = ($Cat.Group | Where-Object IsCorrect).Count
            Results        = $Cat.Group
        }
    }
    
    # Score global
    $GlobalScore = Calculate-CategoryScore -Results $Results
    $GlobalGrade = Convert-ScoreToGrade -Score $GlobalScore
    $GlobalColor = $GradeColors[$GlobalGrade]
    
    # Génération du HTML
    $HtmlContent = @"
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Audit Firewall - Network Reputation Service</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f5f5f5; color: #333; line-height: 1.6; }
        .container { max-width: 1200px; margin: 0 auto; padding: 20px; }
        h1 { text-align: center; color: #2c3e50; margin-bottom: 10px; font-size: 2.5em; }
        .subtitle { text-align: center; color: #666; margin-bottom: 30px; font-size: 1.1em; }
        .section { background: white; margin: 20px 0; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        .section h2 { color: #2c3e50; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 2px solid #3498db; }
        
        /* Score global */
        .global-score { display: flex; align-items: center; justify-content: center; margin: 30px 0; }
        .score-box { background-color: $globalColor; color: white; width: 150px; height: 150px; border-radius: 15px; display: flex; flex-direction: column; align-items: center; justify-content: center; box-shadow: 0 4px 15px rgba(0,0,0,0.2); margin-right: 40px; }
        .score-grade { font-size: 3em; font-weight: bold; }
        .score-percent { font-size: 1.5em; margin-top: 5px; }
        .score-label { font-size: 1em; margin-top: 5px; opacity: 0.9; }
        .stats { text-align: left; }
        .stats div { margin: 8px 0; font-size: 1.2em; }
        
        /* Tableau des scores */
        table { width: 100%; border-collapse: collapse; margin: 20px 0; }
        th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
        th { background-color: #3498db; color: white; font-weight: bold; }
        tr:nth-child(even) { background-color: #f9f9f9; }
        tr:hover { background-color: #e8f4fd; }
        .grade-cell { font-weight: bold; color: white; text-align: center; border-radius: 5px; }
        
        /* Catégories en grille */
        .categories-grid { display: flex; flex-wrap: wrap; gap: 20px; margin: 20px 0; }
        .category-item { flex: 1; min-width: 280px; max-width: calc(25% - 15px); background: white; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); overflow: hidden; }
        .category-header { padding: 15px; cursor: pointer; transition: background-color 0.3s; }
        .category-header:hover { background-color: #f8f9fa; }
        .category-title { font-size: 1.2em; font-weight: bold; margin-bottom: 8px; color: #2c3e50; }
        .category-score { display: inline-block; padding: 5px 15px; border-radius: 20px; color: white; font-weight: bold; font-size: 0.9em; }
        .category-content { display: none; padding: 0 15px 15px; }
        .category-content.active { display: block; animation: slideDown 0.3s ease; }
        
        /* Animations */
        @keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
        
        /* Tables détaillées */
        .detail-table { font-size: 0.9em; }
        .detail-table th { font-size: 0.8em; }
        .correct { background-color: #d4edda !important; color: #155724; }
        .incorrect { background-color: #f8d7da !important; color: #721c24; }
        
        /* Barème */
        .grading-scale { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 10px; }
        .grade-item { display: flex; align-items: center; padding: 10px; border-radius: 8px; background-color: #f8f9fa; }
        .grade-badge { width: 40px; height: 40px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: bold; color: white; margin-right: 15px; }
        
        /* Responsive */
        @media (max-width: 768px) {
            .global-score { flex-direction: column; }
            .score-box { margin-right: 0; margin-bottom: 20px; }
            .category-item { max-width: 100%; }
        }
        
        /* Bouton toggle */
        .toggle-btn { float: right; font-size: 1.2em; transition: transform 0.3s; }
        .toggle-btn.active { transform: rotate(180deg); }
    </style>
</head>
<body>
    <div class="container">
        <h1>🛡️ Audit Firewall - Network Reputation Service</h1>
        <p class="subtitle">Rapport généré le $(Get-Date -Format 'dd/MM/yyyy à HH:mm')</p>
        
        <!-- Résumé Exécutif -->
        <div class="section">
            <h2>📊 Résumé Exécutif</h2>
            <div class="global-score">
                <div class="score-box">
                    <div class="score-grade">$globalGrade</div>
                    <div class="score-percent">$globalScore%</div>
                    <div class="score-label">Score Global</div>
                </div>
                <div class="stats">
                    <div><strong>📋 Total des URLs testées :</strong> $($Results.Count)</div>
                    <div><strong>✅ URLs correctement filtrées :</strong> $(($Results | Where-Object IsCorrect).Count)</div>
                    <div><strong>🎯 Taux de réussite :</strong> $([math]::Round((($Results | Where-Object IsCorrect).Count / $Results.Count) * 100, 2))%</div>
                    <div><strong>📅 Date du test :</strong> $(Get-Date -Format 'dd/MM/yyyy HH:mm')</div>
                </div>
            </div>
        </div>
        
        <!-- Scores par Catégorie -->
        <div class="section">
            <h2>📈 Scores par Catégorie</h2>
            <table>
                <thead>
                    <tr>
                        <th>Catégorie</th>
                        <th>Score (%)</th>
                        <th>Note</th>
                        <th>URLs Totales</th>
                        <th>Résultats Corrects</th>
                    </tr>
                </thead>
                <tbody>
"@

    # Ajout des lignes du tableau
    Foreach($CatScore in $CategoryScores) {
        $HtmlContent += @"
                    <tr>
                        <td><strong>$($catScore.Category)</strong></td>
                        <td>$($catScore.Score)%</td>
                        <td><span class="grade-cell" style="background-color: $($catScore.Color); padding: 5px 10px; border-radius: 5px;">$($catScore.Grade)</span></td>
                        <td>$($catScore.TotalUrls)</td>
                        <td>$($catScore.CorrectResults)</td>
                    </tr>
"@
    }

    $HtmlContent += @"
                </tbody>
            </table>
        </div>
        
        <!-- Détail des Tests par Catégorie -->
        <div class="section">
            <h2>🔍 Détail des Tests par Catégorie</h2>
            <div class="categories-grid">
"@

    # Ajout des catégories
    $CategoryIndex = 0

    Foreach($CatScore in $CategoryScores) {
        $CategoryIndex++
        $HtmlContent += @"
                <div class="category-item">
                    <div class="category-header" onclick="toggleCategory('cat-$CategoryIndex')">
                        <div class="category-title">$($CatScore.Category) <span class="toggle-btn" id="btn-cat-$CategoryIndex">▼</span></div>
                        <span class="category-score" style="background-color: $($CatScore.Color);">$($CatScore.Grade) - $($CatScore.Score)%</span>
                    </div>
                    <div class="category-content" id="cat-$CategoryIndex">
                        <table class="detail-table">
                            <thead>
                                <tr>
                                    <th>URL</th>
                                    <th>Réputation</th>
                                    <th>Action Attendue</th>
                                    <th>Statut</th>
                                    <th>Correct</th>
                                </tr>
                            </thead>
                            <tbody>
"@
        
        # Ajout des résultats de chaque URL
        Foreach($Result in $CatScore.Results) {
            $RowClass = if($Result.IsCorrect) { "correct" } else { "incorrect" }
            $CorrectText = if($Result.IsCorrect) { "✅ Oui" } else { "❌ Non" }
            
            $HtmlContent += @"
                                <tr class="$RowClass">
                                    <td title="$($Result.Url)">$($result.Url.Substring(0, [Math]::Min(30, $Result.Url.Length)))$(if($Result.Url.Length -gt 30){"..."})</td>
                                    <td>$($Result.Reputation)</td>
                                    <td>$($Result.ExpectedAction)</td>
                                    <td>$($Result.Status)</td>
                                    <td>$CorrectText</td>
                                </tr>
"@
        }
        
        $HtmlContent += @"
                            </tbody>
                        </table>
                    </div>
                </div>
"@
    }

    $HtmlContent += @"
            </div>
        </div>
        
        <!-- Barème de Notation -->
        <div class="section">
            <h2>📏 Barème de Notation</h2>
            <div class="grading-scale">
"@

    # Ajout du barème de notation
    $gradingScale = @(
        @{Grade='A+'; Score='95-100%'; Interpretation='Excellent / Parfait'; Color='#28a745'}
        @{Grade='A'; Score='90-95%'; Interpretation='Très bon niveau de filtrage'; Color='#52b83a'}
        @{Grade='B+'; Score='85-90%'; Interpretation='Très bon'; Color='#7ac92e'}
        @{Grade='B'; Score='80-85%'; Interpretation='Bon, quelques ajustements nécessaires'; Color='#a3da23'}
        @{Grade='C+'; Score='75-80%'; Interpretation='Assez bon'; Color='#cceb17'}
        @{Grade='C'; Score='70-75%'; Interpretation='Moyen, lacunes importantes'; Color='#f5f90c'}
        @{Grade='D+'; Score='65-70%'; Interpretation='Passable'; Color='#f7d808'}
        @{Grade='D'; Score='60-65%'; Interpretation='Faible, filtrage inefficace'; Color='#f9b604'}
        @{Grade='E+'; Score='55-60%'; Interpretation='Très faible'; Color='#fb9500'}
        @{Grade='E'; Score='50-55%'; Interpretation='Insuffisant'; Color='#fd7300'}
        @{Grade='F+'; Score='45-50%'; Interpretation='Critique'; Color='#ff5100'}
        @{Grade='F'; Score='0-45%'; Interpretation='Très faible, action immédiate requise'; Color='#dc3545'}
    )

    Foreach($GradeInfo in $GradingScale) {
        $HtmlContent += @"
                <div class="grade-item">
                    <div class="grade-badge" style="background-color: $($GradeInfo.Color);">$($GradeInfo.Grade)</div>
                    <div>
                        <strong>$($GradeInfo.Score)</strong><br>
                        <span style="color: #666;">$($GradeInfo.Interpretation)</span>
                    </div>
                </div>
"@
    }

    $HtmlContent += @"
            </div>
        </div>
    </div>
    
    <script>
        function toggleCategory(categoryId) {
            const content = document.getElementById(categoryId);
            const btn = document.getElementById('btn-' + categoryId);
            
            If(content.classList.contains('active')) {
                content.classList.remove('active');
                btn.classList.remove('active');
                content.style.display = 'none';
            }
            Else {
                content.classList.add('active');
                btn.classList.add('active');
                content.style.display = 'block';
            }
        }
        
        // Animation au chargement
        document.addEventListener('DOMContentLoaded', function() {
            const items = document.querySelectorAll('.category-item');
            items.forEach((item, index) => {
                setTimeout(() => {
                    item.style.opacity = '1';
                    item.style.transform = 'translateY(0)';
                }, index * 100);
            });
        });
    </script>
</body>
</html>
"@

    # Écriture du fichier HTML
    Try{
        $HtmlContent | Out-File -FilePath $OutputPath -Encoding UTF8
        Write-ColorOutput "✓ Rapport généré: $OutputPath" "Green"
    }
    Catch {
        Write-ColorOutput "ERREUR: Impossible de générer le rapport: $($_.Exception.Message)" "Red"
    }
}

## Function Main : fonction principale
Function Main {
    Write-ColorOutput @"
╔══════════════════════════════════════════════════════════════════════════════╗
║                    AUDIT FIREWALL - NETWORK REPUTATION SERVICE               ║
║                                  Version 1.0                                 ║
╚══════════════════════════════════════════════════════════════════════════════╝
"@ "Cyan"

    # Vérification des prérequis
    If(-not (Prerequisites)) {
        Write-ColorOutput "ERREUR: Les prérequis ne sont pas satisfaits. Arrêt du script." "Red"

        Return
    }

    # Chargement du fichier JSON
    Try{
        $JsonFile    = Join-Path $PSScriptRoot "file-nrs.json"
        $Categories  = Get-Content $JsonFile -Raw -Encoding UTF8 | ConvertFrom-Json

        Write-ColorOutput "✓ Fichier JSON chargé avec $($Categories.categorie.Count) catégories" "Green"
    }
    Catch {
        Write-ColorOutput "ERREUR: Impossible de charger le fichier JSON: $($_.Exception.Message)" "Red"

        Return
    }

    # Création du dossier de sortie
    $ReportDate   = Get-Date -Format "dddd dd MMMM yyyy-HH mm"
    $ReportsDir   = Join-Path $PSScriptRoot "Rapports"
    $OutputDir    = Join-Path $ReportsDir $ReportDate

    If(-not (Test-Path $ReportsDir)) {
        New-Item -ItemType Directory -Path $ReportsDir -Force | Out-Null
    }

    If(-not (Test-Path $OutputDir)) {
        New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
    }
    
    Write-ColorOutput "`n Dossier de sortie: $outputDir" "Yellow"
    
    # Début des tests
    Write-ColorOutput "`n=== DÉBUT DES TESTS ===" "Green"
    $StartTime = Get-Date

    $AllResults = Check-Categories -Categories $Categories -ProxyUrl $ProxyUrl -ProxyCredential $ProxyCredential -TimeoutSeconds $TimeoutSeconds -BlockPageKeywords $BlockKeywors

    $EndTime = Get-Date
    $Duration = $EndTime - $StartTime
    
    Write-ColorOutput "`n=== RÉSULTATS FINAUX ===" "Green"
    Write-ColorOutput "`n Temps total d'exécution: $($duration.ToString('hh\:mm\:ss'))" "Yellow"
    Write-ColorOutput "`n Total des URLs testées: $($allResults.Count)" "Yellow"
    
    # Calcul du score global
    $GlobalScore = Calculate-CategoryScore -Results $AllResults
    $GlobalGrade = Convert-ScoreToGrade -Score $GlobalScore
    
    Write-ColorOutput "`n `n Score global: $GlobalScore% - Note: $GlobalGrade" "Magenta"
    
    # Génération du rapport HTML
    $ReportPath = Join-Path $OutputDir "Audit_Firewall_Report.html"
    Generate-HtmlReport -Results $AllResults -OutputPath $ReportPath
    
    # Sauvegarde des résultats en JSON
    $JsonResultsPath = Join-Path $outputDir "Results.json"
    $AllResults | ConvertTo-Json -Depth 10 | Out-File -FilePath $JsonResultsPath -Encoding UTF8
    Write-ColorOutput "✓ Résultats sauvegardés: $JsonResultsPath" "Green"
    
    Write-ColorOutput "`n=== AUDIT TERMINÉ ===" "Green"
    Write-ColorOutput "`n Rapport disponible à: $ReportPath" "Cyan"
    
    # Ouverture automatique du rapport
    If(Get-Command "Start-Process" -ErrorAction SilentlyContinue) {
        $OpenReport = Read-Host "`n Voulez-vous ouvrir le rapport maintenant? (O/N)"
        If($OpenReport -eq "O" -or $OpenReport -eq "o" -or $OpenReport -eq "Y" -or $OpenReport -eq "y") {
            Start-Process $ReportPath
        }
    }
}

### Main

Clear-Host

# Exécution du script principal
Try{
    Main
}
Catch {
    Write-ColorOutput "ERREUR FATALE: $($_.Exception.Message)" "Red"
    Write-ColorOutput "Stack Trace: $($_.ScriptStackTrace)" "Red"
}

