[CmdletBinding()]
param(
    [switch]$DebugMode
)

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

$ScriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }

$cfgDeploy = Join-Path -Path $ScriptDir -ChildPath 'CfgDeploy.ps1'
if (-not (Test-Path -LiteralPath $cfgDeploy)) {
    throw "Missing CfgDeploy.ps1 in $ScriptDir"
}
. $cfgDeploy

$useIsoDailyFormat = Use-IsoDailyFormat

function Sync-SequenceFilenames {
    param(
        [Parameter(Mandatory)] [string]$SequenceFolderPath,
        [Parameter(Mandatory)] [string]$SequenceName,
        [string]$LogFile,
        [string[]]$Extensions = @('.png','.jpg','.jpeg','.exr','.tif','.tiff','.bmp','.tga')
    )
    $renamed = 0
    $collisions = 0
    $errors = 0
    $checked = 0
    $minFrame = [int]::MaxValue
    $maxFrame = -1
    $frameCount = 0

    if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')]   RENAME CHECK in '$SequenceFolderPath' (seq='$SequenceName')" | Add-Content -LiteralPath $LogFile }

    $files = Get-ChildItem -LiteralPath $SequenceFolderPath -File -Recurse -ErrorAction SilentlyContinue |
        Where-Object { $_.FullName -notlike '*\_archive\*' -and ($Extensions -contains $_.Extension.ToLower()) }
    foreach ($f in $files) {
        $checked++
        $base = [System.IO.Path]::GetFileNameWithoutExtension($f.Name)
        $ext = $f.Extension
        $digits = $null

        if ($base -match '_(\d{6})$') {
            $digits = $Matches[1]
        }
        elseif ($base -match '(?<!_)\b(\d{6})$') {
            $digits = $Matches[1]
        }
        elseif ($base -match '(\d{4})$') {
            $digits = ('00' + $Matches[1])
        }
        else {
            continue
        }

        try {
            $n = [int]$digits
            if ($n -lt $minFrame) { $minFrame = $n }
            if ($n -gt $maxFrame) { $maxFrame = $n }
            $frameCount++
        } catch {}

        $targetBase = "$SequenceName" + '_' + $digits
        if ($base -eq $targetBase) { continue }

        $newName = $targetBase + $ext
        $newPath = Join-Path $SequenceFolderPath $newName
        try {
            if (Test-Path -LiteralPath $newPath) {
                $existing = Get-Item -LiteralPath $newPath -ErrorAction Stop
                $sameSize = ($existing.Length -eq $f.Length)
                $sameTime = ([math]::Abs(($existing.LastWriteTimeUtc - $f.LastWriteTimeUtc).TotalSeconds) -le 1)
                if ($sameSize -and $sameTime) {
                    Remove-Item -LiteralPath $f.FullName -Force -ErrorAction Stop
                    $collisions++
                    if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')]   RENAME DROP duplicate: '$($f.Name)' (matches '$newName')" | Add-Content -LiteralPath $LogFile }
                    continue
                }

                $archiveDir = Join-Path $SequenceFolderPath '_archive'
                if (-not (Test-Path -LiteralPath $archiveDir)) {
                    New-Item -ItemType Directory -Path $archiveDir -Force | Out-Null
                }

                $archiveName = $existing.Name
                $archivePath = Join-Path $archiveDir $archiveName
                if (Test-Path -LiteralPath $archivePath) {
                    $stamp = Get-Date -Format 'yyyyMMdd_HHmmss'
                    $baseName = [System.IO.Path]::GetFileNameWithoutExtension($archiveName)
                    $archivePath = Join-Path $archiveDir ("{0}_{1}{2}" -f $baseName, $stamp, $existing.Extension)
                }

                Move-Item -LiteralPath $existing.FullName -Destination $archivePath -Force -ErrorAction Stop
                $collisions++
                if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')]   RENAME ARCHIVE existing '$($existing.Name)' -> '$archivePath'" | Add-Content -LiteralPath $LogFile }
            }
            Rename-Item -LiteralPath $f.FullName -NewName $newName -ErrorAction Stop
            $renamed++
            if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')]   RENAME: '$($f.Name)' -> '$newName'" | Add-Content -LiteralPath $LogFile }
        }
        catch {
            $errors++
            if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')]   RENAME ERROR for '$($f.Name)': $($_.Exception.Message)" | Add-Content -LiteralPath $LogFile }
        }
    }

    $minOut = $null
    $maxOut = $null
    if ($frameCount -gt 0) {
        $minOut = $minFrame
        $maxOut = $maxFrame
    }
    return [pscustomobject]@{
        Renamed    = $renamed
        Collisions = $collisions
        Errors     = $errors
        Checked    = $checked
        MinFrame   = $minOut
        MaxFrame   = $maxOut
        FrameCount = $frameCount
    }
}

