[CmdletBinding()]
param(
    [Parameter(Mandatory=$true, HelpMessage="Path to the zip file on remote machine")]
    [string]$RemoteZipPath,
    
    [Parameter(HelpMessage="Remote extraction path")]
    [string]$RemoteExtractPath,
    
    [Parameter(HelpMessage="Remote machine name or IP")]
    [string]$RemoteMachine = 'macmini2012',
    
    [Parameter(HelpMessage="Remote username")]
    [string]$Username = 'administrator',
    
    [Parameter(HelpMessage="Remote password")]
    [string]$Password = 'Woslaodaha0909',
    
    [Parameter(HelpMessage="Service name to stop/start during extraction")]
    [string]$ServiceName,
    
    [Parameter(HelpMessage="nssmex port (default: 3002)")]
    [int]$NssmexPort = 3002,
    
    [Parameter(HelpMessage="Clean extraction directory before unzipping")]
    [switch]$CleanDirectory = $true,
    
    [Parameter(HelpMessage="Delete zip file after extraction")]
    [switch]$DeleteZipAfterExtraction = $true,
    
    [Parameter(HelpMessage="Enable beep notification on completion")]
    [switch]$EnableBeep = $true,
    
    [Parameter(HelpMessage="Beep frequency in Hz")]
    [int]$BeepFrequency = 1000,
    
    [Parameter(HelpMessage="Beep duration in milliseconds")]
    [int]$BeepDuration = 500
)

# Set default RemoteExtractPath if not provided
if (-not $RemoteExtractPath) {
    # Extract to a folder with the same name as the zip file (without extension)
    $zipName = [System.IO.Path]::GetFileNameWithoutExtension($RemoteZipPath)
    $parentPath = Split-Path -Parent $RemoteZipPath
    $RemoteExtractPath = Join-Path $parentPath $zipName
}

# Messages
$msgCreatingSession = "Creating remote session..."
$msgCheckingZip = "Checking if zip file exists on remote machine..."
$msgZipFound = "Zip file found: {0}"
$msgZipNotFound = "Zip file not found on remote machine: {0}"
$msgStoppingService = "Stopping service: {0}"
$msgServiceStopped = "Service stopped."
$msgServiceNotFound = "Service not found: {0}"
$msgStartingService = "Starting service: {0}"
$msgServiceStarted = "Service started."
$msgCheckingExtractPath = "Checking extraction path: {0}"
$msgExtractPathNotExist = "Extraction path does not exist. Creating..."
$msgCleaningDirectory = "Cleaning extraction directory..."
$msgExtractingZip = "Extracting zip file..."
$msgExtractionComplete = "Extraction complete."
$msgDeletingZip = "Deleting zip file..."
$msgZipDeleted = "Zip file deleted."
$msgListingFiles = "Files extracted:"
$msgOperationComplete = "Unzip operation completed successfully!"

# Convert password to secure string
$securePassword = $Password | ConvertTo-SecureString -AsPlainText -Force

