Private/Context.ps1

# Shared helpers: token resolution, client construction, anchors and output shaping.

function Get-PCNotionToken {
    [CmdletBinding()]
    param()
    if (Get-Command Get-PCSecret -ErrorAction SilentlyContinue) {
        $key = Get-PCSecret -Name notion -ErrorAction SilentlyContinue
        if ($key) { return [pscustomobject]@{ Token = [string]$key; Source = 'secret-store' } }
    }
    if ($env:NOTION_API_KEY) { return [pscustomobject]@{ Token = $env:NOTION_API_KEY; Source = 'environment' } }
    throw 'No Notion token. Store one with Set-PCSecret -Name notion -ApiKey <token> (PowerCraft.Secrets) or set NOTION_API_KEY.'
}

function New-PCNotionContext {
    [CmdletBinding()]
    param()
    $resolved = Get-PCNotionToken
    $options = [PowerCraft.Notion.Core.Api.NotionClientOptions]::new()
    $client = [PowerCraft.Notion.Core.Api.NotionClient]::new($resolved.Token, $null, $options)
    $register = [PowerCraft.Notion.Core.Register.RegisterClient]::new($client, $null, $null)
    [pscustomobject]@{
        Client      = $client
        Register    = $register
        TokenSource = $resolved.Source
        Anchors     = [PowerCraft.Notion.Core.Folder.AnchorMap]::Load((Get-PCNotionConfigPath))
    }
}

function Get-PCNotionConfigPath {
    if ($env:PCNOTION_CONFIG) { return $env:PCNOTION_CONFIG }
    return [PowerCraft.Notion.Core.Folder.AnchorMap]::DefaultConfigPath()
}

function ConvertTo-PCNotionReportObject {
    param([Parameter(Mandatory)] $Report)
    $counts = [ordered]@{}
    foreach ($kv in ($Report.Counts().GetEnumerator() | Sort-Object Key)) { $counts[$kv.Key] = $kv.Value }
    [pscustomobject]@{
        Set                       = $Report.SetName
        Result                    = $Report.Result
        RefusedReason             = $Report.RefusedReason
        ResolvedRoot              = $Report.ResolvedRoot
        Exposure                  = $Report.Exposure
        MaterialisationFingerprint = $Report.MaterialisationFingerprint
        Counts                    = [pscustomobject]$counts
        Items                     = @($Report.Items | ForEach-Object {
            [pscustomobject]@{
                LocalPath = $_.LocalPath; Outcome = $_.Outcome; Case = $_.DecisionCase; State = $_.State; Reason = $_.Reason
                ContentWritten = $_.ContentWritten; ReceiptWritten = $_.ReceiptWritten; RowWritten = $_.RowWritten; RowSkipped = $_.RowSkippedReason
                Candidate = $_.CandidatePath; References = @($_.References); Suggestions = @($_.Suggestions)
            }
        })
        Warnings                  = @($Report.Warnings)
        Orphans                   = @($Report.Orphans)
        ChangedSinceApproval      = @($Report.ChangedSinceApproval)
        Requests                  = $Report.Requests
        RunId                     = $Report.RunId
    }
}

function Show-PCNotionPreview {
    param([Parameter(Mandatory)] $Preview)
    $lines = @("Approve $($Preview.Target)")
    foreach ($kv in $Preview.Bound) { $lines += (" {0,-12} {1}" -f $kv.Key, $kv.Value) }
    $lines += " fingerprint $($Preview.Fingerprint)"
    if ($Preview.AlreadyApproved) { $lines += ' (already approved with exactly these values)' }
    foreach ($p in $Preview.Problems) { $lines += " PROBLEM: $p" }
    $lines -join "`n"
}