Public/cloud-market.ps1

function Get-CloudMarket {
    <#
    .SYNOPSIS
        Gets markets from the Cloud Server.
     
    .DESCRIPTION
        Retrieves a list of markets. Automatically handles token refresh.
     
    .PARAMETER Name
        Optional. Filter by market name.
     
    .PARAMETER ID
        Optional. Filter by market ID
     
    .EXAMPLE
        # Get all markets
        Get-CloudMarket
         
    .EXAMPLE
        # Get market by ID
        Get-CloudMarket -ID 5
         
    .EXAMPLE
        # Get market by name
        Get-CloudMarket -Name SoftIron
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Name,
        
        [Parameter(Mandatory = $false)]
        [Nullable[int]]$ID
    )
    
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market"
    
    if ($PSBoundParameters.ContainsKey('ID')) {
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/${ID}"
        $response = Invoke-CloudApiRequest -Uri $uri -Method Get
        $market = $response.market
        return $market
    }
    else {
        $response = Invoke-CloudApiRequest -Uri $uri -Method Get
        $markets = $response.market
        
        if ($Name) {
            $markets = $markets | Where-Object { $_.name -like "*$Name*" }
        }
        
        return $markets
    }
}

function Update-CloudMarketOwner {
    <#
    .SYNOPSIS
        Updates the ownership of a market in the Cloud Server.
     
    .DESCRIPTION
        Changes the user and/or group ownership of a market. Prompts for confirmation.
     
    .PARAMETER ID
        Required. ID of the market.
     
    .PARAMETER UserID
        Required. ID of the user to own the market.
         
    .PARAMETER GroupID
        Optional. ID of the group to own the market.
         
    .EXAMPLE
        # Update the owner of a market
        Update-CloudMarketOwner -ID 5 -UserID 2
         
    .EXAMPLE
        # Update the user and group ownership of a market
        Update-CloudMarketOwner -ID 5 -UserID 2 -GroupID 100
         
    .EXAMPLE
        # Update the user and group ownership of a market, bypassing the confirmation prompt
        Update-CloudMarketOwner -ID 5 -UserID 2 -Confirm:$false
    #>

    
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [int]$ID,
        
        [Parameter(Mandatory = $true)]
        [Alias('User')]
        [int]$UserID,
                
        [Parameter(Mandatory = $false)]
        [Alias('Group')]
        [int]$GroupID
    )
    
    process {
        # Build the update body
        $body = [PSCustomObject]@{
            user = $UserID
        }
        
        if ($PSBoundParameters.ContainsKey('GroupID')) {
            $body | Add-Member -NotePropertyName 'group' -NotePropertyValue $GroupID
        }
        
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/${ID}/ownership"
        
        # Build action description for confirmation
        $actionParts = @("Change owner to User ID $UserID")
        if ($PSBoundParameters.ContainsKey('GroupID')) {
            $actionParts += "Group ID $GroupID"
        }
        $actionDescription = $actionParts -join " and "
        
        # Use the helper function
        Invoke-CloudResourceUpdate `
            -CallerPSCmdlet $PSCmdlet `
            -ResourceType "Market" `
            -ID $ID `
            -Uri $uri `
            -Body $body `
            -Action $actionDescription `
            -GetResourceScript { Get-CloudMarket -ID $ID } `
            -SuccessMessage "Market $ID ownership updated successfully."
    }
}