function Get-Mp4FrameRange {
    param([string]$Name)
    if ($Name -match '[-_](\d+)[-_](\d+)\.mp4$') {
        return [pscustomobject]@{ Start = [int]$Matches[1]; End = [int]$Matches[2] }
    }
    return $null
}

function Rename-SequencePreviewMp4 {
    param(
        [Parameter(Mandatory)] [string]$SequenceFolderPath,
        [Parameter(Mandatory)] [string]$SequenceName,
        [Parameter(Mandatory)] [int]$StartFrame,
        [Parameter(Mandatory)] [int]$EndFrame,
        [Parameter(Mandatory)] [string]$RootPath,
        [string]$LogFile
    )
    $renamed = 0
    $collisions = 0
    $errors = 0
    $checked = 0

    $targetName = "$SequenceName-$StartFrame-$EndFrame.mp4"
    $targetPath = Join-Path $SequenceFolderPath $targetName
    $collisionsDir = Join-Path $RootPath '_collisions'

    $mp4s = @(Get-ChildItem -LiteralPath $SequenceFolderPath -File -Filter '*.mp4' -ErrorAction SilentlyContinue |
        Where-Object { $_.FullName -notlike '*\_archive\*' })

    if ($mp4s.Count -eq 0) { return [pscustomobject]@{ Renamed = 0; Collisions = 0; Errors = 0; Checked = 0 } }

    $checked = $mp4s.Count

    $candidates = @($mp4s | ForEach-Object {
        $fr = Get-Mp4FrameRange -Name $_.Name
        $frameMatch = ($fr -and $fr.Start -eq $StartFrame -and $fr.End -eq $EndFrame)
        [pscustomobject]@{
            File       = $_
            FrameMatch = $frameMatch
            LastWrite  = $_.LastWriteTimeUtc
        }
    } | Sort-Object -Property @{ Expression = { -not $_.FrameMatch }; Ascending = $true }, @{ Expression = 'LastWrite'; Descending = $true })

    $best = $candidates[0].File
    $moveToCollisions = @(if ($candidates.Count -gt 1) { $candidates[1..($candidates.Count - 1)] } else { @() })

    $hasCollisions = ($moveToCollisions.Count -gt 0) -or ($best.Name -ne $targetName -and (Test-Path -LiteralPath $targetPath))
    if (-not $hasCollisions -and $best.Name -eq $targetName) {
        return [pscustomobject]@{ Renamed = 0; Collisions = 0; Errors = 0; Checked = $checked }
    }

    try {
        if ($hasCollisions -and -not (Test-Path -LiteralPath $collisionsDir)) {
            New-Item -ItemType Directory -Path $collisionsDir -Force | Out-Null
        }

        foreach ($c in $moveToCollisions) {
            $f = $c.File
            $destName = $f.Name
            $destPath = Join-Path $collisionsDir $destName
            if (Test-Path -LiteralPath $destPath) {
                $base = [System.IO.Path]::GetFileNameWithoutExtension($destName)
                $destName = "{0}_{1}.mp4" -f $base, (Get-Date -Format 'yyyyMMdd_HHmmss')
                $destPath = Join-Path $collisionsDir $destName
            }
            Move-Item -LiteralPath $f.FullName -Destination $destPath -Force -ErrorAction Stop
            $collisions++
            if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')]   MP4 COLLISION moved: '$($f.Name)' -> '$destPath'" | Add-Content -LiteralPath $LogFile }
        }

        if ($best.Name -ne $targetName) {
            if (Test-Path -LiteralPath $targetPath) {
                $destPath = Join-Path $collisionsDir $targetName
                if (Test-Path -LiteralPath $destPath) {
                    $base = [System.IO.Path]::GetFileNameWithoutExtension($targetName)
                    $destPath = Join-Path $collisionsDir ("{0}_{1}.mp4" -f $base, (Get-Date -Format 'yyyyMMdd_HHmmss'))
                }
                Move-Item -LiteralPath $targetPath -Destination $destPath -Force -ErrorAction Stop
                $collisions++
            }
            Rename-Item -LiteralPath $best.FullName -NewName $targetName -ErrorAction Stop
            $renamed++
            if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')]   MP4 RENAME: '$($best.Name)' -> '$targetName'" | Add-Content -LiteralPath $LogFile }
        }
    } catch {
        $errors++
        if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')]   MP4 ERROR: $($_.Exception.Message)" | Add-Content -LiteralPath $LogFile }
    }

    return [pscustomobject]@{
        Renamed    = $renamed
        Collisions = $collisions
        Errors     = $errors
        Checked    = $checked
    }
}

