Private/Analyzers.Helper.ps1

# Detect current OS platform
function Get-Platform {
    if ($IsWindows) {
        return "Windows"
    } else {
        return "Linux"
    }
}

# Load custom parsing rules from config file
function Get-CustomParsingRules {
    $configPath = Join-Path $PSScriptRoot '..\theme.config'
    if (-not (Test-Path $configPath)) {
        return @()
    }

    $lines = Get-Content $configPath | Where-Object { $_ -match '^ParseRegex\d+=' }
    $rules = @()

    foreach ($line in $lines) {
        if ($line -match '^ParseRegex\d+=(?<regex>.+)$') {
            $rules += $matches['regex']
        }
    }

    return $rules
}

# Try to match a line to a custom rule
function Test-CustomParse {
    param (
        [string]$Line,
        [string[]]$RegexPatterns
    )

    foreach ($pattern in $RegexPatterns) {
        if ($Line -match $pattern) {
            return [PSCustomObject]@{
                Timestamp = if ($matches['Time']) { $matches['Time'] } else { $null }
                Level     = if ($matches['Level']) { $matches['Level'] } else { 'Info' }
                Provider  = if ($matches['Source']) { $matches['Source'] } else { 'Unknown' }
                Message   = if ($matches['Message']) { $matches['Message'] } else { $Line }
            }
        }
    }

    return $null
}

# Convert raw log line to timestamp object
function Convert-ToTimestamp {
    param (
        [Parameter(Mandatory)]
        [string]$Line
    )

    if ($Line -match '^(?<Time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})') {
        return [datetime]::ParseExact($matches['Time'], 'yyyy-MM-dd HH:mm:ss', $null)
    } elseif ($Line -match '^(?<Month>\w{3}) +(?<Day>\d{1,2}) (?<Time>\d{2}:\d{2}:\d{2})') {
        $year = (Get-Date).Year
        $dateStr = "$($matches['Month']) $($matches['Day']) $year $($matches['Time'])"
        return [datetime]::ParseExact($dateStr, 'MMM dd yyyy HH:mm:ss', $null)
    }

    return $null
}

# Convert a log line to a structured object
function Convert-LogLine {
    param (
        [Parameter(Mandatory)]
        [string]$Line
    )

    $customRules = Get-CustomParsingRules
    $customResult = Test-CustomParse -Line $Line -RegexPatterns $customRules
    if ($customResult) { return $customResult }

    if ($Line -match '^(?<Time>[\d\-:\s]+) \[(?<Level>[^\]]+)\] (?<Provider>[^:]+): (?<Message>.+)$') {
        return [PSCustomObject]@{
            Timestamp = [datetime]::ParseExact($matches['Time'], 'yyyy-MM-dd HH:mm:ss', $null)
            Level     = $matches['Level']
            Provider  = $matches['Provider']
            Message   = $matches['Message']
        }
    }

    if ($Line -match '^(?<Month>\w{3}) +(?<Day>\d{1,2}) (?<Time>\d{2}:\d{2}:\d{2}) (?<Host>\S+) (?<Source>[^:]+): (?<Message>.+)$') {
        $year = (Get-Date).Year
        $datetime = "$($matches['Month']) $($matches['Day']) $year $($matches['Time'])"
        return [PSCustomObject]@{
            Timestamp = [datetime]::ParseExact($datetime, 'MMM dd yyyy HH:mm:ss', $null)
            Level     = 'Info'
            Provider  = $matches['Source']
            Message   = $matches['Message']
        }
    }

    return $null
}

# Select lines based on include/exclude keywords
function Select-LogLines {
    param (
        [string[]]$Lines,
        [string[]]$IncludeKeywords = @(),
        [string[]]$ExcludeKeywords = @()
    )

    $filtered = $Lines

    if ($IncludeKeywords.Count -gt 0) {
        $filtered = $filtered | Where-Object {
            $line = $_
            ($IncludeKeywords | Where-Object { $line -match $_ }).Count -gt 0
        }
    }

    if ($ExcludeKeywords.Count -gt 0) {
        $filtered = $filtered | Where-Object {
            $line = $_
            ($ExcludeKeywords | Where-Object { $line -match $_ }).Count -eq 0
        }
    }

    return $filtered
}

# Reverse array of lines (used for reverse sorting)
function Convert-LinesOrder {
    param (
        [string[]]$Lines
    )
    return [System.Linq.Enumerable]::Reverse($Lines)
}

# Utility messages
function Write-Info {
    param ([string]$Message)
    Write-Host "ℹ️ $Message" -ForegroundColor Cyan
}

function Write-WarningMessage {
    param ([string]$Message)
    Write-Warning "⚠️ $Message"
}

function Write-ErrorMessage {
    param ([string]$Message)
    Write-Host "❌ $Message" -ForegroundColor Red
}