# ================= CONFIG =================
$SourcePath   = ""
$LogPath      = "C:\ffmpeg_encode.log"

$CQ           = 24
$Preset       = "slow"
$DryRun       = $false
# =========================================

$videoExts = ".mp4",".mkv",".avi",".mov",".ts",".m2ts",".wmv",".flv",".webm"

if (!(Test-Path $LogPath)) {
    New-Item -ItemType File -Path $LogPath | Out-Null
}

function Write-Log {
    param ([string]$Message)
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    "$timestamp - $Message" | Tee-Object -FilePath $LogPath -Append
}

function Format-Time {
    param ([double]$Seconds)
    if ($Seconds -lt 0) { return "00:00:00" }
    [TimeSpan]::FromSeconds([math]::Round($Seconds)).ToString("hh\:mm\:ss")
}

Write-Log "==== FFmpeg H.265 batch encode started ===="

$files = Get-ChildItem $SourcePath -Recurse -File |
    Where-Object { $_.Extension -in $videoExts }

$total      = $files.Count
$counter    = 0
$totalSaved = 0

# Stats
$encoded = 0
$remuxed = 0
$skipped = 0
$failed  = 0

$encodeTimes = @()

foreach ($file in $files) {
    $counter++

    Write-Progress -Id 1 `
        -Activity "Overall Progress" `
        -Status "File $counter of $total"

    $input  = $file.FullName
    $output = Join-Path $file.DirectoryName ($file.BaseName + ".mkv")
    $tmp    = Join-Path $file.DirectoryName ($file.BaseName + ".tmp.mkv")

    $codec = & ffprobe -v error -select_streams v:0 `
        -show_entries stream=codec_name `
        -of default=noprint_wrappers=1:nokey=1 "$input"

    # Skip H.265 MKV
    if (($codec -eq "hevc") -and ($file.Extension -eq ".mkv")) {
        Write-Progress -Id 2 -ParentId 1 `
            -Activity "Current File" `
            -Status "SKIPPED (H.265 MKV): $($file.Name)" `
            -PercentComplete 100
        Write-Log "SKIPPED: $input"
        $skipped++
        continue
    }

    if ($DryRun) {
        Write-Log "DRY-RUN: $input -> $output"
        continue
    }

    $origSize = (Get-Item $input).Length

    $duration = & ffprobe -v error -show_entries format=duration `
        -of default=noprint_wrappers=1:nokey=1 "$input"
    $duration = [double]$duration

    $startTime = Get-Date

    $args = "-y -i `"$input`" -c:v hevc_nvenc -preset $Preset -rc vbr_hq -cq $CQ -c:a copy `"$tmp`" -progress pipe:1 -nostats"

    $psi = New-Object System.Diagnostics.ProcessStartInfo
    $psi.FileName = "ffmpeg"
    $psi.Arguments = $args
    $psi.RedirectStandardOutput = $true
    $psi.UseShellExecute = $false
    $psi.CreateNoWindow = $true

    $p = New-Object System.Diagnostics.Process
    $p.StartInfo = $psi
    $p.Start() | Out-Null

    while (-not $p.HasExited) {
        $line = $p.StandardOutput.ReadLine()
        if ($line -match "^out_time_ms=(\d+)$") {
            $doneSec = $matches[1] / 1000000
            $percent = [math]::Min([math]::Round(($doneSec / $duration) * 100), 100)

            $elapsed = (Get-Date) - $startTime
            $rate = if ($doneSec -gt 0) { $elapsed.TotalSeconds / $doneSec } else { 0 }
            $etaFile = ($duration - $doneSec) * $rate

            $avgEncode = if ($encodeTimes.Count -gt 0) {
                ($encodeTimes | Measure-Object -Average).Average
            } else { 0 }

            $etaQueue = ($total - $counter) * $avgEncode

            Write-Progress -Id 2 -ParentId 1 `
                -Activity "Current File" `
                -Status "Encoding: $($file.Name) ($percent%) | File ETA: $(Format-Time $etaFile) | Queue ETA: $(Format-Time $etaQueue)" `
                -PercentComplete $percent
        }
    }

    if (Test-Path $tmp) {
        try {
            Remove-Item $input -Force
            Rename-Item $tmp $output -Force

            $newSize = (Get-Item $output).Length
            $saved   = $origSize - $newSize
            $totalSaved += $saved

            $encodeTime = ((Get-Date) - $startTime).TotalSeconds
            $encodeTimes += $encodeTime

            $encoded++
            Write-Log "ENCODED: $input | Saved $([math]::Round($saved/1MB,2)) MB"
        }
        catch {
            Write-Log "FAILED TO REPLACE: $input"
            $failed++
        }
    }
    else {
        Write-Log "FAILED: $input"
        $failed++
    }
}

Write-Progress -Id 2 -Completed
Write-Progress -Id 1 -Completed

$totalSavedMB = [math]::Round($totalSaved / 1MB, 2)

Write-Host ""
Write-Host "===== SUMMARY ====="
Write-Host "Total files : $total"
Write-Host "Encoded     : $encoded"
Write-Host "Skipped     : $skipped"
Write-Host "Failed      : $failed"
Write-Host "Space saved : $totalSavedMB MB"
Write-Host "==================="

Write-Log "==== FFmpeg H.265 batch encode finished ===="
