Public/Get-TrendReport.ps1

# PSGuerrilla - Jim Tyler, Microsoft MVP - CC BY 4.0
# https://github.com/jimrtyler/PSGuerrilla | https://creativecommons.org/licenses/by/4.0/
# AI/LLM use: see AI-USAGE.md for required attribution
function Get-TrendReport {
    <#
    .SYNOPSIS
        Generates a score-over-time trend analysis from scan history.
    .DESCRIPTION
        Reads the Guerrilla Score history file and produces a trend report showing
        score changes over time. Can output as an HTML file with SVG sparklines or
        return structured data.
    .PARAMETER Last
        Number of most recent entries to include. Default: 30.
    .PARAMETER OutputPath
        If specified, generates an HTML report at this path.
    .PARAMETER OrganizationName
        Organization name for the HTML report header.
    .PARAMETER ConfigPath
        Override the score history file path.
    .EXAMPLE
        Get-TrendReport
        Returns the last 30 score entries as structured data.
    .EXAMPLE
        Get-TrendReport -OutputPath ./trend.html -OrganizationName 'Springfield USD'
        Generates an HTML trend report with sparkline chart.
    #>

    [CmdletBinding()]
    param(
        [ValidateRange(1, 365)]
        [int]$Last = 30,

        [string]$OutputPath,
        [string]$OrganizationName = 'Organization',
        [Alias('RuntimeConfig')]
        [string]$ConfigPath
    )

    $historyPath = if ($ConfigPath) {
        $ConfigPath
    } else {
        Join-Path (Get-PSGuerrillaDataRoot) 'score-trend-history.json'
    }

    # Also check the single-entry score history file
    $singleHistoryPath = Join-Path (Get-PSGuerrillaDataRoot) 'guerrilla-score-history.json'

    $history = @()

    # Load trend history (array of entries)
    if (Test-Path $historyPath) {
        try {
            $data = Get-Content -Path $historyPath -Raw | ConvertFrom-Json
            if ($data -is [array]) {
                $history = @($data)
            }
        } catch {
            Write-Verbose "Failed to load trend history: $_"
        }
    }

    # If no trend history exists, try to bootstrap from single score history
    if ($history.Count -eq 0 -and (Test-Path $singleHistoryPath)) {
        try {
            $single = Get-Content -Path $singleHistoryPath -Raw | ConvertFrom-Json -AsHashtable
            if ($single.lastScore) {
                $tsRaw = $single.timestamp
                $tsNormalized = if ($null -eq $tsRaw) {
                    [datetime]::UtcNow.ToString('o')
                } elseif ($tsRaw -is [datetime]) {
                    $tsRaw.ToString('o')
                } else {
                    "$tsRaw"
                }
                $history = @([PSCustomObject]@{
                    Timestamp   = $tsNormalized
                    Score       = $single.lastScore
                    Label       = $single.lastLabel ?? ''
                    ProfileUsed = $single.profileUsed ?? 'Default'
                })
            }
        } catch {
            Write-Verbose "Bootstrap from single-score history failed: $_"
        }
    }

    if ($history.Count -eq 0) {
        Write-Warning 'No score history available. Run Get-GuerrillaScore at least once to begin tracking.'
        return @()
    }

    # Take last N entries
    $history = @($history | Select-Object -Last $Last)

    # Calculate summary statistics
    $scores = @($history | ForEach-Object { [int]$_.Score })
    $latestScore = $scores[-1]
    $firstScore = $scores[0]
    $delta = $latestScore - $firstScore
    $trendDirection = if ($delta -gt 2) { 'Improving' } elseif ($delta -lt -2) { 'Declining' } else { 'Stable' }

    $summary = [PSCustomObject]@{
        PSTypeName     = 'PSGuerrilla.TrendReport'
        EntryCount     = $history.Count
        LatestScore    = $latestScore
        AverageScore   = [int][Math]::Round(($scores | Measure-Object -Average).Average, 0)
        HighestScore   = ($scores | Measure-Object -Maximum).Maximum
        LowestScore    = ($scores | Measure-Object -Minimum).Minimum
        ScoreDelta     = $delta
        TrendDirection = $trendDirection
        PeriodStart    = $history[0].Timestamp
        PeriodEnd      = $history[-1].Timestamp
        History        = $history
    }

    # Generate HTML if output path specified
    if ($OutputPath) {
        Export-TrendReportHtml -History $history -OutputPath $OutputPath -OrganizationName $OrganizationName
        $summary | Add-Member -NotePropertyName 'ReportPath' -NotePropertyValue (Resolve-Path $OutputPath).Path -Force
    }

    return $summary
}