function Resolve-SequenceName {
    param(
        [Parameter(Mandatory)] [System.IO.DirectoryInfo]$Directory
    )
    if ($Directory.Name -eq '_CURRENT' -and $Directory.Parent) {
        return $Directory.Parent.Name
    }
    return $Directory.Name
}

function Add-SequenceFolder {
    param(
        [Parameter(Mandatory)] [System.IO.DirectoryInfo]$Directory,
        [Parameter(Mandatory)] [hashtable]$Map
    )
    if ($Directory.Name -like '_*') { return }
    $fullPath = $Directory.FullName
    if ($Map.ContainsKey($fullPath)) { return }
    
    # Check if directory contains sequence files directly (not just subdirectories)
    $extensions = @('.png','.jpg','.jpeg','.exr','.tif','.tiff','.bmp','.tga')
    $hasSequenceFiles = Get-ChildItem -LiteralPath $fullPath -File -ErrorAction SilentlyContinue |
        Where-Object { $extensions -contains $_.Extension.ToLower() } |
        Select-Object -First 1
    
    # If it only has subdirectories and no sequence files, skip it
    $hasSubdirs = Get-ChildItem -LiteralPath $fullPath -Directory -ErrorAction SilentlyContinue |
        Select-Object -First 1
    if ($null -eq $hasSequenceFiles -and $null -ne $hasSubdirs) {
        return
    }
    
    $Map[$fullPath] = Resolve-SequenceName -Directory $Directory
}