function Update-CloudMarketPermissions {
    <#
    .SYNOPSIS
        Updates the permissions of a market in the Cloud Server.
     
    .DESCRIPTION
        Changes the permission of a market. Prompts for confirmation.
     
    .PARAMETER ID
        Required. ID of the market.
     
    .PARAMETER OwnerUse
        Optional. True or false, enable OwnerUse
 
    .PARAMETER OwnerManage
        Optional. True or false, enable OwnerManage
 
    .PARAMETER OwnerAdmin
        Optional. True or false, enable OwnerAdmin
 
    .PARAMETER GroupUse
        Optional. True or false, enable GroupUse
         
    .PARAMETER GroupManage
        Optional. True or false, enable GroupManage
         
    .PARAMETER GroupAdmin
        Optional. True or false, enable GroupAdmin
         
    .PARAMETER OtherUse
        Optional. True or false, enable OtherUse
         
    .PARAMETER OtherManage
        Optional. True or false, enable OtherManage
         
    .PARAMETER OtherAdmin
        Optional. True or false, enable OtherManage
         
    .EXAMPLE
        # Give group users permission to use the market
        Update-CloudMarketPermissions -ID 35 -GroupUse $true
         
    .EXAMPLE
        # Deny group admin permission to the market
        Update-CloudMarketPermissions -ID 35 -GroupAdmin $false
         
    .EXAMPLE
        # Set multiple permissions at once on a market
        Update-CloudMarketPermissions -ID 35 -GroupUse $true -GroupManage $true -OtherUse $true
    #>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [int]$ID,
        
        [Parameter(Mandatory = $false)]
        [bool]$OwnerUse,
        
        [Parameter(Mandatory = $false)]
        [bool]$OwnerManage,
        
        [Parameter(Mandatory = $false)]
        [bool]$OwnerAdmin,
        
        [Parameter(Mandatory = $false)]
        [bool]$GroupUse,
        
        [Parameter(Mandatory = $false)]
        [bool]$GroupManage,
        
        [Parameter(Mandatory = $false)]
        [bool]$GroupAdmin,
        
        [Parameter(Mandatory = $false)]
        [bool]$OtherUse,
        
        [Parameter(Mandatory = $false)]
        [bool]$OtherManage,
        
        [Parameter(Mandatory = $false)]
        [bool]$OtherAdmin
    )
    
    process {
        # Build the permissions object structure as shown in the API spec
        $permissions = @{}
        
        if ($PSBoundParameters.ContainsKey('OwnerUse')) { $permissions['owner_use'] = $OwnerUse }
        if ($PSBoundParameters.ContainsKey('OwnerManage')) { $permissions['owner_manage'] = $OwnerManage }
        if ($PSBoundParameters.ContainsKey('OwnerAdmin')) { $permissions['owner_admin'] = $OwnerAdmin }
        
        if ($PSBoundParameters.ContainsKey('GroupUse')) { $permissions['group_use'] = $GroupUse }
        if ($PSBoundParameters.ContainsKey('GroupManage')) { $permissions['group_manage'] = $GroupManage }
        if ($PSBoundParameters.ContainsKey('GroupAdmin')) { $permissions['group_admin'] = $GroupAdmin }
        
        if ($PSBoundParameters.ContainsKey('OtherUse')) { $permissions['other_use'] = $OtherUse }
        if ($PSBoundParameters.ContainsKey('OtherManage')) { $permissions['other_manage'] = $OtherManage }
        if ($PSBoundParameters.ContainsKey('OtherAdmin')) { $permissions['other_admin'] = $OtherAdmin }
        
        # Create the body with the permissions nested structure
        $body = @{
            permissions = $permissions
        }
        
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/${ID}/permissions"
        
        Invoke-CloudResourceUpdate `
            -CallerPSCmdlet $PSCmdlet `
            -ResourceType "Market" `
            -ID $ID `
            -Uri $uri `
            -Body $body `
            -Action "Update permissions" `
            -GetResourceScript { Get-CloudMarket -ID $ID }
    }
}

function Get-CloudMarketApp {
    <#
    .SYNOPSIS
        Gets market apps from the Cloud Server.
     
    .DESCRIPTION
        Retrieves a list of market apps. Automatically handles token refresh.
     
    .PARAMETER Name
        Optional. Filter by market app name.
     
    .PARAMETER ID
        Optional. Filter by market app ID
     
    .EXAMPLE
        # Get all market apps
        Get-CloudMarketApp
         
    .EXAMPLE
        # Get market app by app ID
        Get-CloudMarketApp -ID 5
         
    .EXAMPLE
        # Get market apps by app name
        Get-CloudMarketApp -Name Debian
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Name,
        
        [Parameter(Mandatory = $false)]
        [Nullable[int]]$ID
    )
    
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/app"
    
    if ($PSBoundParameters.ContainsKey('ID')) {
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/app/${ID}"
        $response = Invoke-CloudApiRequest -Uri $uri -Method Get
        
        $market = $response.application 
        return $market
    }
    else {
        $response = Invoke-CloudApiRequest -Uri $uri -Method Get
        $markets = $response.applications
        
        if ($Name) {
            $markets = $markets | Where-Object { $_.name -like "*$Name*" }
        }
        
        return $markets
    }
}

function Update-CloudMarketAppOwner {
    <#
    .SYNOPSIS
        Updates the ownership of a market app in the Cloud Server.
     
    .DESCRIPTION
        Changes the user and/or group ownership of a market app. Prompts for confirmation.
     
    .PARAMETER ID
        Required. ID of the market app.
     
    .PARAMETER UserID
        Required. ID of the user to own the market app.
         
    .PARAMETER GroupID
        Optional. ID of the group to own the market app.
         
    .EXAMPLE
        # Update the owner of a market app
        Update-CloudMarketAppOwner -ID 5 -UserID 2
         
    .EXAMPLE
        # Update the user and group ownership of a market app
        Update-CloudMarketAppOwner -ID 5 -UserID 2 -GroupID 100
         
    .EXAMPLE
        # Update the user and group ownership of a market app, bypassing the confirmation prompt
        Update-CloudMarketAppOwner -ID 5 -UserID 2 -Confirm:$false
    #>

    
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [int]$ID,
        
        [Parameter(Mandatory = $true)]
        [Alias('User')]
        [int]$UserID,
                
        [Parameter(Mandatory = $false)]
        [Alias('Group')]
        [int]$GroupID
    )
    
    process {
        # Build the update body
        $body = [PSCustomObject]@{
            user = $UserID
        }
        
        if ($PSBoundParameters.ContainsKey('GroupID')) {
            $body | Add-Member -NotePropertyName 'group' -NotePropertyValue $GroupID
        }
        
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/app/${ID}/ownership"
        
        # Build action description for confirmation
        $actionParts = @("Change owner to User ID $UserID")
        if ($PSBoundParameters.ContainsKey('GroupID')) {
            $actionParts += "Group ID $GroupID"
        }
        $actionDescription = $actionParts -join " and "
        
        # Use the helper function
        Invoke-CloudResourceUpdate `
            -CallerPSCmdlet $PSCmdlet `
            -ResourceType "Market App" `
            -ID $ID `
            -Uri $uri `
            -Body $body `
            -Action $actionDescription `
            -GetResourceScript { Get-CloudMarketApp -ID $ID } `
            -SuccessMessage "Market App $ID ownership updated successfully."
    }
}

function Update-CloudMarketAppPermissions {
    <#
    .SYNOPSIS
        Updates the permissions of a market app in the Cloud Server.
     
    .DESCRIPTION
        Changes the permission of a market app. Prompts for confirmation.
     
    .PARAMETER ID
        Required. ID of the market app.
     
    .PARAMETER OwnerUse
        Optional. True or false, enable OwnerUse
 
    .PARAMETER OwnerManage
        Optional. True or false, enable OwnerManage
 
    .PARAMETER OwnerAdmin
        Optional. True or false, enable OwnerAdmin
 
    .PARAMETER GroupUse
        Optional. True or false, enable GroupUse
         
    .PARAMETER GroupManage
        Optional. True or false, enable GroupManage
         
    .PARAMETER GroupAdmin
        Optional. True or false, enable GroupAdmin
         
    .PARAMETER OtherUse
        Optional. True or false, enable OtherUse
         
    .PARAMETER OtherManage
        Optional. True or false, enable OtherManage
         
    .PARAMETER OtherAdmin
        Optional. True or false, enable OtherManage
         
    .EXAMPLE
        # Give group users permission to use the market app
        Update-CloudMarketAppPermissions -ID 35 -GroupUse $true
         
    .EXAMPLE
        # Deny group admin permission on the market app
        Update-CloudMarketAppPermissions -ID 35 -GroupAdmin $false
         
    .EXAMPLE
        # Set multiple permissions on a market app at once
        Update-CloudMarketAppPermissions -ID 35 -GroupUse $true -GroupManage $true -OtherUse $true
    #>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [int]$ID,
        
        [Parameter(Mandatory = $false)]
        [bool]$OwnerUse,
        
        [Parameter(Mandatory = $false)]
        [bool]$OwnerManage,
        
        [Parameter(Mandatory = $false)]
        [bool]$OwnerAdmin,
        
        [Parameter(Mandatory = $false)]
        [bool]$GroupUse,
        
        [Parameter(Mandatory = $false)]
        [bool]$GroupManage,
        
        [Parameter(Mandatory = $false)]
        [bool]$GroupAdmin,
        
        [Parameter(Mandatory = $false)]
        [bool]$OtherUse,
        
        [Parameter(Mandatory = $false)]
        [bool]$OtherManage,
        
        [Parameter(Mandatory = $false)]
        [bool]$OtherAdmin
    )
    
    process {
        # Build the permissions object structure as shown in the API spec
        $permissions = @{}
        
        if ($PSBoundParameters.ContainsKey('OwnerUse')) { $permissions['owner_use'] = $OwnerUse }
        if ($PSBoundParameters.ContainsKey('OwnerManage')) { $permissions['owner_manage'] = $OwnerManage }
        if ($PSBoundParameters.ContainsKey('OwnerAdmin')) { $permissions['owner_admin'] = $OwnerAdmin }
        
        if ($PSBoundParameters.ContainsKey('GroupUse')) { $permissions['group_use'] = $GroupUse }
        if ($PSBoundParameters.ContainsKey('GroupManage')) { $permissions['group_manage'] = $GroupManage }
        if ($PSBoundParameters.ContainsKey('GroupAdmin')) { $permissions['group_admin'] = $GroupAdmin }
        
        if ($PSBoundParameters.ContainsKey('OtherUse')) { $permissions['other_use'] = $OtherUse }
        if ($PSBoundParameters.ContainsKey('OtherManage')) { $permissions['other_manage'] = $OtherManage }
        if ($PSBoundParameters.ContainsKey('OtherAdmin')) { $permissions['other_admin'] = $OtherAdmin }
        
        # Create the body with the permissions nested structure
        $body = @{
            permissions = $permissions
        }
        
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/app/${ID}/permissions"
        
        Invoke-CloudResourceUpdate `
            -CallerPSCmdlet $PSCmdlet `
            -ResourceType "Market App" `
            -ID $ID `
            -Uri $uri `
            -Body $body `
            -Action "Update permissions" `
            -GetResourceScript { Get-CloudMarketApp -ID $ID }
    }
}

