Common/Common.psm1

using module './Result'
Import-Module -Name @(Join-Path $PSScriptRoot Wrappers | Join-Path -ChildPath Wrappers)
Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath Util | Join-Path -ChildPath Util)
Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath Util | Join-Path -ChildPath MigrationUtil)
Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath RiverMeadow.Development.Source | Join-Path -ChildPath SourceUtil | Join-Path -ChildPath SourceUtil)
function Confirm-RMCommonParameter {
    param (
        [hashtable] $UserParameter
    )
    $Errors = @()
    $Warnings = @()
    $IsSourceAndTargetCloudPresent = $true
    if (!$UserParameter.ContainsKey("TargetCloud") -or [string]::IsNullOrEmpty($UserParameter["TargetCloud"])) {
        $Errors += "TargetCloud is required"
        $IsSourceAndTargetCloudPresent = $false
    }
    if (!$UserParameter.ContainsKey("SourceIP") -or [string]::IsNullOrEmpty($UserParameter["SourceIP"])) {
        $Errors += "SourceIP is required"
        $IsSourceAndTargetCloudPresent = $false
    } else {
        $IsValidIPAddress = Confirm-RMIPAddress -IPAddress $UserParameter.SourceIP
        if (!$IsValidIPAddress) {
            $Errors += "Invalid Source IP address."
            $IsSourceAndTargetCloudPresent = $false
        }
    }

    if (!$UserParameter.ContainsKey("TargetVMName") -or [string]::IsNullOrEmpty($UserParameter["TargetVMName"])) {
        $Warnings += "TargetVMName has not been provided, source hostname will be used as the target VM name"
    }

    $Errors += Confirm-RMSchedule -UserParameter $UserParameter
    return $Errors, $Warnings, $IsSourceAndTargetCloudPresent
}

function Confirm-RMVMBasedCommonParameter {
    param (
        [hashtable] $UserParameter
    )
    $Errors = @()
    $Warnings = @()
    $IsSourcePresent = $true
    if (!$UserParameter.ContainsKey("SourceVMName") -or [string]::IsNullOrEmpty($UserParameter["SourceVMName"])) {
        $Errors += "SourceVMName is required"
        $IsSourcePresent = $false
    } elseif (!$UserParameter.ContainsKey("TargetVMName") -or [string]::IsNullOrEmpty($UserParameter["TargetVMName"])) {
        $Warnings += "TargetVMName has not been provided, source hostname will be used as the target VM name"
    }

    if (!$UserParameter.ContainsKey("TargetCloud") -or [string]::IsNullOrEmpty($UserParameter["TargetCloud"])) {
        $Errors += "TargetCloud is required"
        $IsSourcePresent = $false
    }

    $Errors += Confirm-RMSchedule -UserParameter $UserParameter
    return $Errors, $Warnings, $IsSourcePresent
}

function Confirm-RMVMBasedDMCommonParameter {
    param(
        [hashtable] $UserParameter
    )
    $Errors = @()
    $IsValidMigrationId = $true
    if (!$UserParameter.ContainsKey("MigrationId") -or [string]::IsNullOrWhiteSpace($UserParameter["MigrationId"])) {
        $Errors += "MigrationId is required"
        $IsValidMigrationId = $false
    }

    if ($UserParameter.ContainsKey("RunContinuous") `
            -and $UserParameter.ContainsKey("ScheduledAt") `
            -and ![string]::IsNullOrWhiteSpace($UserParameter["ScheduledAt"])) {
        $Errors += "Parameters 'RunContinuous' and 'ScheduledAt' cannot be used at the same time."
    }
    
    $Errors += Confirm-RMSchedule -UserParameter $UserParameter
    return $Errors, $IsValidMigrationId
}

