FilterBox/Write-SRxFilterBranch.ps1

[CmdletBinding()]
param(
    [Parameter(Mandatory)] [string]$RootPath,
    [Parameter(Mandatory)] [string]$PackPath,
    [Parameter(Mandatory)] [string]$ResultPath,
    [Parameter(Mandatory=$false)] [switch]$Force,
    [Parameter(Mandatory=$false)] [ValidateSet('JSON','XML')] [string]$Format = 'JSON'
)

$ErrorActionPreference = 'Stop'

function Write-SRxFilterResult {
    param([bool]$Success, [bool]$Conflict, $Data, [string]$ErrorText)
    $payload = [pscustomobject]@{
        Success   = $Success
        Conflict  = $Conflict
        Data      = $Data
        Error     = $ErrorText
        Pid       = $PID
        Ended     = (Get-Date).ToString('o')
    }
    $json = $payload | ConvertTo-Json -Depth 25 -Compress
    try {
        $dir = Split-Path -Parent $ResultPath
        if ($dir -and -not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
        Set-Content -LiteralPath $ResultPath -Value $json -Encoding UTF8
    } catch { }
    Write-Host ("__JSON__" + $json)
}

function ConvertFrom-SRxJsonFile {
    param([string]$Path)
    if (-not (Test-Path $Path)) { throw "Input file not found: $Path" }
    $raw = Get-Content -LiteralPath $Path -Raw -Encoding UTF8
    if ([string]::IsNullOrWhiteSpace($raw)) { throw "Input file empty: $Path" }
    return ($raw | ConvertFrom-Json)
}

function ConvertTo-SRxNodesStack {
    param($Branch)
    $stack = [System.Collections.Stack]::new()
    foreach ($d in $Branch) {
        $attrs = @{}
        if ($d.Attributes) {
            foreach ($p in $d.Attributes.PSObject.Properties) { $attrs[$p.Name] = [string]$p.Value }
        }
        if ($d.NodeName)            { $attrs['ts_NodeName']            = [string]$d.NodeName }
        if ($d.KeyAttribute)        { $attrs['ts_KeyAttribute']        = [string]$d.KeyAttribute }
        if ($d.KeyAttributeValue)   { $attrs['ts_KeyAttributeValue']   = [string]$d.KeyAttributeValue }
        if ($d.ProvisioningActivity){ $attrs['ts_ProvisioningActivity']= [string]$d.ProvisioningActivity }
        if ($d.CustomizationTarget) { $attrs['ts_CustomizationTarget'] = $true }
        if ($d.Deprecated)          { $attrs['ts_Deprecated']          = $true }

        $termNode = [pscustomobject]@{
            Name       = [string]$d.Name
            Attributes = $attrs
            Scope      = [int]$d.Scope
            xPath      = [string]$d.XPath
            Operation  = [string]$d.Operation
            optype     = [int]$d.Optype
        }
        $stack.Push($termNode)
    }
    return ,$stack
}

try {
    Set-Location -Path $RootPath
    $externalScript = Join-Path $RootPath 'loadmodule.ps1'
    . $externalScript
    if ($null -ne $LoadModule) { $LoadModule.Invoke("SRxCore") | Out-Null }
    Initialize-SRxEnv -LoadModule2 $LoadModule -RootPath $RootPath | Out-Null
    Connect-SRxSPOService
    if ($null -eq $global:SRxEnv) {
        if (Get-Command Start-SRxShell -ErrorAction SilentlyContinue) {
            Start-SRxShell -RootPath $RootPath -isJob | Out-Null
        } elseif (Get-Command Initialize-SRxEnv -ErrorAction SilentlyContinue) {
            Initialize-SRxEnv -RootPath $RootPath | Out-Null
        } else {
            throw "SRx environment could not be initialised from '$RootPath'."
        }
    }
    if ($null -eq $global:SRxEnv -or $null -eq $global:SRxEnv.Tenancy) {
        throw "global:SRxEnv or global:SRxEnv.Tenancy is null after bootstrap."
    }

    try { Import-Module (Join-Path $PSScriptRoot 'SRxFilterBox.psm1') -DisableNameChecking -Force -ErrorAction SilentlyContinue } catch { }
    try { Import-Module (Join-Path $PSScriptRoot 'SRxCustomizationJson.psm1') -DisableNameChecking -Force -ErrorAction SilentlyContinue } catch { }
    try { . (Join-Path $PSScriptRoot 'Write-SRxJsonCustomization.ps1') } catch { }
    $pack = ConvertFrom-SRxJsonFile -Path $PackPath
    $operation = [string]$pack.Operation
    $scope     = [int]$pack.Scope

     $effFormat = $Format
     if ([int]$pack.Scope -le 0) { $effFormat = 'XML' }
 
     if (-not (Get-Command Get-SRxCustomizationWriter -ErrorAction SilentlyContinue)) { throw "Get-SRxCustomizationWriter not available (SRxCore not loaded)." }
     
 
     if ($effFormat -eq 'JSON') {
        if (-not (Get-Command New-SRxJsonContainerTerm -ErrorAction SilentlyContinue)) { throw "New-SRxJsonContainerTerm not available (SRxCustomizationJson not loaded)." }
        if (-not (Get-Command Write-SRxJsonCustomization -ErrorAction SilentlyContinue)) { throw "Write-SRxJsonCustomization not available (dot-source it in STAGE 1)." }

        $container = New-SRxJsonContainerTerm -Pack $pack -Operation $operation

        $conn = Get-SRxConnection -siteUrl $global:SRxEnv.Tenancy.AdminUrl

        $props = @{}
        foreach ($k in $container.Attributes.Keys) { $props[[string]$k] = [string]$container.Attributes[$k] }

        $jw = Write-SRxJsonCustomization -Connection $conn `
                -Scope       ([int]$pack.Scope) `
                -Optype      ([int]$pack.Optype) `
                -Environment ([string]$pack.Environment) `
                -Design      ([string]$pack.Design) `
                -TermID      ([string]$pack.TermID) `
                -ContainerName ([string]$container.Name) `
                -Operation   ([string]$operation) `
                -Props       $props
        if (-not $jw.Success) { throw "Direct JSON write failed: $($jw.Error)" }
    }
    else {
        $writer = Get-SRxCustomizationWriter
        $nodesStack = ConvertTo-SRxNodesStack -Branch $pack.Branch
        $writerPack = [pscustomobject]@{
            nodesStack     = ,$nodesStack
            ts_Environment = [string]$pack.Environment
            ts_Design      = [string]$pack.Design
            ts_TermID      = [string]$pack.TermID
        }
        $writer.Start($writerPack)
    }
    $syncData    = $null
    $syncWarning = $null
    try {
        if (Get-Command Sync-SRxLocalFilterBranch -ErrorAction SilentlyContinue) {
            if ($effFormat -eq 'JSON') {
                $sync = Sync-SRxLocalJsonCustomization -Pack $pack -Operation $operation
            } else {
                $sync = Sync-SRxLocalFilterBranch -Pack $pack
            }
            if ($sync.Success) { $syncData = $sync }
            else               { $syncWarning = "Local sync failed: $($sync.Error)" }
        } else {
            $syncWarning = "Sync-SRxLocalFilterBranch not available; local cache not updated."
        }
    } catch {
        $syncWarning = "Local sync threw: $($_.Exception.Message)"
    }

    $data = [pscustomobject]@{
        Operation   = $operation
        Scope       = $scope
        FilterNodes = if ($syncData) { $syncData.FilterNodes } else { $null }
        OuterXml    = if ($syncData) { $syncData.OuterXml }    else { $null }
        SyncWarning = $syncWarning
    }
    Write-SRxFilterResult -Success $true -Conflict $false -Data $data -ErrorText $null
    exit 0
}
catch {
    $msg = $_.Exception.Message
    if ($_.Exception.InnerException) { $msg += " | inner: " + $_.Exception.InnerException.Message }
    Write-SRxFilterResult -Success $false -Conflict $false -Data $null -ErrorText $msg
    exit 1
}