function New-CloudMarket {
    <#
    .SYNOPSIS
        Creates a new cloud market on the Cloud Server.
     
    .DESCRIPTION
        Creates a new cloud market. Automatically handles token refresh.
     
    .PARAMETER Name
        Required. Display name of the new market
     
    .PARAMETER Type
        Required. The type of market.
         
    .PARAMETER Description
        Optional. If type is S3, use this to define the description of the marketplace. String must not include spaces.
         
    .PARAMETER Endpoint
        Required. The full URL of the market, including credentials if applicable. For S3, this is just the base URL, i.e. https://s3.cloud.com
         
    .PARAMETER S3Key
        Optional. If type is S3, this is the access key.
         
    .PARAMETER S3Secret
        Optional. If type is S3, this is the secret key.
         
    .PARAMETER S3Region
        Optional. If type is S3, this is the region used.
         
    .PARAMETER S3Bucket
        Optional. If type is S3, this is the bucket used.
             
    .EXAMPLE
        # Create a new market backed by SoftIron's community marketplace. Requires credentials
        New-CloudMarket -Name "NewMarket" -Type static -Endpoint "https://USERNAME:PASSWORD@marketplace.softiron.cloud/community/metadata/
 
    .EXAMPLE
        # Create a new market backed by an existing S3 bucket
        New-CloudMarket -Name "S3-Market" -Type s3 -Description "S3-Market" -S3Key IS3ykrgDMA3mKZMIh943i -S3Secret Qk3ykKUw8xp2uvXcbiLp5N3ykmgUJfBpywt23wpvw -Endpoint "https://s3.storage.local" -S3Region "US-EAST" -S3Bucket "marketplace"
         
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateScript({
            if ($_ -match '\s') {
                throw "Name cannot contain spaces: $_"
            }
            return $true
        })]
        [string]$Name,
        
        [Parameter(Mandatory = $true)]
        [string]$Type,
        
        [Parameter(Mandatory = $true)]
        [string]$Endpoint,
        
        [Parameter(Mandatory = $false)]
        [ValidateScript({
            if ($_ -match '\s') {
                throw "Description cannot contain spaces: $_"
            }
            return $true
        })]
        [string]$Description,
        
        [Parameter(Mandatory = $false)]
        [string]$S3Key,
        
        [Parameter(Mandatory = $false)]
        [string]$S3Secret,
        
        [Parameter(Mandatory = $false)]
        [string]$S3Region,
        
        [Parameter(Mandatory = $false)]
        [string]$S3Bucket
        
    )
    # Define the market components
    if ($type -match "static"){    
        $templateParts = @()
        $templateParts += "NAME=$Name"
        $templateParts += "MARKET_MAD=$Type"
        $templateParts += "ENDPOINT=$ENDPOINT"
        
        # Join all parts with spaces
        $templateString = $templateParts -join ' '
    
        $config = [PSCustomObject]@{
            template = $templateString
        }
    }

    elseif ($Type -match "s3"){
        $templateParts = @()
        $templateParts += "NAME=$Name"
        $templateParts += "MARKET_MAD=$Type"
        $templateParts += "ENDPOINT=$ENDPOINT"
        $templateParts += "AWS=YES"
        $templateParts += "ACCESS_KEY_ID=$S3Key"
        $templateParts += "SECRET_ACCESS_KEY=$S3Secret"
        $templateParts += "REGION=$S3Region"
        $templateParts += "BUCKET=$S3Bucket"
        $templateParts += "Description=$Description"
        
        # Join all parts with spaces
        $templateString = $templateParts -join ' '
        $config = [PSCustomObject]@{
            template = $templateString
        }
    }
    
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market"
    $response = Invoke-CloudApiRequest -Uri $uri -Method POST -Body $config
        
    $market = $response#.application
        return $market
}

