param(
    [string]$SourcePath,
    [string]$TargetPath
)

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

function Show-GUI {
    $form = New-Object System.Windows.Forms.Form
    $form.Text = "Folder Mirror Tool"
    $form.Size = New-Object System.Drawing.Size(600,450)
    $form.StartPosition = "CenterScreen"
    $form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog

    # Source Controls
    $lblSource = New-Object Windows.Forms.Label
    $lblSource.Location = New-Object Drawing.Point(10,10)
    $lblSource.Text = "Source Path:"
    $txtSource = New-Object Windows.Forms.TextBox
    $txtSource.Location = New-Object Drawing.Point(120,10)
    $txtSource.Size = New-Object Drawing.Size(350,20)
    $btnSource = New-Object Windows.Forms.Button
    $btnSource.Location = New-Object Drawing.Point(480,10)
    $btnSource.Text = "Browse"
    $btnSource.Add_Click({
        $folder = New-Object Windows.Forms.FolderBrowserDialog
        if($folder.ShowDialog() -eq "OK") { $txtSource.Text = $folder.SelectedPath }
    })

    # Target Controls
    $lblTarget = New-Object Windows.Forms.Label
    $lblTarget.Location = New-Object Drawing.Point(10,40)
    $lblTarget.Text = "Target Path:"
    $txtTarget = New-Object Windows.Forms.TextBox
    $txtTarget.Location = New-Object Drawing.Point(120,40)
    $txtTarget.Size = New-Object Drawing.Size(350,20)
    $btnTarget = New-Object Windows.Forms.Button
    $btnTarget.Location = New-Object Drawing.Point(480,40)
    $btnTarget.Text = "Browse"
    $btnTarget.Add_Click({
        $folder = New-Object Windows.Forms.FolderBrowserDialog
        if($folder.ShowDialog() -eq "OK") { $txtTarget.Text = $folder.SelectedPath }
    })

    # Log Box
    $script:txtLogGui = New-Object Windows.Forms.RichTextBox
    $script:txtLogGui.Location = New-Object Drawing.Point(10,70)
    $script:txtLogGui.Size = New-Object Drawing.Size(560,300)
    $script:txtLogGui.ReadOnly = $true
    $script:txtLogGui.Font = New-Object System.Drawing.Font("Consolas", 8)
    $script:txtLogGui.WordWrap = $false
    $script:txtLogGui.ScrollBars = [System.Windows.Forms.RichTextBoxScrollBars]::Both

    # Start Button
    $script:btnStartGui = New-Object Windows.Forms.Button
    $script:btnStartGui.Location = New-Object Drawing.Point(480,380)
    $script:btnStartGui.Size = New-Object Drawing.Size(90,30)
    $script:btnStartGui.Text = "Start Mirror"
    $script:btnStartGui.Add_Click({
        $currentSourcePath = $txtSource.Text
        $currentTargetPath = $txtTarget.Text

        try {
            if (-not (Test-Path $currentSourcePath -PathType Container)) { throw "Source path invalid or not a folder." }
            if (-not (Test-Path $currentTargetPath -PathType Container)) {
                try {
                    $script:txtLogGui.AppendText("Target path does not exist. Attempting to create: $currentTargetPath`n")
                    $null = New-Item -ItemType Directory -Path $currentTargetPath -Force -ErrorAction Stop
                    $script:txtLogGui.AppendText("Created target directory: $currentTargetPath`n")
                } catch {
                    throw "Target path invalid or not a folder, and could not be created: $($_.Exception.Message)"
                }
            }
            
            $script:txtLogGui.Clear()
            $script:txtLogGui.AppendText("Starting mirror operation...`n")
            $script:txtLogGui.AppendText("Source: $currentSourcePath`n")
            $script:txtLogGui.AppendText("Target: $currentTargetPath`n")

            $global:logFile = "$PSScriptRoot\MirrorLog_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
            $script:txtLogGui.AppendText("Detailed log will also be saved to: $global:logFile`n`n")

            # Robocopy parameters for GUI (Verbose, but no per-file % progress to keep GUI clean)
            $robocopyArgs = @(
                "`"$currentSourcePath`"", 
                "`"$currentTargetPath`"",
                "/MIR",      # Mirror mode
                "/V",        # Verbose output (shows skipped files)
                "/FP",       # Include Full Pathname of files in output
                "/BYTES",    # Print sizes as bytes
                "/NP",       # No Progress percentage (to keep GUI log cleaner)
                # Removed /NDL (No Directory List) -> will show directory list
                # Removed /NJH (No Job Header) -> will show job header
                # Removed /NJS (No Job Summary) -> will show job summary
                "/LOG+:`"$global:logFile`"", 
                "/R:5",      # 5 retries on failed files
                "/W:5"       # 5 second wait between retries
            )

            $script:btnStartGui.Enabled = $false 

            $process = New-Object System.Diagnostics.Process
            $process.StartInfo.FileName = "robocopy.exe"
            $process.StartInfo.Arguments = $robocopyArgs -join " "
            $process.StartInfo.UseShellExecute = $false
            $process.StartInfo.RedirectStandardOutput = $true
            $process.StartInfo.RedirectStandardError = $true
            $process.StartInfo.CreateNoWindow = $true
            $process.EnableRaisingEvents = $true

            $process.add_OutputDataReceived({
                if (-not [string]::IsNullOrEmpty($_.Data)) {
                    $script:txtLogGui.BeginInvoke([Action[string]]{
                        param($line)
                        $script:txtLogGui.AppendText("$line`r`n") 
                        $script:txtLogGui.ScrollToCaret()
                    }, $_.Data)
                }
            })

            $process.add_ErrorDataReceived({
                if (-not [string]::IsNullOrEmpty($_.Data)) {
                    $script:txtLogGui.BeginInvoke([Action[string]]{
                        param($line)
                        # Robocopy often uses stderr for summary or non-critical info too,
                        # so not always coloring it as a hard error.
                        # Let Robocopy's output speak for itself mostly.
                        $script:txtLogGui.AppendText("[STDERR] $line`r`n")
                        $script:txtLogGui.ScrollToCaret()
                    }, $_.Data)
                }
            })
            
            $process.add_Exited({
                $exitCode = $process.ExitCode
                $script:txtLogGui.BeginInvoke([Action]{
                    $script:txtLogGui.AppendText("`n------------------------------------`n")
                    $script:txtLogGui.AppendText("Robocopy process finished.`n")
                    $script:txtLogGui.AppendText("Robocopy Exit Code: $exitCode`n")

                    if ($exitCode -ge 8) {
                        $script:txtLogGui.SelectionStart = $script:txtLogGui.TextLength
                        $script:txtLogGui.SelectionLength = 0
                        $script:txtLogGui.SelectionColor = [System.Drawing.Color]::Red
                        $script:txtLogGui.AppendText("Robocopy reported errors or critical failures (Code >= 8). Check log for details.`n")
                        $script:txtLogGui.SelectionColor = $script:txtLogGui.ForeColor
                        [Windows.Forms.MessageBox]::Show("Robocopy completed with errors or critical failures (Exit Code: $exitCode). Check Robocopy output and the log file for details.", "Robocopy Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
                    } elseif ($exitCode -eq 0) {
                         $script:txtLogGui.AppendText("Robocopy: No files were copied. No failure was encountered. No files were mismatched. The files already exist in the destination directory; therefore, the copy operation was skipped.`n")
                    } elseif ($exitCode -gt 0 -and $exitCode -lt 8) { 
                        $script:txtLogGui.SelectionStart = $script:txtLogGui.TextLength
                        $script:txtLogGui.SelectionLength = 0
                        $script:txtLogGui.SelectionColor = [System.Drawing.Color]::DarkGreen
                        $script:txtLogGui.AppendText("Robocopy completed. Some files may have been copied, or extra/mismatched files detected (Code $exitCode). This is generally considered successful or informational. Review output for details.`n")
                        $script:txtLogGui.SelectionColor = $script:txtLogGui.ForeColor
                    }
                    $script:txtLogGui.AppendText("Log file: $global:logFile`n")
                    $script:txtLogGui.ScrollToCaret()
                    $script:btnStartGui.Enabled = $true 
                })
                $process.Close()
                $process.Dispose()
            })

            $process.Start() | Out-Null
            $process.BeginOutputReadLine()
            $process.BeginErrorReadLine()
        }
        catch {
            $errorMessage = $_.Exception.Message
            if ($_.Exception.InnerException) { $errorMessage += " Inner: " + $_.Exception.InnerException.Message }
            $script:txtLogGui.AppendText("[SCRIPT ERROR] $errorMessage`n")
            [Windows.Forms.MessageBox]::Show($errorMessage, "Script Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
            if ($script:btnStartGui) {$script:btnStartGui.Enabled = $true} 
        }
    })

    $form.Controls.AddRange(@(
        $lblSource, $txtSource, $btnSource, 
        $lblTarget, $txtTarget, $btnTarget, 
        $script:txtLogGui, 
        $script:btnStartGui
    ))

    if ($SourcePath) { $txtSource.Text = $SourcePath }
    if ($TargetPath) { $txtTarget.Text = $TargetPath }
    
    $form.Add_Shown({
        # If parameters were passed and GUI is shown, optionally auto-start
        # For now, we require manual click even if params are pre-filled.
        # if ($txtSource.Text -and $txtTarget.Text) { $script:btnStartGui.PerformClick() }
    })

    [void]$form.ShowDialog()
}

