[CmdletBinding()]
param(
    [string]$ConfigPath = 'C:\ProgramData\AWatch-rus\deployment-config.json',
    [string]$OutputRoot,
    [int]$RetentionDays,
    [string[]]$Channels,
    [Nullable[int]]$HoursBack,
    [int]$DaysBack = 3,
    [switch]$NoZip
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

function New-Directory {
    param([string]$Path)
    if (-not (Test-Path -LiteralPath $Path)) {
        New-Item -ItemType Directory -Path $Path -Force | Out-Null
    }
}

function Get-ConfigValue {
    param(
        [object]$Config,
        [string]$Section,
        [string]$Name,
        $DefaultValue
    )
    if ($null -eq $Config) { return $DefaultValue }
    if ($Config.PSObject.Properties.Name -notcontains $Section) { return $DefaultValue }
    $sectionValue = $Config.$Section
    if ($null -eq $sectionValue) { return $DefaultValue }
    if ($sectionValue.PSObject.Properties.Name -notcontains $Name) { return $DefaultValue }
    return $sectionValue.$Name
}

$config = $null
if (Test-Path -LiteralPath $ConfigPath) {
    $config = Get-Content -LiteralPath $ConfigPath -Raw | ConvertFrom-Json
}

$effectiveOutputRoot = if ($OutputRoot) {
    $OutputRoot
} else {
    [string](Get-ConfigValue -Config $config -Section 'forensics' -Name 'evtxExportRoot' -DefaultValue 'C:\ProgramData\AWatch-rus\forensics\evtx-exports')
}
$effectiveRetentionDays = if ($PSBoundParameters.ContainsKey('RetentionDays')) {
    $RetentionDays
} else {
    [int](Get-ConfigValue -Config $config -Section 'forensics' -Name 'retentionDays' -DefaultValue 14)
}
$effectiveChannels = if ($Channels -and $Channels.Count -gt 0) {
    @($Channels)
} else {
    @(Get-ConfigValue -Config $config -Section 'forensics' -Name 'evtxChannels' -DefaultValue @(
        'Security',
        'System',
        'Application',
        'Microsoft-Windows-PowerShell/Operational',
        'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational',
        'Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational'
    ))
}

New-Directory -Path $effectiveOutputRoot

$hostName = if ($config -and $config.PSObject.Properties.Name -contains 'awHostname' -and -not [string]::IsNullOrWhiteSpace([string]$config.awHostname)) {
    [string]$config.awHostname
} else {
    [string]$env:COMPUTERNAME
}

$timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$batchRoot = Join-Path $effectiveOutputRoot "$hostName-$timestamp"
$evtxRoot = Join-Path $batchRoot 'evtx'
$metaPath = Join-Path $batchRoot 'manifest.json'
$zipPath = Join-Path $effectiveOutputRoot "$hostName-$timestamp.zip"

New-Directory -Path $batchRoot
New-Directory -Path $evtxRoot

$lookbackMs = if ($null -ne $HoursBack) {
    [int64]$HoursBack * 60 * 60 * 1000
} else {
    [int64]$DaysBack * 24 * 60 * 60 * 1000
}
$query = "*[System[TimeCreated[timediff(@SystemTime) <= $lookbackMs]]]"
$results = @()

foreach ($channel in @($effectiveChannels | Where-Object { -not [string]::IsNullOrWhiteSpace([string]$_) })) {
    $safeName = (($channel -replace '[\\/:*?""<>| ]', '_').Trim('_'))
    $targetPath = Join-Path $evtxRoot ($safeName + '.evtx')
    try {
        & wevtutil.exe epl $channel $targetPath /ow:true /q:$query | Out-Null
        $exists = Test-Path -LiteralPath $targetPath
        $size = if ($exists) { (Get-Item -LiteralPath $targetPath).Length } else { 0 }
        $results += [pscustomobject]@{
            channel = $channel
            path = $targetPath
            exported = $exists
            size = $size
            status = if ($exists) { 'ok' } else { 'empty' }
        }
    }
    catch {
        $results += [pscustomobject]@{
            channel = $channel
            path = $targetPath
            exported = $false
            size = 0
            status = 'error'
            error = $_.Exception.Message
        }
    }
}

$manifest = [ordered]@{
    generatedAtUtc = (Get-Date).ToUniversalTime().ToString('o')
    hostname = $hostName
    configPath = $ConfigPath
    outputRoot = $effectiveOutputRoot
    batchRoot = $batchRoot
    zipPath = if ($NoZip) { $null } else { $zipPath }
    daysBack = $DaysBack
    hoursBack = if ($null -ne $HoursBack) { [int]$HoursBack } else { $null }
    retentionDays = $effectiveRetentionDays
    channels = @($effectiveChannels)
    exports = @($results)
}
$manifest | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $metaPath -Encoding UTF8

if (-not $NoZip) {
    if (Test-Path -LiteralPath $zipPath) {
        Remove-Item -LiteralPath $zipPath -Force -ErrorAction SilentlyContinue
    }
    Compress-Archive -Path (Join-Path $batchRoot '*') -DestinationPath $zipPath -Force
}

$cutoff = (Get-Date).AddDays(-1 * [Math]::Max(1, $effectiveRetentionDays))
Get-ChildItem -LiteralPath $effectiveOutputRoot -Directory -ErrorAction SilentlyContinue |
    Where-Object { $_.LastWriteTime -lt $cutoff } |
    ForEach-Object { Remove-Item -LiteralPath $_.FullName -Recurse -Force -ErrorAction SilentlyContinue }
Get-ChildItem -LiteralPath $effectiveOutputRoot -File -Filter '*.zip' -ErrorAction SilentlyContinue |
    Where-Object { $_.LastWriteTime -lt $cutoff } |
    ForEach-Object { Remove-Item -LiteralPath $_.FullName -Force -ErrorAction SilentlyContinue }

$manifest
