# Samy.SVSBootstrap.ps1
# SVSMSP toolkit bootstrap and cleanup

function Initialize-NuGetProvider {
    [CmdletBinding()]
    param()

    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    $ProgressPreference = 'SilentlyContinue'
    $ConfirmPreference  = 'None'

    $provPath = "$env:ProgramData\PackageManagement\ProviderAssemblies"
    if (-not (Test-Path $provPath)) {
        try {
            New-Item -Path $provPath -ItemType Directory -Force -ErrorAction Stop | Out-Null
            Write-LogHybrid "Created missing provider folder: $provPath" Info Bootstrap -LogToEvent
        }
        catch {
            Write-LogHybrid "Failed to create provider folder: $($_.Exception.Message)" Warning Bootstrap -LogToEvent
        }
    }

    if (-not (Get-Command Install-PackageProvider -ErrorAction SilentlyContinue)) {
        try {
            Install-Module PowerShellGet -Force -AllowClobber -Confirm:$false -ErrorAction Stop
            Write-LogHybrid "Installed PowerShellGet module" Info Bootstrap -LogToEvent
        }
        catch {
            Write-LogHybrid "PowerShellGet install failed: $($_.Exception.Message)" Error Bootstrap -LogToEvent
        }
    }

    $pkgMgmtVersion = (Get-Module PackageManagement -ListAvailable | Sort-Object Version -Descending | Select-Object -First 1).Version
    if ($pkgMgmtVersion -lt [Version]"1.3.1") {
        try {
            Install-Module PackageManagement -Force -AllowClobber -Confirm:$false -ErrorAction Stop
            Write-LogHybrid "Updated PackageManagement to latest version" Info Bootstrap -LogToEvent
        }
        catch {
            Write-LogHybrid "PackageManagement update failed: $($_.Exception.Message)" Warning Bootstrap -LogToEvent
        }
    }

    Import-Module PackageManagement -Force -ErrorAction SilentlyContinue | Out-Null
    Import-Module PowerShellGet     -Force -ErrorAction SilentlyContinue | Out-Null

    $gallery = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue
    if ($gallery -and $gallery.InstallationPolicy -ne 'Trusted') {
        try {
            Set-PSRepository -Name PSGallery -InstallationPolicy Trusted -ErrorAction Stop
            Write-LogHybrid "PSGallery marked as Trusted" Info Bootstrap -LogToEvent
        }
        catch {
            Write-LogHybrid "Failed to trust PSGallery: $($_.Exception.Message)" Warning Bootstrap -LogToEvent
        }
    }

    $nuget = Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue
    if (-not $nuget) {
        try {
            Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$false -ErrorAction Stop
            $nuget = Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue
            Write-LogHybrid "Installed NuGet provider v$($nuget.Version)" Info Bootstrap -LogToEvent
        }
        catch {
            Write-LogHybrid "NuGet install failed: $($_.Exception.Message)" Error Bootstrap -LogToEvent
        }
    }
    else {
        Write-LogHybrid "NuGet provider already present (v$($nuget.Version))" Info Bootstrap -LogToEvent
    }

    try {
        Import-PackageProvider -Name NuGet -Force -ErrorAction Stop | Out-Null
    }
    catch {
        Write-LogHybrid "NuGet provider import failed: $($_.Exception.Message)" Error Bootstrap -LogToEvent
    }
}