# --- Main script execution logic ---

if (-not $PSBoundParameters.ContainsKey('SourcePath') -or -not $PSBoundParameters.ContainsKey('TargetPath')) {
    Show-GUI # Pass potentially existing parameters for pre-filling
}
else {
    $cliErrorOccurred = $false
    try {
        if (-not (Test-Path $SourcePath -PathType Container)) { throw "Source path '$SourcePath' invalid or not a folder." }
        if (-not (Test-Path $TargetPath -PathType Container)) {
            Write-Host "Target path '$TargetPath' does not exist. Attempting to create..." -ForegroundColor Yellow
            try {
                $null = New-Item -ItemType Directory -Path $TargetPath -Force -ErrorAction Stop
                Write-Host "Created target directory: $TargetPath" -ForegroundColor Green
            } catch {
                throw "Target path '$TargetPath' invalid or not a folder, and could not be created: $($_.Exception.Message)"
            }
        }

        $logFile = "$PSScriptRoot\MirrorLog_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
        Write-Host "[$(Get-Date)] Starting mirror operation..."
        
        Write-Host "Source: $SourcePath"
        Write-Host "Target: $TargetPath"
        Write-Host "Log file: $logFile"

        # Robocopy parameters for CLI (Fully verbose, including progress)
        $robocopyArgs = @(
            "`"$SourcePath`"", 
            "`"$TargetPath`"",
            "/MIR",      # Mirror mode
            "/V",        # Verbose output (shows skipped files)
            "/FP",       # Include Full Pathname of files in output
            "/BYTES",    # Print sizes as bytes
            # Removed /NP -> will show progress percentage
            # Removed /NDL -> will show directory list
            # Removed /NJH -> will show job header
            # Removed /NJS -> will show job summary
            "/TEE",      # Output to console AND log file
            "/LOG+:`"$logFile`"",
            "/R:5",
            "/W:5"
        )
        
        Write-Host "Executing: robocopy $($robocopyArgs -join " ")"
        Write-Host "------------------------------------ ROBOCOPY OUTPUT START ------------------------------------"
        $process = Start-Process robocopy -ArgumentList $robocopyArgs -NoNewWindow -PassThru -Wait
        Write-Host "------------------------------------ ROBOCOPY OUTPUT END --------------------------------------"
        Write-Host "Robocopy Exit Code: $($process.ExitCode)"


        if ($process.ExitCode -ge 8) {
            throw "Robocopy reported errors or critical failures with exit code $($process.ExitCode). Check output above and log: $logFile"
        } elseif ($process.ExitCode -eq 0) {
             Write-Host "[$(Get-Date)] Robocopy: No files were copied. No failure was encountered. No files were mismatched. (Exit Code: 0)" -ForegroundColor Cyan
        } else { # 1 to 7
            Write-Host "[$(Get-Date)] Robocopy completed. Some files may have been copied, or extra/mismatched files detected (Exit Code: $($process.ExitCode)). This is generally considered successful or informational. Review output for details." -ForegroundColor Cyan
        }
    
        Write-Host "[$(Get-Date)] Mirror operation main phase completed." -ForegroundColor Green
        if ($process.ExitTime -and $process.StartTime) { 
            Write-Host "Total Robocopy processing time: $($process.ExitTime - $process.StartTime)"
        }
    }
    catch {
        Write-Host "[SCRIPT ERROR] $($_.Exception.Message)" -ForegroundColor Red
        if ($_.Exception.InnerException) { Write-Host "[INNER SCRIPT ERROR] $($_.Exception.InnerException.Message)" -ForegroundColor Red }
        $cliErrorOccurred = $true
    }
    finally {
        if ($cliErrorOccurred) {
            Write-Host "Operation finished with errors." -ForegroundColor Red
        } else {
            Write-Host "Operation finished." -ForegroundColor Green
        }
        Read-Host "Press Enter to exit..."
        if ($cliErrorOccurred) {
             if ($Host.Name -eq "ConsoleHost") { exit 1 } # Exit with error code for automation
        }
    }
}