try {
    $root = (Get-Location).ProviderPath
    $logFile = $null

    if ($DebugMode) {
        $logFile = Join-Path $root ("UpdateSequences_{0}.log" -f (Get-Date -Format 'yyyyMMdd_HHmmss'))
        "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === UpdateSequences started in '$root' ===" | Out-File -LiteralPath $logFile -Encoding UTF8
    }

    $sequenceMap = @{}

    $primaryPattern = if ($useIsoDailyFormat) { '????-??-??' } else { 'daily_*' }
    $secondaryPattern = if ($useIsoDailyFormat) { 'daily_*' } else { '????-??-??' }

    $primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |
        Where-Object { $_.Name -notlike '_*' }
    foreach ($d in $primaryDirs) {
        $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })
        if ($seqDirs.Count -eq 0) {
            Add-SequenceFolder -Directory $d -Map $sequenceMap
        } else {
            foreach ($s in $seqDirs) {
                Add-SequenceFolder -Directory $s -Map $sequenceMap
            }
        }
    }

    $secondaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $secondaryPattern -ErrorAction SilentlyContinue |
        Where-Object { $_.Name -notlike '_*' }
    foreach ($d in $secondaryDirs) {
        $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })
        if ($seqDirs.Count -eq 0) {
            Add-SequenceFolder -Directory $d -Map $sequenceMap
        } else {
            foreach ($s in $seqDirs) {
                Add-SequenceFolder -Directory $s -Map $sequenceMap
            }
        }
    }

    $directSeqs = Get-ChildItem -LiteralPath $root -Directory -ErrorAction SilentlyContinue |
        Where-Object {
            $_.Name -notlike '_*' -and
            $_.Name -notlike 'daily_*' -and
            $_.Name -notmatch '^\d{4}-\d{2}-\d{2}$'
        }
    foreach ($seq in $directSeqs) {
        $seqDirs = @(Get-ChildItem -LiteralPath $seq.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })
        if ($seqDirs.Count -eq 0) {
            Add-SequenceFolder -Directory $seq -Map $sequenceMap
        } else {
            foreach ($s in $seqDirs) {
                Add-SequenceFolder -Directory $s -Map $sequenceMap
            }
        }
    }

    $sequenceFolders = $sequenceMap.GetEnumerator() | ForEach-Object {
        [pscustomobject]@{
            Path = $_.Key
            Name = $_.Value
        }
    } | Sort-Object -Property Path

    if (-not $sequenceFolders) {
        Write-Host "No sequence folders found." -ForegroundColor Yellow
        if ($logFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')]   No sequence folders found." | Add-Content -LiteralPath $logFile }
        exit 0
    }

    $totalSequences = 0
    $filesRenamedTotal = 0
    $renameCollisions = 0
    $renameErrors = 0
    $mp4RenamedTotal = 0
    $mp4Collisions = 0
    $mp4Errors = 0

    foreach ($seq in $sequenceFolders) {
        $totalSequences++
        $renameResult = Sync-SequenceFilenames -SequenceFolderPath $seq.Path -SequenceName $seq.Name -LogFile $logFile
        if ($DebugMode -or $renameResult.Renamed -gt 0 -or $renameResult.Collisions -gt 0 -or $renameResult.Errors -gt 0) {
            Write-Host "[RENAME]|$($seq.Path)|$($seq.Name)|checked=$($renameResult.Checked)|renamed=$($renameResult.Renamed)|collisions=$($renameResult.Collisions)|errors=$($renameResult.Errors)" -ForegroundColor Cyan
        }
        $filesRenamedTotal += $renameResult.Renamed
        $renameCollisions += $renameResult.Collisions
        $renameErrors += $renameResult.Errors

        if ($renameResult.FrameCount -gt 0 -and $null -ne $renameResult.MinFrame -and $null -ne $renameResult.MaxFrame) {
            $mp4Result = Rename-SequencePreviewMp4 -SequenceFolderPath $seq.Path -SequenceName $seq.Name -StartFrame $renameResult.MinFrame -EndFrame $renameResult.MaxFrame -RootPath $root -LogFile $logFile
            if ($DebugMode -or $mp4Result.Renamed -gt 0 -or $mp4Result.Collisions -gt 0 -or $mp4Result.Errors -gt 0) {
                Write-Host "[MP4]|$($seq.Path)|$($seq.Name)|renamed=$($mp4Result.Renamed)|collisions=$($mp4Result.Collisions)|errors=$($mp4Result.Errors)" -ForegroundColor Cyan
            }
            $mp4RenamedTotal += $mp4Result.Renamed
            $mp4Collisions += $mp4Result.Collisions
            $mp4Errors += $mp4Result.Errors
        }
    }

    Write-Host "=== SUMMARY REPORT ===" -ForegroundColor Magenta
    Write-Host "Sequences scanned: $totalSequences" -ForegroundColor White
    Write-Host "Files renamed: $filesRenamedTotal (collisions: $renameCollisions, errors: $renameErrors)" -ForegroundColor White
    Write-Host "Preview MP4s renamed: $mp4RenamedTotal (collisions: $mp4Collisions, errors: $mp4Errors)" -ForegroundColor White
    Write-Host "=====================" -ForegroundColor Magenta

    if ($logFile) {
        "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === UpdateSequences completed (seq=$totalSequences renamed=$filesRenamedTotal mp4=$mp4RenamedTotal) ===" | Add-Content -LiteralPath $logFile
    }

    exit 0
}
catch {
    if ($logFile) {
        "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')]   ERROR: $($_.Exception.Message)" | Add-Content -LiteralPath $logFile
    }
    Write-Host "ERROR: $_" -ForegroundColor Red
    exit 1
}