function Rename-CloudMarket {
    <#
    .SYNOPSIS
        Rename a market in the Cloud Server.
     
    .DESCRIPTION
        Rename a market. Automatically handles token refresh.
        
    .PARAMETER ID
        Required. ID of the market.
 
    .PARAMETER Name
        Required. New name of the market.
 
    .EXAMPLE
        # Rename a market app
        Rename-CloudMarket -ID 5 -Name "NewMarketName"
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [int]$ID,

        [Parameter(Mandatory = $true)]
        [string]$Name
    )
    $newname=@{
        name=$Name
    }

    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/${ID}/name"
    write-verbose "Body: $newname"
    $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -body $NewName
    Write-Host "Market $ID renamed successfully." -ForegroundColor Green
    return $response
}

function Enable-CloudMarket {
    <#
    .SYNOPSIS
        Enable a market in the Cloud Server.
     
    .DESCRIPTION
        Enable a market. Automatically handles token refresh.
        
    .PARAMETER ID
        Required. ID of the market.
 
    .EXAMPLE
        # Enable a market
        Enable-CloudMarket -ID 5
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [int]$ID
    )
    $enable= @{
        enable= $true
    }


    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/${ID}/enable"
    $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -body $enable
    Write-Host "Market $ID enabled successfully." -ForegroundColor Green
    return $response
}