function Install-SVSMSP {
    param (
        [switch] $Cleanup,
        [switch] $InstallToolkit,
        [Parameter(Mandatory = $false)][array]   $AllModules       = @(@{ ModuleName = "SVS_Toolkit" }, @{ ModuleName = "SVSMSP" }),
        [Parameter(Mandatory = $false)][array]   $AllRepositories  = @(@{ RepoName = "SVS_Repo" }, @{ RepoName = "SVS_Toolkit" }),
        [Parameter(Mandatory = $false)][string]  $NewModuleName    = "SVSMSP",
        [Parameter(Mandatory = $false)][string]  $NewRepositoryName = "SVS_Repo",
        [Parameter(Mandatory = $false)][string]  $NewRepositoryURL  = "http://proget.svstools.ca:8083/nuget/SVS_Repo/"
    )

    function Start-Cleanup {
        Write-LogHybrid "Cleanup mode enabled. Starting cleanup..." Info SVSModule

        try {
            Uninstall-Module -Name SVSMSP -AllVersions -Force -ErrorAction Stop
            Write-LogHybrid "SVSMSP module uninstalled from system." Success SVSModule -LogToEvent
        }
        catch {
            if ($_.Exception.Message -match 'No match was found') {
                Write-LogHybrid "No existing SVSMSP module found to uninstall." Warning SVSModule -LogToEvent
            }
            else {
                Write-LogHybrid "Failed to uninstall SVSMSP: $($_.Exception.Message)" Error SVSModule -LogToEvent
            }
        }

        if (Get-PSRepository -Name SVS_Repo -ErrorAction SilentlyContinue) {
            try {
                Unregister-PSRepository -Name SVS_Repo -ErrorAction Stop
                Write-LogHybrid "SVS_Repo repository unregistered." Success SVSModule -LogToEvent
            }
            catch {
                Write-LogHybrid "Failed to unregister SVS_Repo: $($_.Exception.Message)" Error SVSModule -LogToEvent
            }
        }

        if (Get-Module -Name SVSMSP) {
            try {
                Remove-Module SVSMSP -Force -ErrorAction Stop
                Write-LogHybrid "SVSMSP module removed from current session." Success SVSModule -LogToEvent
            }
            catch {
                Write-LogHybrid "Failed to remove SVSMSP from session: $($_.Exception.Message)" Error SVSModule -LogToEvent
            }
        }

        $cscePath = 'C:\CSCE'
        if (Test-Path $cscePath) {
            try {
                Remove-Item -Path $cscePath -Recurse -Force
                Write-LogHybrid "Deleted '$cscePath' contents." Success SVSModule -LogToEvent
            }
            catch {
                Write-LogHybrid "Failed to delete '$cscePath': $($_.Exception.Message)" Warning SVSModule -LogToEvent
            }
        }
    }

    function Remove-SVSDeploymentRegKey {
        $regKey = 'HKLM:\Software\SVS'

        try {
            if (Test-Path $regKey) {
                Remove-Item -Path $regKey -Recurse -Force
                Write-LogHybrid "Registry key '$regKey' deleted successfully." Success SVSModule -LogToEvent
            }
            else {
                Write-LogHybrid "Registry key '$regKey' not found; nothing to delete." Info SVSModule -LogToEvent
            }
        }
        catch {
            Write-LogHybrid "Failed to delete registry key '$regKey': $($_.Exception.Message)" Error SVSModule -LogToEvent
        }
    }

    function Repair-SVSMspEventLogBinding {
        param(
            [string]$EventSource = "SVSMSP_Module",
            [string]$TargetLog   = "SVSMSP Events"
        )

        Write-LogHybrid "Checking Event Log binding for source '$EventSource'..." Info SVSModule -LogToEvent

        try {
            if (-not [System.Diagnostics.EventLog]::SourceExists($EventSource)) {
                Write-LogHybrid "Event source '$EventSource' not found. Nothing to repair." Info SVSModule -LogToEvent
                return
            }

            $currentLog = [System.Diagnostics.EventLog]::LogNameFromSourceName($EventSource, '.')
        }
        catch {
            Write-LogHybrid "Failed to query Event Log binding for '$EventSource': $($_.Exception.Message)" Warning SVSModule -LogToEvent
            return
        }

        if (-not $currentLog) {
            Write-LogHybrid "Could not determine current log for event source '$EventSource'. Skipping repair." Warning SVSModule -LogToEvent
            return
        }

        if ($currentLog -eq $TargetLog) {
            Write-LogHybrid "Event source '$EventSource' already bound to '$TargetLog'." Info SVSModule -LogToEvent
            return
        }

        Write-LogHybrid "Rebinding event source '$EventSource' from '$currentLog' to '$TargetLog'..." Warning SVSModule -LogToEvent

        try {
            [System.Diagnostics.EventLog]::DeleteEventSource($EventSource)

            if (-not [System.Diagnostics.EventLog]::Exists($TargetLog)) {
                New-EventLog -LogName $TargetLog -Source $EventSource -ErrorAction Stop
            }
            else {
                New-EventLog -LogName $TargetLog -Source $EventSource -ErrorAction Stop
            }

            Write-LogHybrid "Event source '$EventSource' rebound to '$TargetLog'." Success SVSModule -LogToEvent
        }
        catch {
            Write-LogHybrid "Failed to rebind event source '$EventSource' to log '$TargetLog': $($_.Exception.Message)" Error SVSModule -LogToEvent
        }
    }

    function Start-ToolkitInstallation {
        Initialize-NuGetProvider
        Start-Cleanup

        Write-LogHybrid "Registering repo $NewRepositoryName..." Info SVSModule -LogToEvent
        if (-not (Get-PSRepository -Name $NewRepositoryName -ErrorAction SilentlyContinue)) {
            Register-PSRepository -Name $NewRepositoryName -SourceLocation $NewRepositoryURL -InstallationPolicy Trusted
        }

        Write-LogHybrid "Installing module $NewModuleName..." Info SVSModule -LogToEvent
        Install-Module -Name $NewModuleName -Repository $NewRepositoryName -Scope AllUsers -Force

        Repair-SVSMspEventLogBinding -EventSource "SVSMSP_Module" -TargetLog "SVSMSP Events"

        Write-LogHybrid "Toolkit installation completed." Success SVSModule -LogToEvent
    }

    Write-LogHybrid "Install-SVSMSP called" Info SVSModule -LogToEvent

    if ($Cleanup) {
        Start-Cleanup
        Remove-SVSDeploymentRegKey
        return
    }

    if ($InstallToolkit) {
        Start-ToolkitInstallation
        return
    }

    Start-ToolkitInstallation
}
