OfferDex.psm1

function Start-Bootstrap{

    Invoke-SpectreCommandWithStatus -Title "Fetching asset list from dexie.space" -ScriptBlock {
        if(-not $Global:assets){
            Get-xchAssets
        }
    } -Spinner Toggle10

    Reset-CurrentOffers
    
}

function Start-OfferDex{
    
    Show-OfferDexHeader
    Start-Bootstrap
    Show-OfferDexMenu
}

function Show-OfferDexHeader{
    Clear-Host
    Write-SpectreFigletText -Text "offerDEX" -Color green -Alignment Center
    Write-SpectreRule -Title "Combine offers from dexie" -LineColor green 
"Combine offers found on dexie to get the most for you trade! offerDex will get upto 100 offers from dexie at a time that match your requirements.
 
It will combine as many offers as it can together for you under your max spend amount and copy the offer file to your clipbord."
 |  Format-SpectrePanel -Expand -Color green -Height 4 

}

function Show-OfferDexMenu{
    if($Global:offers.count -ge 1){
        $choices = @(
        @{
            message = "Get Quote"
            action = { Get-NewOffer}
        },
        @{
            message = "Review Quotes"
            action = { Show-OfferDexQuotes }
        },
        @{
            message = "Clear Quotes"
            action = { Reset-CurrentOffers }
        },
        @{
            message = "Quit"
            action = {break}
        }
    
    ) 
    } else {

    

        $choices = @(
            @{
                message = "Get Quote"
                action = { Get-NewOffer}
            },
            @{
                message = "Review Quotes"
                action = { Show-OfferDexQuotes }
            },
            @{
                message = "Quit"
                action = {break}
            }
        
        ) 
    }
    $selection = Read-SpectreSelection -Message "Menu:" -Choices $choices -ChoiceLabelProperty message
    &($selection.action)
}

function Show-OfferDexQuotes {
    Show-OfferDexHeader
    if($Global:offers){
        $Global:offers.offer | Format-SpectreTable -Color green 
        $selection = Read-SpectreSelection -Message "Copy Offer to clipboard:" -Choices ($Global:offers.offer) -ChoiceLabelProperty Id
        $clip = ($global:offers | Where-Object {$_.offer -eq $selection}).quote
        Set-Clipboard -Value $clip
    }
    Show-OfferDexMenu
}

function Get-xchAssets {
    $uri = "https://api.dexie.space/v3/prices/tickers"
    $data = Invoke-RestMethod -Uri $uri
    $assets = @()
    $assets += @{
        asset_id = "xch"
        ticker = "XCH"
        name = "Chia"
        volume = 1000000000000
    }
    if($data.success){
        $data.tickers | ForEach-Object {
            $assets += @{
                asset_id = ($_.base_currency)
                ticker = ($_.base_code)
                name = ($_.base_name)
                volume = ($_.target_volume -as [Decimal])
            }
        }
        
    }
    $Global:assets = ( $assets | Sort-Object -Property volume -Descending)
}

function Read-SpectreNumber{
    param(
        [Parameter(Mandatory=$true)]
        [string]$message,
        
        [Parameter(Mandatory=$true)]
        [Int16]$numberOfDecimals,
        $DefaultAnswer
    )
    if($null -eq $DefaultAnswer){
        $dinput = Read-SpectreText -Message $message
    } else {
        $dinput = Read-SpectreText -Message $message -DefaultAnswer $DefaultAnswer
    }
    
    if($numberOfDecimals -lt 1){
        $match = '^\d+$'
    } else {
        $match = '^\d+(\.\d{1,'+"$($numberOfDecimals)"+'})?$'
    }
    
    if($dinput -match $match){
        return [decimal]$dinput
    } else {
        
        Write-Host "Invalid input. Please enter a valid number with up to $numberOfDecimals decimal places."
        return Read-SpectreNumber -message $message  -numberOfDecimals $numberOfDecimals
    }
}

function Reset-CurrentOffers{
    $Global:offers = @()
    Show-OfferDexHeader
    Show-OfferDexMenu
}

function Get-NewOffer{
    Show-OfferDexHeader
    $offered = Read-SpectreSelection -Message "What asset are you offering?" -Choices ($Global:assets) -ChoiceLabelProperty ticker -EnableSearch -SearchHighlightColor blue -PageSize 10
    $requested = Read-SpectreSelection -Message "What asset do you want?" -Choices (($Global:assets | Where-Object {$_.asset_id -ne $offered.asset_id})) -ChoiceLabelProperty ticker -EnableSearch -SearchHighlightColor blue -PageSize 10
    $decimals = ($offered.ticker -eq "XCH") ? 12 : 3
    $offered_amount = Read-SpectreNumber -message "How much [red]$($offered.name)[/] do you want to spend on [green]$($requested.name)[/]" -numberOfDecimals $decimals
    $dexie_uri = "https://api.dexie.space/v1/offers?offered=$($requested.ticker)&requested=$($offered.ticker)&page_size=100"
    $offers = Invoke-SpectreCommandWithStatus -Title "Searching [blue]dexie.space[/]!" -ScriptBlock {
        $tmp_offers = Invoke-RestMethod -Uri $dexie_uri -Method Get
        $amount_spent = (($decimals -eq 12) ? 0.001 : 0.03)
        $collected = @()
        $amount_received = 0
        $tmp_offers.offers | ForEach-Object {
            $tmp_amt = $amount_spent + $_.requested[0].amount
            if($tmp_amt -le $offered_amount){
                $amount_spent = $tmp_amt
                $amount_received += $_.offered[0].amount
                
                $collected += @{
                    offered = $_.offered[0].code
                    offered_amount = $_.offered[0].amount
                    requested = $_.requested[0].code
                    requested_amount = $_.requested[0].amount
                    offer = $_.offer
                }
            }
        }
        start-sleep 1
        return [ordered]@{
            fee_asset_id = ($offered.asset_id)
            spent_asset = ($offered.ticker)
            spent_amount = $amount_spent
            received_asset = ($requested.ticker)
            received_amount = $amount_received
            offers = ($collected.offer)
            display = [PSCustomObject]@{
                "Id" = [System.DateTimeOffset]::Now.ToUnixTimeSeconds()
                "Spent Asset" = ($offered.ticker)
                "Spent Amount" = $amount_spent
                "Received Asset" = ($requested.ticker)
                "Received Amount" = $amount_received
                "# of Combined Offers"=($collected.offer.count)
                "Price S/R" = ([Math]::Round($amount_spent/$amount_received,3))
                "Price R/S" = ([Math]::Round($amount_received/$amount_spent,3))
            }
        }
    
    }
    if($offers){
        

        [PSCustomObject]$offers.display | Format-SpectreTable -Color green

        $response = Invoke-RestMethod -uri "https://offer.watch/api/combine" -body ($offers | ConvertTo-Json) -Method Post -ContentType "application/json"

        if($response){
            Write-SpectreHost -Message "
[gold1]Your offer file has been copied to your clipboard.[/]
 
You can paste it into your SageWallet -> Offers -> View Offer "

            
            $Global:offers += [pscustomobject]@{
                offer = $offers.display
                quote = $response
            }
            
            Set-Clipboard -value $response 
        }    
    }
    Show-OfferDexMenu
}

Export-ModuleMember -Function Start-OfferDex