Public/Export-Budget.ps1

function Export-Budget {
    <#
    .SYNOPSIS
        Exports an entire budget to a folder or archive.
 
    .DESCRIPTION
        Exports all entities (accounts, billers, earnings) from a budget to a folder
        or compressed archive. Optionally includes metadata and projected transactions.
 
    .PARAMETER OutputPath
        The folder path or .zip file for the export.
 
    .PARAMETER Budget
        Optional budget name to export. Uses active budget if not specified.
 
    .PARAMETER Format
        Output format for entity files: CSV or JSON. Defaults to JSON.
 
    .PARAMETER IncludeMetadata
        Include the budget metadata file in the export.
 
    .PARAMETER IncludeProjections
        Include projected transactions in the export. Requires StartDate and EndDate.
 
    .PARAMETER StartDate
        Start date for projected transactions. Required if IncludeProjections is specified.
 
    .PARAMETER EndDate
        End date for projected transactions. Required if IncludeProjections is specified.
 
    .PARAMETER Compress
        Create a .zip archive instead of a folder.
 
    .EXAMPLE
        Export-Budget -OutputPath "C:\Backups\MyBudget"
 
        Exports the active budget to a folder.
 
    .EXAMPLE
        Export-Budget -OutputPath "C:\Backups\MyBudget" -Format JSON -IncludeMetadata
 
        Exports the budget with metadata in JSON format.
 
    .EXAMPLE
        Export-Budget -OutputPath "budget-backup.zip" -Compress
 
        Exports the budget to a compressed archive.
 
    .EXAMPLE
        Export-Budget -OutputPath "C:\Backups\FullBudget" -IncludeProjections -StartDate "2025-01-01" -EndDate "2025-12-31"
 
        Exports the budget with projected transactions for 2025.
 
    .OUTPUTS
        Path to the exported folder or archive
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$OutputPath,

        [Parameter()]
        [string]$Budget,

        [Parameter()]
        [ValidateSet('CSV', 'JSON')]
        [string]$Format = 'JSON',

        [Parameter()]
        [switch]$IncludeMetadata,

        [Parameter()]
        [switch]$IncludeProjections,

        [Parameter()]
        [datetime]$StartDate,

        [Parameter()]
        [datetime]$EndDate,

        [Parameter()]
        [switch]$Compress
    )

    # Validate projection parameters
    if ($IncludeProjections) {
        if (-not $StartDate -or -not $EndDate) {
            Write-Error "StartDate and EndDate are required when IncludeProjections is specified."
            return
        }
    }

    # Determine if output is a zip file
    $isZipOutput = $OutputPath -like '*.zip'
    if ($isZipOutput) {
        $Compress = $true
    }

    # Set up export folder
    if ($Compress -and -not $isZipOutput) {
        $zipPath = "$OutputPath.zip"
        $exportFolder = Join-Path $env:TEMP "BudgetExport_$(Get-Date -Format 'yyyyMMddHHmmss')"
    }
    elseif ($isZipOutput) {
        $zipPath = $OutputPath
        $exportFolder = Join-Path $env:TEMP "BudgetExport_$(Get-Date -Format 'yyyyMMddHHmmss')"
    }
    else {
        $exportFolder = $OutputPath
    }

    # Ensure export folder exists
    if (-not (Test-Path $exportFolder)) {
        New-Item -Path $exportFolder -ItemType Directory -Force | Out-Null
    }

    # Get budget info
    $budgetParams = @{}
    if ($Budget) { $budgetParams['Budget'] = $Budget }

    # Determine file extension based on format
    $extension = if ($Format -eq 'JSON') { '.json' } else { '.csv' }

    try {
        # Export accounts
        $accountsPath = Join-Path $exportFolder "Accounts$extension"
        $exportResult = Export-Account -OutputPath $accountsPath -Format $Format @budgetParams
        if ($exportResult) {
            Write-Verbose "Exported accounts to: $accountsPath"
        }

        # Export billers
        $billersPath = Join-Path $exportFolder "Billers$extension"
        $exportResult = Export-Biller -OutputPath $billersPath -Format $Format @budgetParams
        if ($exportResult) {
            Write-Verbose "Exported billers to: $billersPath"
        }

        # Export earnings
        $earningsPath = Join-Path $exportFolder "Earnings$extension"
        $exportResult = Export-Earning -OutputPath $earningsPath -Format $Format @budgetParams
        if ($exportResult) {
            Write-Verbose "Exported earnings to: $earningsPath"
        }

        # Export metadata if requested
        if ($IncludeMetadata) {
            $budgetInfo = Get-Budget -Name $Budget -Detailed
            if ($budgetInfo) {
                $metadataPath = Join-Path $exportFolder "metadata.json"
                $budgetInfo | ConvertTo-Json -Depth 10 | Set-Content -Path $metadataPath
                Write-Verbose "Exported metadata to: $metadataPath"
            }
        }

        # Export projected transactions if requested
        if ($IncludeProjections) {
            $projectionsPath = Join-Path $exportFolder "ProjectedTransactions$extension"
            $exportResult = Export-ProjectedTransactions -StartDate $StartDate -EndDate $EndDate -OutputPath $projectionsPath -Format $Format @budgetParams
            if ($exportResult) {
                Write-Verbose "Exported projected transactions to: $projectionsPath"
            }
        }

        # Compress if requested
        if ($Compress) {
            # Ensure parent directory of zip file exists
            $zipParent = Split-Path -Path $zipPath -Parent
            if ($zipParent -and -not (Test-Path $zipParent)) {
                New-Item -Path $zipParent -ItemType Directory -Force | Out-Null
            }

            Compress-Archive -Path "$exportFolder\*" -DestinationPath $zipPath -Force
            Write-Verbose "Created archive: $zipPath"

            # Clean up temp folder
            Remove-Item -Path $exportFolder -Recurse -Force

            return (Resolve-Path $zipPath).Path
        }
        else {
            return (Resolve-Path $exportFolder).Path
        }
    }
    catch {
        Write-Error "Failed to export budget: $_"

        # Clean up temp folder on error if compressing
        if ($Compress -and (Test-Path $exportFolder)) {
            Remove-Item -Path $exportFolder -Recurse -Force -ErrorAction SilentlyContinue
        }
    }
}