[CmdletBinding()]
param(
    [Parameter(Mandatory=$true, HelpMessage="Name of the application to release")]
    [string]$AppName,
    
    [Parameter(Mandatory=$true, HelpMessage="Local service name")]
    [string]$ServiceName,
    
    [Parameter(Mandatory=$true, HelpMessage="Local extraction path")]
    [string]$LocalExtractPath,
    
    [Parameter(HelpMessage="Build configuration (Debug/Release)")]
    [string]$PublishConfig = 'Release',
    
    [Parameter(HelpMessage="Target runtime")]
    [string]$Runtime = 'win-x64',
    
    [Parameter(HelpMessage="Self-contained deployment")]
    [bool]$SelfContained = $true,
    
    [Parameter(HelpMessage="Target .NET framework version")]
    [string]$TargetFramework = "net8.0",
    
    [Parameter(HelpMessage="Local zip file path")]
    [string]$LocalZipPath,
    
    [Parameter(HelpMessage="Local publish subfolder path")]
    [string]$PublishSubPath,
    
    [Parameter(HelpMessage="Project path to publish (optional)")]
    [string]$ProjectPath = "",
    
    [Parameter(HelpMessage="Enable beep notification on completion")]
    [switch]$EnableBeep,
    
    [Parameter(HelpMessage="Beep frequency in Hz")]
    [int]$BeepFrequency = 1000,
    
    [Parameter(HelpMessage="Beep duration in milliseconds")]
    [int]$BeepDuration = 500
)

# Set default LocalZipPath if not provided
if (-not $LocalZipPath) {
    $LocalZipPath = "C:\services\$AppName.zip"
}

# Set default PublishSubPath if not provided
if (-not $PublishSubPath) {
    $PublishSubPath = "bin/$PublishConfig/$TargetFramework/$Runtime/publish"
}

# Validate required parameters
if ([string]::IsNullOrWhiteSpace($AppName)) {
    Write-Error "AppName parameter is required"
    exit 1
}

if ([string]::IsNullOrWhiteSpace($ServiceName)) {
    Write-Error "ServiceName parameter is required"
    exit 1
}

if ([string]::IsNullOrWhiteSpace($LocalExtractPath)) {
    Write-Error "LocalExtractPath parameter is required"
    exit 1
}

# Messages
$msgStoppingService = "Stopping local service: $ServiceName"
$msgStartingService = "Starting local service: $ServiceName"
$msgPublishNotFound = "Publish folder not found: {0}"
$msgServiceStopped = "Service stopped."
$msgServiceStarted = "Service started."
$msgServiceNotFound = "Service not found: {0}"
$msgCheckingExtractPath = "Checking if extract path exists: {0}"
$msgExtractPathNotExist = "Extract path does not exist. Creating..."
$msgZipFound = "Zip file found: {0}"
$msgZipNotFound = "Zip file not found: {0}"
$msgRemovingFiles = "Removing all files and folders in extract path..."
$msgExtractingZip = "Extracting zip file..."
$msgExtractionComplete = "Extraction complete."
$msgPublishing = "Publishing $AppName..."
$msgCreatingZip = "Creating zip file for $AppName..."

# Determine zip file name
$zipFileName = "$AppName.zip"

try {
    Write-Host $msgPublishing -ForegroundColor Cyan
    
    # Build dotnet publish command
    $publishArgs = @("-c", $PublishConfig, "-r", $Runtime)
    if ($SelfContained) {
        $publishArgs += "--self-contained", "true"
    } else {
        $publishArgs += "--self-contained", "false"
    }
    
    # Add project path if provided
    if ($ProjectPath) {
        $publishArgs += $ProjectPath
    }
    
    # Publish the .NET app
    dotnet publish @publishArgs
    
    if ($LASTEXITCODE -ne 0) {
        Write-Error "dotnet publish failed with exit code $LASTEXITCODE"
        exit 1
    }

    # Zip the publish folder
    if ($ProjectPath) {
        $publishPath = Join-Path -Path $ProjectPath -ChildPath $PublishSubPath
    } else {
        $publishPath = Join-Path -Path (Get-Location) -ChildPath $PublishSubPath
    }
    $zipPath = Join-Path -Path (Get-Location) -ChildPath $zipFileName
    
    if (Test-Path $zipPath) { 
        Remove-Item $zipPath -Force 
    }
    
    if (Test-Path $publishPath) {
        Write-Host $msgCreatingZip -ForegroundColor Cyan
        Compress-Archive -Path "$publishPath\*" -DestinationPath $zipPath -Force

        # Stop the service locally
        Write-Host $msgStoppingService -ForegroundColor Yellow
        if (Get-Service -Name $ServiceName -ErrorAction SilentlyContinue) {
            Stop-Service -Name $ServiceName -Force -ErrorAction SilentlyContinue
            Write-Host $msgServiceStopped -ForegroundColor Green
        } else {
            Write-Host ($msgServiceNotFound -f $ServiceName) -ForegroundColor Yellow
        }
        
        # Copy zip file locally
        Write-Host "Copying zip file to: $LocalZipPath" -ForegroundColor Cyan
        Copy-Item -Path $zipPath -Destination $LocalZipPath -Force
        
        # Extract locally
        Write-Host ($msgCheckingExtractPath -f $LocalExtractPath) -ForegroundColor Cyan
        if (!(Test-Path $LocalExtractPath)) {
            Write-Host $msgExtractPathNotExist -ForegroundColor Yellow
            New-Item -Path $LocalExtractPath -ItemType Directory | Out-Null
        }
        
        if (Test-Path $LocalZipPath) {
            Write-Host ($msgZipFound -f $LocalZipPath) -ForegroundColor Green
            Write-Host $msgRemovingFiles -ForegroundColor Yellow
            Get-ChildItem -Path $LocalExtractPath | Remove-Item -Recurse -Force
            Write-Host $msgExtractingZip -ForegroundColor Cyan
            Add-Type -AssemblyName System.IO.Compression.FileSystem
            [System.IO.Compression.ZipFile]::ExtractToDirectory($LocalZipPath, $LocalExtractPath)
            Write-Host $msgExtractionComplete -ForegroundColor Green
        } else {
            Write-Host ($msgZipNotFound -f $LocalZipPath) -ForegroundColor Red
        }
        
        # Start the service locally
        Write-Host $msgStartingService -ForegroundColor Yellow
        if (Get-Service -Name $ServiceName -ErrorAction SilentlyContinue) {
            Start-Service -Name $ServiceName -ErrorAction SilentlyContinue
            Write-Host $msgServiceStarted -ForegroundColor Green
        } else {
            Write-Host ($msgServiceNotFound -f $ServiceName) -ForegroundColor Yellow
        }

        # Remove the zip file after publishing
        if (Test-Path $zipPath) { 
            Remove-Item $zipPath -Force 
        }

        # Play a beep sound if enabled
        if ($EnableBeep) {
            [console]::beep($BeepFrequency, $BeepDuration)
        }
        
        Write-Host ""
        Write-Host "Successfully deployed $AppName locally" -ForegroundColor Green
        Write-Host "Service: $ServiceName" -ForegroundColor Green
        Write-Host "Location: $LocalExtractPath" -ForegroundColor Green
    } else {
        Write-Host ($msgPublishNotFound -f $publishPath) -ForegroundColor Red
        exit 1
    }
} catch {
    Write-Error "An error occurred: $_"
    exit 1
}