try {
    # Prepare credentials
    $cred = New-Object System.Management.Automation.PSCredential($Username, $securePassword)
    
    # Create a session
    Write-Host $msgCreatingSession
    $session = New-PSSession -ComputerName $RemoteMachine -Credential $cred -ErrorAction Stop
    
    # Execute unzip operation on remote machine
    $result = Invoke-Command -Session $session -ScriptBlock {
        param(
            $zipPath, 
            $extractPath, 
            $serviceName, 
            $cleanDir, 
            $deleteZip,
            $nssmexPort,
            $msgCheckingZip,
            $msgZipFound,
            $msgZipNotFound,
            $msgStoppingService,
            $msgServiceStopped,
            $msgServiceNotFound,
            $msgStartingService,
            $msgServiceStarted,
            $msgCheckingExtractPath,
            $msgExtractPathNotExist,
            $msgCleaningDirectory,
            $msgExtractingZip,
            $msgExtractionComplete,
            $msgDeletingZip,
            $msgZipDeleted,
            $msgListingFiles
        )
        
        try {
            # Check if zip file exists
            Write-Host $msgCheckingZip
            if (!(Test-Path $zipPath)) {
                throw ($msgZipNotFound -f $zipPath)
            }
            
            Write-Host ($msgZipFound -f $zipPath) -ForegroundColor Green
            $zipInfo = Get-Item $zipPath
            $zipSizeMB = $zipInfo.Length / 1MB
            Write-Host "Zip file size: $([math]::Round($zipSizeMB, 2)) MB"
            
            # Stop service if specified
            if ($serviceName) {
                Write-Host ($msgStoppingService -f $serviceName)
                $serviceStopped = $false
                
                # Try nssmex REST API first
                try {
                    $stopUrl = "http://localhost:${nssmexPort}/api/stop/${serviceName}"
                    Write-Host "  Trying nssmex API: $stopUrl" -ForegroundColor Gray
                    $response = Invoke-RestMethod -Uri $stopUrl -Method Get
                    Write-Host "  nssmex: $msgServiceStopped" -ForegroundColor Green
                    $serviceStopped = $true
                    Start-Sleep -Seconds 2
                } catch {
                    Write-Host "  nssmex API not available or failed" -ForegroundColor Yellow
                }
                
                # Also try Windows Services
                if (Get-Service -Name $serviceName -ErrorAction SilentlyContinue) {
                    try {
                        Stop-Service -Name $serviceName -Force -ErrorAction Stop
                        Write-Host "  Windows Service: $msgServiceStopped" -ForegroundColor Green
                        $serviceStopped = $true
                        
                        # Wait for service to fully stop
                        $timeout = 30
                        $elapsed = 0
                        while ((Get-Service -Name $serviceName).Status -ne 'Stopped' -and $elapsed -lt $timeout) {
                            Start-Sleep -Seconds 1
                            $elapsed++
                        }
                    } catch {
                        Write-Host "  Windows Service stop failed: $_" -ForegroundColor Yellow
                    }
                } else {
                    Write-Host "  Windows Service not found" -ForegroundColor Yellow
                }
                
                if (-not $serviceStopped) {
                    Write-Host "  WARNING: Could not stop service via any method" -ForegroundColor Yellow
                }
            }
            
            # Check and create extraction path if needed
            Write-Host ($msgCheckingExtractPath -f $extractPath)
            if (!(Test-Path $extractPath)) {
                Write-Host $msgExtractPathNotExist
                New-Item -Path $extractPath -ItemType Directory -Force | Out-Null
            }
            
            # Clean directory if requested
            if ($cleanDir) {
                Write-Host $msgCleaningDirectory -ForegroundColor Yellow
                Get-ChildItem -Path $extractPath | Remove-Item -Recurse -Force
            }
            
            # Extract zip file
            Write-Host $msgExtractingZip -ForegroundColor Yellow
            Add-Type -AssemblyName System.IO.Compression.FileSystem
            
            if ($VerbosePreference -eq 'Continue') {
                # Extract with progress information
                $archive = [System.IO.Compression.ZipFile]::OpenRead($zipPath)
                $totalEntries = $archive.Entries.Count
                Write-Host "Total entries to extract: $totalEntries"
                $archive.Dispose()
            }
            
            [System.IO.Compression.ZipFile]::ExtractToDirectory($zipPath, $extractPath)
            Write-Host $msgExtractionComplete -ForegroundColor Green
            
            # List extracted files if verbose
            if ($VerbosePreference -eq 'Continue') {
                Write-Host $msgListingFiles
                $files = Get-ChildItem -Path $extractPath -Recurse | Where-Object { !$_.PSIsContainer }
                $files | ForEach-Object { Write-Host "  - $($_.FullName.Replace($extractPath, '').TrimStart('\'))" }
                Write-Host "Total files extracted: $($files.Count)"
            }
            
            # Delete zip file if requested
            if ($deleteZip) {
                Write-Host $msgDeletingZip
                Remove-Item -Path $zipPath -Force
                Write-Host $msgZipDeleted -ForegroundColor Green
            }
            
            # Start service if it was stopped
            if ($serviceName) {
                Write-Host ($msgStartingService -f $serviceName)
                $serviceStarted = $false
                
                # Try nssmex REST API first
                try {
                    $startUrl = "http://localhost:${nssmexPort}/api/start/${serviceName}"
                    Write-Host "  Trying nssmex API: $startUrl" -ForegroundColor Gray
                    $response = Invoke-RestMethod -Uri $startUrl -Method Get
                    Write-Host "  nssmex: $msgServiceStarted" -ForegroundColor Green
                    $serviceStarted = $true
                } catch {
                    Write-Host "  nssmex API not available or failed" -ForegroundColor Yellow
                }
                
                # Also try Windows Services
                if (Get-Service -Name $serviceName -ErrorAction SilentlyContinue) {
                    try {
                        Start-Service -Name $serviceName -ErrorAction Stop
                        Write-Host "  Windows Service: $msgServiceStarted" -ForegroundColor Green
                        $serviceStarted = $true
                    } catch {
                        Write-Host "  Windows Service start failed: $_" -ForegroundColor Yellow
                    }
                } else {
                    Write-Host "  Windows Service not found" -ForegroundColor Yellow
                }
                
                if (-not $serviceStarted) {
                    Write-Host "  WARNING: Could not start service via any method" -ForegroundColor Yellow
                }
            }
            
            return $true
            
        } catch {
            # Attempt to restart service on error if it was stopped
            if ($serviceName) {
                # Try nssmex REST API
                try {
                    $startUrl = "http://localhost:${nssmexPort}/api/start/${serviceName}"
                    Invoke-RestMethod -Uri $startUrl -Method Get
                } catch {
                    # Ignore errors during cleanup
                }
                
                # Try Windows Services
                if (Get-Service -Name $serviceName -ErrorAction SilentlyContinue) {
                    if ((Get-Service -Name $serviceName).Status -eq 'Stopped') {
                        Start-Service -Name $serviceName -ErrorAction SilentlyContinue
                    }
                }
            }
            throw $_
        }
    } -ArgumentList $RemoteZipPath, $RemoteExtractPath, $ServiceName, $CleanDirectory, $DeleteZipAfterExtraction, `
                     $NssmexPort, $msgCheckingZip, $msgZipFound, $msgZipNotFound, $msgStoppingService, `
                     $msgServiceStopped, $msgServiceNotFound, $msgStartingService, $msgServiceStarted, `
                     $msgCheckingExtractPath, $msgExtractPathNotExist, $msgCleaningDirectory, `
                     $msgExtractingZip, $msgExtractionComplete, $msgDeletingZip, $msgZipDeleted, `
                     $msgListingFiles
    
    # Clean up session
    Remove-PSSession $session
    
    # Play a beep sound if enabled
    if ($EnableBeep) {
        [console]::beep($BeepFrequency, $BeepDuration)
    }
    
    Write-Host $msgOperationComplete -ForegroundColor Green
    
} catch {
    Write-Error "An error occurred: $_"
    if ($session) {
        Remove-PSSession $session -ErrorAction SilentlyContinue
    }
    exit 1
}