Public/VM/Import-VergeVM.ps1

function Import-VergeVM {
    <#
    .SYNOPSIS
        Imports a virtual machine from a VergeOS YBVM file.

    .DESCRIPTION
        Import-VergeVM creates a new VM by importing from a YBVM (VergeOS native VM)
        file. The file must already be uploaded to the VergeOS media catalog.

        For OVA/OVF/VMDK files, use New-VergeVM to create a VM, then use
        Import-VergeDrive to import the disk image as a drive.

    .PARAMETER FileKey
        The key (ID) of the YBVM file to import. Use Get-VergeFile -Type ybvm.

    .PARAMETER FileName
        The name of the YBVM file to import.

    .PARAMETER File
        A file object from Get-VergeFile. Accepts pipeline input.

    .PARAMETER Name
        The name for the new VM. If not specified, the name from the file is used.

    .PARAMETER PreserveMACAddresses
        Preserve the MAC addresses from the import file. Default is true.

    .PARAMETER PreserveDriveFormat
        Keep the original drive format instead of converting to raw. Default is false.

    .PARAMETER Tier
        The preferred storage tier (1-5) for the imported VM's drives.

    .PARAMETER Wait
        Wait for the import to complete before returning.

    .PARAMETER Timeout
        Maximum time in seconds to wait for import completion. Default is 600 (10 minutes).

    .PARAMETER PassThru
        Return the import job object (or VM object if -Wait is specified).

    .PARAMETER Server
        The VergeOS connection to use. Defaults to the current default connection.

    .EXAMPLE
        Import-VergeVM -FileName "backup-webserver.ybvm" -Name "WebServer-Restored"

        Imports a YBVM file as a new VM.

    .EXAMPLE
        Get-VergeFile -Type ybvm | Import-VergeVM -Wait -PassThru

        Imports all YBVM files and waits for completion.

    .EXAMPLE
        Import-VergeVM -FileKey 123 -Tier 1 -Wait

        Imports a YBVM file to Tier 1 storage and waits for completion.

    .OUTPUTS
        Verge.VMImport object by default. Verge.VM when -Wait and -PassThru are specified.

    .NOTES
        This cmdlet imports YBVM (VergeOS native) files only.
        For OVA/OVF/VMDK imports, create a VM first with New-VergeVM, then use
        Import-VergeDrive to add the disk image.
        Use Get-VergeFile -Type ybvm to see importable VM files.
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'ByFileName')]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory, ParameterSetName = 'ByFileKey')]
        [int]$FileKey,

        [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByFileName')]
        [string]$FileName,

        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'ByFile')]
        [PSTypeName('Verge.File')]
        [PSCustomObject]$File,

        [Parameter()]
        [ValidateLength(1, 128)]
        [string]$Name,

        [Parameter()]
        [bool]$PreserveMACAddresses = $true,

        [Parameter()]
        [switch]$PreserveDriveFormat,

        [Parameter()]
        [ValidateRange(1, 5)]
        [ValidateScript({
            if ($_ -eq 0) {
                throw "Tier 0 is reserved for system metadata and cannot be used for VM drives."
            }
            $true
        })]
        [int]$Tier,

        [Parameter()]
        [switch]$Wait,

        [Parameter()]
        [ValidateRange(30, 3600)]
        [int]$Timeout = 600,

        [Parameter()]
        [switch]$PassThru,

        [Parameter()]
        [object]$Server
    )

    begin {
        # Resolve connection
        if (-not $Server) {
            $Server = $script:DefaultConnection
        }
        if (-not $Server) {
            throw [System.InvalidOperationException]::new(
                'Not connected to VergeOS. Use Connect-VergeOS to establish a connection.'
            )
        }
    }

    process {
        # Resolve file key
        $targetFileKey = $null
        $targetFileName = $null
        $targetFileType = $null

        switch ($PSCmdlet.ParameterSetName) {
            'ByFileKey' {
                $targetFileKey = $FileKey
                try {
                    $fileInfo = Get-VergeFile -Key $FileKey -Server $Server
                    $targetFileName = $fileInfo.Name
                    $targetFileType = $fileInfo.Type
                }
                catch {
                    $targetFileName = "File $FileKey"
                }
            }
            'ByFileName' {
                $fileInfo = Get-VergeFile -Name $FileName -Server $Server | Select-Object -First 1
                if (-not $fileInfo) {
                    Write-Error -Message "File '$FileName' not found in media catalog" -ErrorId 'FileNotFound'
                    return
                }
                $targetFileKey = $fileInfo.Key
                $targetFileName = $fileInfo.Name
                $targetFileType = $fileInfo.Type
            }
            'ByFile' {
                $targetFileKey = $File.Key
                $targetFileName = $File.Name
                $targetFileType = $File.Type
            }
        }

        if (-not $targetFileKey) {
            Write-Error -Message "Could not resolve file for import" -ErrorId 'FileNotResolved'
            return
        }

        # Validate file type
        if ($targetFileType -and $targetFileType -ne 'ybvm') {
            Write-Error -Message "Import-VergeVM only supports YBVM files. File '$targetFileName' is type '$targetFileType'. For OVA/OVF/VMDK files, create a VM with New-VergeVM and use Import-VergeDrive to add the disk." -ErrorId 'InvalidFileType'
            return
        }

        # Build import request body
        $body = @{
            file                  = $targetFileKey
            preserve_macs         = $PreserveMACAddresses
            preserve_drive_format = $PreserveDriveFormat.IsPresent
        }

        if ($Name) {
            $body['name'] = $Name
        }

        if ($Tier) {
            $body['preferred_tier'] = $Tier.ToString()
        }

        $vmName = if ($Name) { $Name } else { $targetFileName }

        if ($PSCmdlet.ShouldProcess($targetFileName, "Import VM as '$vmName'")) {
            try {
                Write-Verbose "Starting import from '$targetFileName' (Key: $targetFileKey)"
                $response = Invoke-VergeAPI -Method POST -Endpoint 'vm_imports' -Body $body -Connection $Server

                if (-not $response) {
                    Write-Error -Message "Failed to start import - no response from API" -ErrorId 'ImportStartFailed'
                    return
                }

                $importId = $response.id ?? $response.'$key'
                Write-Verbose "Import job created with ID: $importId"

                if ($Wait) {
                    Write-Verbose "Waiting for import to complete (timeout: ${Timeout}s)..."
                    $startTime = Get-Date
                    $lastStatus = ''

                    while ($true) {
                        Start-Sleep -Seconds 3

                        $importStatus = Invoke-VergeAPI -Method GET -Endpoint "vm_imports/$importId" -Connection $Server

                        if ($importStatus.status -ne $lastStatus) {
                            $lastStatus = $importStatus.status
                            Write-Verbose "Import status: $lastStatus - $($importStatus.status_info)"
                        }

                        if ($importStatus.status -eq 'complete') {
                            Write-Verbose "Import completed successfully"

                            if ($PassThru -and $importStatus.vm) {
                                Get-VergeVM -Key $importStatus.vm -Server $Server
                            }
                            elseif ($PassThru) {
                                [PSCustomObject]@{
                                    PSTypeName  = 'Verge.VMImport'
                                    Id          = $importId
                                    Name        = $importStatus.name
                                    Status      = $importStatus.status
                                    StatusInfo  = $importStatus.status_info
                                    VMKey       = $importStatus.vm
                                    FileKey     = $targetFileKey
                                    FileName    = $targetFileName
                                }
                            }
                            return
                        }

                        if ($importStatus.status -in @('error', 'aborted')) {
                            Write-Error -Message "Import failed: $($importStatus.status_info)" -ErrorId 'ImportFailed'
                            return
                        }

                        $elapsed = (Get-Date) - $startTime
                        if ($elapsed.TotalSeconds -ge $Timeout) {
                            Write-Warning "Import timed out after ${Timeout}s. Import may still be running."

                            if ($PassThru) {
                                [PSCustomObject]@{
                                    PSTypeName  = 'Verge.VMImport'
                                    Id          = $importId
                                    Name        = $importStatus.name
                                    Status      = $importStatus.status
                                    StatusInfo  = $importStatus.status_info
                                    VMKey       = $importStatus.vm
                                    FileKey     = $targetFileKey
                                    FileName    = $targetFileName
                                }
                            }
                            return
                        }
                    }
                }
                else {
                    if ($PassThru) {
                        [PSCustomObject]@{
                            PSTypeName  = 'Verge.VMImport'
                            Id          = $importId
                            Name        = $response.name ?? $vmName
                            Status      = $response.status ?? 'initializing'
                            StatusInfo  = $response.status_info
                            VMKey       = $response.vm
                            FileKey     = $targetFileKey
                            FileName    = $targetFileName
                        }
                    }
                    else {
                        Write-Verbose "Import started. Use -Wait to monitor progress."
                    }
                }
            }
            catch {
                Write-Error -Message "Failed to import VM from '$targetFileName': $($_.Exception.Message)" -ErrorId 'ImportFailed'
            }
        }
    }
}