function Remove-CloudMarket {
    <#
    .SYNOPSIS
        Removes a market from the Cloud Server.
     
    .DESCRIPTION
        Deletes a Market by ID. Automatically handles token refresh.
     
    .PARAMETER ID
        Required. Market ID to remove
     
    .EXAMPLE
        # Remove a market and prompt for confirmation
        Remove-CloudMarket -ID 105
         
    .EXAMPLE
        # Remove a market and bypass the confirmation prompt
        Remove-CloudMarket -ID 105 -Confirm:$false
         
    #>

    
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
    param(
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [int]$ID
    )
    
    process {
        # Get the Market details for confirmation message
        $market = (Get-CloudMarket -ID $ID).name
        
        if (-not $market) {
            Write-Warning "Market $ID not found."
            return
        }
        
        
        # Confirm before deletion
        if ($PSCmdlet.ShouldProcess("Market $ID - $market", "Remove Market")) {
            
            $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/$ID"
            
            Write-Verbose "Removing Market ${ID}: $marketName"
            
            try {
                $response = Invoke-CloudApiRequest -Uri $uri -Method Delete
                Write-Host "Market $ID removed successfully." -ForegroundColor Green
                return $response
            }
            catch {
                # Check for specific error messages
                if ($_.Exception.Message -match "not found|does not exist") {
                    Write-Warning "Market $ID not found or already deleted."
                    return
                }
                else {
                    # Re-throw other errors
                    throw
                }
            }
        }
    }
}

function Lock-CloudMarketApp {
    <#
    .SYNOPSIS
        Lock a market app in the Cloud Server.
     
    .DESCRIPTION
        Lock a market app. Automatically handles token refresh.
        
    .PARAMETER ID
        Required. ID of the market app.
 
    .PARAMETER Level
        Optional. Lock level (USE, MANAGE, ADMIN, ALL). Defaults to USE
 
    .PARAMETER Test
        When set, performs a test lock instead of a real one.
 
    .EXAMPLE
        # Lock a market app
        Lock-CloudMarketApp -ID 5
 
    .EXAMPLE
        # Test locking an app
        Lock-CloudMarketApp -ID 5 -Test
    #>

    
    [CmdletBinding()]
    param(
        
        [Parameter(Mandatory = $true)]
        [int]$ID,
        
        [Parameter(Mandatory = $false)]
        [ValidateSet('USE','MANAGE','ADMIN','ALL')]
        [string]$Level="USE",
        
        [switch]$Test
    )

    $lockdata = @{
        level = $Level
        test  = [bool]$Test
    }
    
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/app/${ID}/lock"
    $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -Body $lockdata
    Write-Host "Market app $ID locked successfully." -ForegroundColor Green
    return $response
}

function Unlock-CloudMarketApp {
    <#
    .SYNOPSIS
        Unlock a market app in the Cloud Server.
         
    .DESCRIPTION
        Unlock a market app Automatically handles token refresh.
        
    .PARAMETER ID
        ID of the market app
 
    .EXAMPLE
        # Unlock cloud market app #5
        Unlock-CloudMarketApp -ID 5
    #>

    
    [CmdletBinding()]
    param(
        
        [Parameter(Mandatory = $true)]
        [int]$ID        

    )
   
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/app/${ID}/unlock"
    $response = Invoke-CloudApiRequest -Uri $uri -Method Patch
    Write-Host "Market app $ID unlocked successfully." -ForegroundColor Green
    return $response
}

