[CmdletBinding(SupportsShouldProcess)]param(
    [ArgumentCompleter({Invoke-Command -ScriptBlock $_DockerComposeDirsCompleter -ArgumentList $args})]
    [string[]]$ProjectPath,
    [switch]$Recurse,
    [int]$Depth=1,
    [switch]$Force,
    [switch]$OneLine,
    [Parameter(Position = 0, mandatory, ValueFromRemainingArguments = $true)]
    [ArgumentCompleter({Invoke-Command -ScriptBlock $_DockerComposeCompleter -ArgumentList $args})]
    [array]$CliParams
)

if( -not $ProjectPath ) { $ProjectPath=@($PWD) }

$script:JobQueue = @()
$script:CleanupJobQueue = @()
function CompleteJobs {
    if( -not $JobQueue ) { return }
    $local:currentJobQueue = $JobQueue
    $JobQueue = @()
    $CleanupJobQueue += $currentJobQueue.Job

    $local:sw = [System.Diagnostics.StopWatch]::StartNew()
    $local:progress = [ordered]@{
        Activity  = "Waiting for docker-compose..."
        ItemCount = $currentJobQueue.Count
    }

    while( $true ) {
        $local:activeJobs = $($currentJobQueue | Where-Object Done -eq $false)
        $progress.CurrentOperation = "Processing: $($activeJobs.Name -join ', ')..."
        $progress.ItemProgress = $currentJobQueue.Count - $activeJobs.Count
        $progress.Elapsed      = $sw.Elapsed
        Show-Progress @progress
        $local:doneJobs = $activeJobs |
            Select-Object -ExpandProperty Job |
            Wait-Job -Any -Timeout 3
        if( $doneJobs ) {
            $doneJobs | ForEach-Object {
                $_ | Receive-Job | ForEach-Object {
                    Write-Host "---: $($_.Path) | $($_.Params)" -ForegroundColor Cyan
                    $_.Results
                    foreach( $local:j in $currentJobQueue ) {
                        if( $j.Path -eq $_.Path ) {
                            $j.Done = $true
                        }
                    }
                }
            }
        }
        if( -not $($currentJobQueue.Done -contains $false) ) { break }
    }
    Write-Host '--- Background jobs completed' -ForegroundColor Green

    Show-Progress -Activity $progress.Activity -Completed
}

if( $CliParams[0] -is [string] ) {
    $CliParams = @($CliParams,@($null))
}

$local:ext = ".yml"
$local:dcPathList = @()
$ProjectPath | ForEach-Object {
        while( $true ) {
            if( (Test-Path (Join-Path $_ "docker-compose$ext")) -and -not $Recurse ) {
                $dcPathList += Resolve-Path $_
            } elseif( $Recurse ) {
                $local:gciParams = [ordered]@{
                    Recurse = $true
                }
                if( $Depth ) {
                    $gciParams.Depth = $Depth
                }
                $dcPathList += Get-ChildItem -Path $_ -Include "docker-compose$ext" @gciParams |
                    Select-Object -ExpandProperty Directory |
                    Where-Object { $Force -or -not (Test-Path $(Join-Path $_ .noauto.all)) }
            }
            if( ($dcPathList -and -not $Recure) -or $ext -eq '.yaml' ) { 
                break
            }
            $ext = '.yaml'
        }
    }
if( -not $dcPathList ) { return }

$local:SingleProject = $dcPathList.Length -eq 1

foreach( $local:p in $CliParams ) {
    if( -not $p ) { continue }

    $local:AsJob = $false;
    $local:Wait  = $false;

    if( $p -isnot [String] -or $p.Length -eq 1 ) {
        $local:skipFirst = $true
        switch( $p[0] ) {
            '&' { $AsJob = -not $SingleProject }
            '!' { $Wait  = -not $SingleProject }
            default { $skipFirst = $false }
        }
        if( $skipFirst ) { $p = $p | Select-Object -Skip 1 }
    }

    $local:dcParams=@()
    $local:dcParams += $p | Where-Object { $_ } | ForEach-Object {
        if( $_ -match "(?:^'[^']+'$)|(?:^`"[^`"]+`"$)|(?:^[^\s]+$)" ) { $_ }
        else { "'$($_.Replace( "'", "''" ))'" }
    }
 
    $dcPathList | ForEach-Object {
        $local:dcPath = Join-Path $_ 'docker-compose.yaml'
        if( -not (Test-Path $dcPath) ) {
            $dcPath = Join-Path $_ 'docker-compose.yml'
        }
        if( -not (Test-Path $dcPath) ) {
            if( $Recurse ) { return }
            else { throw "ERROR: dcPath ($dcPath) does not exists" }
        }
       
        if( $Wait ) {
            if( $WhatIfPreference ) {
                Write-Host -ForegroundColor DarkCyan "Wait for bg jobs to complete !"
            } else {
                CompleteJobs
            }
        } 

        if( -not $dcParams ) { continue }

        $local:nextActionDescription = "In $dcPath Run $(if($AsJob){"(bg) "})with: $dcParams"
        if( $WhatIfPreference ) {
            Write-Host -ForegroundColor DarkYellow $nextActionDescription
        } else {
            Write-Verbose $nextActionDescription

            if( $AsJob ) {
                $JobQueue += ([PSCustomObject]([ordered]@{
                    Path = $dcPath
                    Name = Split-Path -Leaf $(Split-Path -Parent $dcPath)
                    Job = Start-Job -ArgumentList @($dcPath,$dcParams) -ScriptBlock {
                        param($dcPath,$dcParams)
                        [PSCustomObject] $([ordered]@{
                            Path = $dcPath
                            Params = $dcParams
                            Results = $(& docker-compose --file $dcPath $dcParams)
                        })}
                    Done = $false
                }))
            } else {
                & docker-compose --file $dcPath $dcParams
            }
        }
    }
}

# if( $WhatIfPreference ) { return }

CompleteJobs
if( $CleanupJobQueue ) {
    $CleanupJobQueue | Remove-Job
}