#!/usr/bin/env pwsh
$ErrorActionPreference = "Stop"


function Get-PageMetaCache
{
    <#
        .SYNOPSIS
            Get a locally indexed/cached Confluence page id

        .EXAMPLE
            Get-PageMetaCache `
                 -Title 'Page Title' `
                 -Manifest @() `
                 -Index @{}

        .NOTES
            To test or not to test, that is the question... Since the
            `Test-JSON` cmdlet requires serialized JSON, but we are working with
            the deserialized Hashtable, it's too computationally intense to
            always test the input upon every call. We therefore only make sure, 
            that correct data is written to the filesystem. For the rest, each 
            function is responsible for themself (learned that that's a valid 
            reflexive pronoun today 🤓).

            This function is lucky to get this note, because it's at the top 💯. 
            Of course this applies to every function.
    #>
    Param(
        [Parameter(Mandatory)] [string] $Title,
        [Parameter(Mandatory)] [Array] $Manifest,
        [Parameter()] [Collections.Hashtable] $Index
    )

    Process
    {
        If ($Index -And $Manifest.Count -gt 0 -And $Manifest[$Index.$Title])
        {
            $Manifest[$Index.$Title]
        }

        Else
        {
            For ($i = 0; $i -lt $Manifest.Count; $i += 1)
            {
                If ($Manifest[$i].Title -eq $Title)
                {
                    $Manifest[$i]

                    break
                }
            }
        }
    }
}


function Get-PageMeta
{
    <#
        .SYNOPSIS
            Get a Confluence page id

        .DESCRIPTION
            First, tries to retrieve from local page id index (cache) through 
            the local alias. If no cache hit, then polls the Confluence 
            instance host for the id by providing a space key and page title.

        .EXAMPLE
            Get-PageMeta `
                 -Host 'confluence.contoso.com' `
                 -Title 'Testitest' `
                 -Space 'TIARA' `
                 -CacheIndexFile 'confluence-page-cache.json'
    #>
    Param(
        [Parameter(Mandatory)] [string] $Host,
        [Parameter(Mandatory)] [string] $Title,
        [Parameter(Mandatory)] [string] $Space,
        [Parameter(Mandatory)] [Array] $Manifest,
        [Parameter()] [Collections.Hashtable] $Index
    )

    Begin
    {
         $pageMeta = Get-PageMetaCache `
             -Title $Title `
             -Manifest $Manifest `
             -Index $Index
    }

    Process
    {
        If ($pageMeta -And $pageMeta.Id)
        {
            $pageMeta

            return
        }

        $escapedTitle = [Uri]::EscapeDataString($Title)

        #TODO: move this to a separate function
        $query = "title=${escapedTitle}&spaceKey=${Space}&expand=history"

        Invoke-WebRequest `
            -Uri "https://${Host}/rest/api/content?$query" `
            -Method 'Get' `
            -Headers @{
                'Authorization' = "Bearer $(Get-PersonalAccessToken $Host)"
            } `
            -OutVariable response | Out-Null

        $results = ($response.Content | ConvertFrom-JSON).results

        if ($results.Count -gt 1)
        {
            throw "more than one result for query: $query"
        }

        elseif ($results.Count -eq 1) 
        {
            Update-PageMeta `
                -Id $results[0].id `
                -Version $results[0]._expandable.version `
                -Title $Title `
                -Manifest $Manifest
        }
    }
}


function Update-PageMeta
{
    <#
        .SYNOPSIS
            Register a Confluence page's metadata in the local cache

        .DESCRIPTION
            Synchronizes the locally cached page metadata (in manifest) with the
            data stored by the Confluence instance. Therefore it is required to
            supply a page id, since this is the reference linking the locally
            cached page to a published instance of a page.

        .EXAMPLE
            Update-PageMeta `
                -Title 'foobar' `
                -PageId 'pageId' `
                -Version 9001 `
                -AncestorTitle 'ancestorTitle' `
                -Hash 'hash' `
                -Manifest $mockManifest
    #>
    Param(
        [Parameter(Mandatory)] [String] $Title,
        # remote Confluence page instance id
        [Parameter(Mandatory)] [String] $Id,
        [Parameter()] [Int] $Version,
        [Parameter()] [String] $AncestorTitle,
        [Parameter()] [String] $Hash,
        [Parameter(Mandatory)] [Array] $Manifest,
        [Parameter()] [Collections.Hashtable] $Index
    )

    Process
    {
        $pageMeta = Get-PageMetaCache `
                        -Title $Title `
                        -Manifest $Manifest `
                        -Index $Index

        If (-Not $pageMeta)
        {
            throw "page titled `$Title` not indexed in Manifest."
        }

        $pageMeta.Id = $Id

        If ($Version)
        {
            $pageMeta.Version = $Version
        }

        If ($AncestorTitle)
        {
            $pageMeta.AncestorTitle = $AncestorTitle
        }

        # if content didn't update, hash stays the same
        If ($Hash)
        {
            $pageMeta.Hash = $Hash
        }

        Write-Debug "register: $Title -> $PageId"

        $pageMeta
    }
}