function Confirm-RMSchedule {
    param(
        [hashtable] $UserParameter
    )
    $Errors = @()
    if ($UserParameter.ContainsKey("ScheduledAt") -or ![string]::IsNullOrEmpty($UserParameter["ScheduledAt"])) {
        $IsValidDateTime = Confirm-RMDateFormat -InputDate $UserParameter["ScheduledAt"] -DateFormat "MM/dd/yyyy HH:mm"
        if ($IsValidDateTime) {
            if (!(Confirm-RMAfterCurrentDateTime -InputDateTime $UserParameter["ScheduledAt"])) {
                $Errors += "ScheduledAt date and time should be greater than the current date and time"
            }
        } else {
            $Errors += "ScheduledAt should have the date and time in the format 'MM/dd/yyyy HH:mm' with valid values for date and time"
        }
    }

    return $Errors
}

function Confirm-RMCommonParameterWithSource {
    param (
        [hashtable] $UserParameter,
        [System.Object] $Source
    )
    $Errors = @()
    if ($UserParameter.ContainsKey("MountPoints") -and $UserParameter["MountPoints"].Count -gt 0) {
        $SourceMountPoints = Get-MountPoint -Source $Source
        $Errors += Compare-RMMountPoint -Source $Source -SourceMountPoints $SourceMountPoints.Values `
            -UserInputMountPoints $UserParameter["MountPoints"] -ParameterName "MountPoints"

        $NonExistsMountPoints = Test-RMNonExistentMountPoints -SourceMountPoints $SourceMountPoints.Values -UserInputMountPoints $UserParameter["MountPoints"]
        if ($NonExistsMountPoints.Count -gt 0) {
            $NonExistsMountPointsAsString =  $NonExistsMountPoints -join ", "
            $Errors += "'$NonExistsMountPointsAsString' does not exist on the source."
        }
    }

    if ($UserParameter.ContainsKey("UpgradeOSVersion") -and ![string]::IsNullOrEmpty($UserParameter["UpgradeOSVersion"])) {
        $UpgradeOSVersion = $UserParameter["UpgradeOSVersion"]
        $SourceOSMMapping = Get-RMOSMMappingBySource -Source $Source
        if ($SourceOSMMapping.Keys.Count -eq 0) {
            $Errors += "No OS upgrade options are available for the given source OS"
            return $Errors
        }
        $OSMLabels = $SourceOSMMapping.keys -join ", "
        $UpgradeOSVersion = $UpgradeOSVersion.Trim('"')
        $UpgradeOSVersion = $UpgradeOSVersion.Trim("'")
        if ($SourceOSMMapping.keys -notcontains $UpgradeOSVersion) {
            $Errors += "UpgradeOSVersion should be one of '$OSMLabels'"
        }
    }

    return $Errors
}

function Out-RMUserParameterResult {
    param (
        [string[]] $ErrorMessage,
        [string[]] $WarningMessage
    )

    foreach ($Warning in $WarningMessage) {
        Write-Warning -Message $Warning
    }

    if ($ErrorMessage.Count -eq 0) {
        return
    }

    foreach ($Error in $ErrorMessage) {
        Write-RMError -Message $Error
    }
}

function Update-RMMigrationReturnAsSuccess {
    param(
        [System.Object] $MigrationResponse,
        [bool] $IsScheduledMigration,
        [string] $ReturnMessage,
        [RMMigrationReturn] $RMMigrationReturn
    )
    if ($IsScheduledMigration) {
        Write-Output "Migration scheduled successfully" | Out-Host
        $RMMigrationReturn.SetReturnCode([RMReturn]::SUCCESS)
        return $RMMigrationReturn
    }
   
    $MigrationId = Get-RMMigrationIdFromResponse -Response $MigrationResponse
    Write-Output "$ReturnMessage : $MigrationId" | Out-Host
    $RMMigrationReturn.SetMigrationId($MigrationId)
    $RMMigrationReturn.SetReturnCode([RMReturn]::SUCCESS)
    return $RMMigrationReturn
}

function Update-RMMigrationReturnAsError {
    param(
        [string] $Message,
        [RMMigrationReturn] $RMMigrationReturn
    )
    Write-RMError -Message $Message
    $RMReturn = [RMReturn]::new([RMReturn]::ERROR, [RMError]::new($Message), $null, $null)
    $RMMigrationReturn.SetRMReturn($RMReturn)
    return $RMMigrationReturn
}