function Remove-CloudMarketApp {
    <#
    .SYNOPSIS
        Removes a market app from the Cloud Server.
     
    .DESCRIPTION
        Removes a market app. Automatically handles token refresh.
     
    .PARAMETER ID
        Required. Market app ID.
     
    .EXAMPLE
        # Remove market app with confirmation prompt (default behavior):
        Remove-CloudMarketApp -ID 3
        Confirm
        Are you sure you want to perform this action?
        Performing the operation "Remove Market App" on target "App ID 3 (MyApp)".
        [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): Y
 
    .EXAMPLE
        # Remove image without confirmation prompt:
        Remove-CloudMarketApp -ID 3 -Confirm:$false
    #>

    
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [int]$ID
    )
    
    process {
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/app/${ID}"
        
        Invoke-CloudResourceRemoval `
            -CallerPSCmdlet $PSCmdlet `
            -ResourceType "Market App" `
            -ID $ID `
            -Uri $uri `
            -GetResourceScript { Get-CloudMarketApp -ID $ID }
    }
}

function Enable-CloudMarketApp {
    <#
    .SYNOPSIS
        Enable a market app in the Cloud Server.
     
    .DESCRIPTION
        Enable a market app. Automatically handles token refresh.
        
    .PARAMETER ID
        Required. ID of the market app.
 
    .EXAMPLE
        # Enable a market app
        Enable-CloudMarketApp -ID 5
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [int]$ID
    )
    $enable= @{
        enable= $true
    }


    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/app/${ID}/enable"
    $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -body $enable
    Write-Host "Market app $ID enabled successfully." -ForegroundColor Green
    return $response
}

function Rename-CloudMarketApp {
    <#
    .SYNOPSIS
        Rename a market app in the Cloud Server.
     
    .DESCRIPTION
        Rename a market app. Automatically handles token refresh.
        
    .PARAMETER ID
        Required. ID of the market app.
 
    .PARAMETER Name
        Required. New name of the market app.
 
    .EXAMPLE
        # Rename a market app
        Rename-CloudMarketApp -ID 5 -Name "NewAppName"
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [int]$ID,

        [Parameter(Mandatory = $true)]
        [string]$Name
    )
    $newname=@{
        name=$Name
    }

    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/app/${ID}/name"
    write-verbose "Body: $newname"
    $response = Invoke-CloudApiRequest -Uri $uri -Method Patch -body $NewName
    Write-Host "Market app $ID renamed successfully." -ForegroundColor Green
    return $response
}

function New-CloudMarketApp {
    <#
    .SYNOPSIS
        Allocates a new marketplace app on the Cloud Server.
     
    .DESCRIPTION
        Creates a new marketplace app in a specified market. Automatically handles token refresh.
     
    .PARAMETER MarketId
        Required. The ID of the marketplace where the app will be created.
     
    .PARAMETER Name
        Required. Display name of the new marketplace app.
     
    .PARAMETER Type
        Required. The type of app (e.g., IMAGE, VMTEMPLATE).
         
    .PARAMETER OriginId
        Optional. The ID of the origin resource (e.g., image ID, template ID).
         
    .PARAMETER Description
        Optional. Description of the marketplace app.
         
    .PARAMETER Publisher
        Optional. Publisher or vendor of the app.
         
    .PARAMETER Version
        Optional. Version of the app.
         
    .PARAMETER Format
        Optional. Format of the image (e.g., qcow2, raw).
         
    .PARAMETER AdditionalParams
        Optional. Hashtable of additional template parameters to include.
             
    .EXAMPLE
        # Create a new marketplace app for an image
        New-CloudMarketApp -MarketId 5 -Name "Ubuntu-22.04" -Type "IMAGE" -OriginId 42 -Description "Ubuntu 22.04 LTS Server" -Publisher "Canonical" -Version "22.04" -Format "qcow2"
 
    .EXAMPLE
        # Create a marketplace app with additional custom parameters
        $additionalParams = @{
            "SIZE" = "10240"
            "MD5" = "a1b2c3d4e5f6"
        }
        New-CloudMarketApp -MarketId 5 -Name "CustomApp" -Type "IMAGE" -OriginId 10 -AdditionalParams $additionalParams
         
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [int]$MarketId,
        
        [Parameter(Mandatory = $true)]
        [ValidateScript({
            if ($_ -match '\s') {
                throw "Name cannot contain spaces: $_"
            }
            return $true
        })]
        [string]$Name,
        
        [Parameter(Mandatory = $true)]
        [string]$Type,
        
        [Parameter(Mandatory = $false)]
        [string]$OriginId,
        
        [Parameter(Mandatory = $false)]
        [string]$Description,
        
        [Parameter(Mandatory = $false)]
        [string]$Publisher,
        
        [Parameter(Mandatory = $false)]
        [string]$Version,
        
        [Parameter(Mandatory = $false)]
        [string]$Format,
        
        [Parameter(Mandatory = $false)]
        [hashtable]$AdditionalParams
    )
    
    # Build the template string
    $templateParts = @()
    $templateParts += "NAME=$Name"
    $templateParts += "TYPE=$Type"
    
    # Add optional parameters if provided
    if ($OriginId) { $templateParts += "ORIGIN_ID=$OriginId" }
    if ($Description) { $templateParts += "DESCRIPTION=$Description" }
    if ($Publisher) { $templateParts += "PUBLISHER=$Publisher" }
    if ($Version) { $templateParts += "VERSION=$Version" }
    if ($Format) { $templateParts += "FORMAT=$Format" }
    
    # Add any additional parameters from hashtable
    if ($AdditionalParams) {
        foreach ($key in $AdditionalParams.Keys) {
            $templateParts += "$key=$($AdditionalParams[$key])"
        }
    }
    
    # Join all parts with spaces
    $templateString = $templateParts -join ' '
    
    # Create the request body
    $config = [PSCustomObject]@{
        template = $templateString
    }
    
    # Build the URI with the market ID
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/$MarketId/app"
    
    # Make the API request
    $response = Invoke-CloudApiRequest -Uri $uri -Method POST -Body $config
    
    return $response
}

function Update-CloudMarket {
    <#
    .SYNOPSIS
        Updates an existing cloud market on the Cloud Server.
     
    .DESCRIPTION
        Updates an existing cloud market configuration. Automatically handles token refresh.
     
    .PARAMETER Id
        Required. The ID of the market to update.
     
    .PARAMETER Name
        Optional. Display name of the market.
     
    .PARAMETER Type
        Optional. The type of market.
         
    .PARAMETER Description
        Optional. If type is S3, use this to define the description of the marketplace. String must not include spaces.
         
    .PARAMETER Endpoint
        Optional. The full URL of the market, including credentials if applicable.
         
    .PARAMETER S3Key
        Optional. If type is S3, this is the access key.
         
    .PARAMETER S3Secret
        Optional. If type is S3, this is the secret key.
         
    .PARAMETER S3Region
        Optional. If type is S3, this is the region used.
         
    .PARAMETER S3Bucket
        Optional. If type is S3, this is the bucket used.
             
    .EXAMPLE
        # Update the endpoint for an existing static market
        Update-CloudMarket -ID 5 -Endpoint "https://USERNAME:PASSWORD@marketplace.softiron.cloud/community/metadata/"
 
    .EXAMPLE
        # Update S3 credentials for an existing S3 market
        Update-CloudMarket -ID 3 -S3Key "NewAccessKey123" -S3Secret "NewSecretKey456"
         
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [int]$Id,
        
        [Parameter(Mandatory = $false)]
        [ValidateScript({
            if ($_ -match '\s') {
                throw "Name cannot contain spaces: $_"
            }
            return $true
        })]
        [string]$Name,
        
        [Parameter(Mandatory = $false)]
        [string]$Type,
        
        [Parameter(Mandatory = $false)]
        [string]$Endpoint,
        
        [Parameter(Mandatory = $false)]
        [ValidateScript({
            if ($_ -match '\s') {
                throw "Description cannot contain spaces: $_"
            }
            return $true
        })]
        [string]$Description,
        
        [Parameter(Mandatory = $false)]
        [string]$S3Key,
        
        [Parameter(Mandatory = $false)]
        [string]$S3Secret,
        
        [Parameter(Mandatory = $false)]
        [string]$S3Region,
        
        [Parameter(Mandatory = $false)]
        [string]$S3Bucket
    )
    
    # Build template string with only provided parameters
    $templateParts = @()
    
    if ($PSBoundParameters.ContainsKey('Name')) { $templateParts += "NAME=$Name" }
    if ($PSBoundParameters.ContainsKey('Type')) { $templateParts += "MARKET_MAD=$Type" }
    if ($PSBoundParameters.ContainsKey('Endpoint')) { $templateParts += "ENDPOINT=$Endpoint" }
    
    # Add S3-specific parameters if provided
    if ($PSBoundParameters.ContainsKey('S3Key')) { 
        $templateParts += "AWS=YES"
        $templateParts += "ACCESS_KEY_ID=$S3Key" 
    }
    if ($PSBoundParameters.ContainsKey('S3Secret')) { $templateParts += "SECRET_ACCESS_KEY=$S3Secret" }
    if ($PSBoundParameters.ContainsKey('S3Region')) { $templateParts += "REGION=$S3Region" }
    if ($PSBoundParameters.ContainsKey('S3Bucket')) { $templateParts += "BUCKET=$S3Bucket" }
    if ($PSBoundParameters.ContainsKey('Description')) { $templateParts += "Description=$Description" }
    
    # Validate that at least one parameter was provided
    if ($templateParts.Count -eq 0) {
        throw "At least one parameter must be provided to update the market."
    }
    
    # Join all parts with spaces
    $templateString = $templateParts -join ' '
    
    $config = [PSCustomObject]@{
        template = $templateString
    }

    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/${ID}"
    write-verbose "Config: $config"
    write-verbose "URI: $uri"
    $response = Invoke-CloudApiRequest -Uri $uri -Method PATCH -Body $config
    
    Write-Host "Market $MarketId updated successfully." -ForegroundColor Green
    return $response
}

function Update-CloudMarketApp {
    <#
    .SYNOPSIS
        Updates an existing marketplace app on the Cloud Server.
     
    .DESCRIPTION
        Updates an existing marketplace app configuration. Automatically handles token refresh.
     
    .PARAMETER ID
        Required. The ID of the app to update.
     
    .PARAMETER Name
        Optional. Display name of the marketplace app.
     
    .PARAMETER Type
        Optional. The type of app (e.g., IMAGE, VMTEMPLATE).
 
   .PARAMETER Merge
        Optional. If true (default), merges with existing template. If false, replaces the template entirely.
        Use -Merge:$false to completely replace the template configuration.
 
    .PARAMETER OriginId
        Optional. The ID of the origin resource.
         
    .PARAMETER Description
        Optional. Description of the marketplace app.
         
    .PARAMETER Publisher
        Optional. Publisher or vendor of the app.
         
    .PARAMETER Version
        Optional. Version of the app.
         
    .PARAMETER Format
        Optional. Format of the image (e.g., qcow2, raw).
         
    .PARAMETER AdditionalParams
        Optional. Hashtable of additional template parameters to include.
             
    .EXAMPLE
        # Update the version and description of a marketplace app without merging
        Update-CloudMarketApp -ID 5 -Version "22.04.1" -Description "Ubuntu 22.04.1 LTS Server" -Merge:$false
 
    .EXAMPLE
        # Update marketplace app with custom parameters, merging the new configuration with the existing one (default behavior)
        $params = @{ "SIZE" = "20480" }
        Update-CloudMarketApp -ID 5 -AdditionalParams $params
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [int]$Id,

        [Parameter()]
        [bool]$Merge = $true,
        
        [Parameter(Mandatory = $false)]
        [ValidateScript({
            if ($_ -match '\s') {
                throw "Name cannot contain spaces: $_"
            }
            return $true
        })]
        [string]$Name,
        
        [Parameter(Mandatory = $false)]
        [string]$Type,
        
        [Parameter(Mandatory = $false)]
        [string]$OriginId,
        
        [Parameter(Mandatory = $false)]
        [string]$Description,
        
        [Parameter(Mandatory = $false)]
        [string]$Publisher,
        
        [Parameter(Mandatory = $false)]
        [string]$Version,
        
        [Parameter(Mandatory = $false)]
        [string]$Format,
        
        [Parameter(Mandatory = $false)]
        [hashtable]$AdditionalParams
    )
    
    # Build template string with only provided parameters
    $templateParts = @()
    
    if ($PSBoundParameters.ContainsKey('Name')) { $templateParts += "NAME=$Name" }
    if ($PSBoundParameters.ContainsKey('Type')) { $templateParts += "TYPE=$Type" }
    if ($PSBoundParameters.ContainsKey('OriginId')) { $templateParts += "ORIGIN_ID=$OriginId" }
    if ($PSBoundParameters.ContainsKey('Description')) { $templateParts += "DESCRIPTION=$Description" }
    if ($PSBoundParameters.ContainsKey('Publisher')) { $templateParts += "PUBLISHER=$Publisher" }
    if ($PSBoundParameters.ContainsKey('Version')) { $templateParts += "VERSION=$Version" }
    if ($PSBoundParameters.ContainsKey('Format')) { $templateParts += "FORMAT=$Format" }
    
    # Add any additional parameters from hashtable
    if ($AdditionalParams) {
        foreach ($key in $AdditionalParams.Keys) {
            $templateParts += "$key=$($AdditionalParams[$key])"
        }
    }
    
    # Validate that at least one parameter was provided
    if ($templateParts.Count -eq 0) {
        throw "At least one parameter must be provided to update the marketplace app."
    }
    
    # Join all parts with spaces
    $templateString = $templateParts -join ' '
    
    # Create the request body
    $config = [PSCustomObject]@{
        merge = $Merge
        template = $templateString
    }
    
    # Build the URI
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/market/app/${ID}/"
    
    # Make the API request
    write-verbose "Body: $config"
    write-verbose "URI: $uri"
    $response = Invoke-CloudApiRequest -Uri $uri -Method PATCH -Body $config

    Write-Host "Marketplace app $ID updated successfully." -ForegroundColor Green
    return $response
}