private/ConvertFrom-HtmlParkmachineDetailResponse.ps1

function ConvertFrom-HtmlParkmachineDetailResponse {
    param (
        [Parameter(Mandatory = $true)]
        [string]
        $HtmlContent
    )

    $html = ($HtmlContent | ConvertFrom-Html)

    # Machine ID and name
    $nameSpan = $html.SelectSingleNode("//span[starts-with(@id,'pm_name_')]")
    $machineId = if ($nameSpan) { $nameSpan.GetAttributeValue('id', '') -replace 'pm_name_', '' } else { '' }
    $machineName = if ($nameSpan) { $nameSpan.InnerText.Trim() } else { '' }

    $result = [PSCustomObject]@{
        MachineId   = $machineId
        MachineName = $machineName
    }

    # Maps normalized HTML label → { Name = 'PropertyName'; Parts = @('Sub1','Sub2',...) }
    $fieldMap = @{
        'Location'                                                                                   = @{ Name = 'Location' }
        'Coordinate X'                                                                               = @{ Name = 'CoordinateX' }
        'Coordinate Y'                                                                               = @{ Name = 'CoordinateY' }
        'Time for message transmission'                                                              = @{ Name = 'MessageTransmissionTime' }
        'Last Update'                                                                                = @{ Name = 'LastUpdate' }
        'PM Status'                                                                                  = @{ Name = 'PMStatus' }
        'Error'                                                                                      = @{ Name = 'Error' }
        'Warning'                                                                                    = @{ Name = 'Warning' }
        'Other'                                                                                      = @{ Name = 'Other' }
        'Action status'                                                                              = @{ Name = 'ActionStatus' }
        'Cash'                                                                                       = @{ Name = 'Cash' }
        'Cashless'                                                                                   = @{ Name = 'Cashless' }
        'Ticket Sold'                                                                                = @{ Name = 'TicketsSold' }
        'Last coin exchange'                                                                         = @{ Name = 'LastCoinExchange' }
        'Battery level'                                                                              = @{ Name = 'BatteryLevel' }
        'Tickets printed;left'                                                                       = @{ Name = 'Tickets'; Parts = @('Printed', 'Left') }
        'Coinbox capacity left'                                                                      = @{ Name = 'Coinbox'; Parts = @('Capacity', 'Left') }
        'Network details'                                                                            = @{ Name = 'Network'; Parts = @('Operator', 'Type', 'Signal', 'Timestamp') }
        'Software details'                                                                           = @{ Name = 'Software'; Parts = @('AppVersion', 'OSVersion', 'HWId', 'Frontend', 'Project') }
        'Previous software details'                                                                  = @{ Name = 'PreviousSoftware'; Parts = @('AppVersion', 'OSVersion', 'HWId', 'Frontend', 'Project') }
        'PM working time;since'                                                                      = @{ Name = 'WorkingTime'; Parts = @('Minutes', 'Since') }
        'Printer Firmware; Modem Firmware; Modem Manufacturer; Modem Model; Sim Card Number (ICCID)' = @{ Name = 'Firmware'; Parts = @('Printer', 'Modem', 'ModemManufacturer', 'ModemModel', 'SimCardNumber') }
        'Spare column 8'                                                                             = @{ Name = 'SpareColumn8' }
        'Spare column 9'                                                                             = @{ Name = 'SpareColumn9' }
        'Spare column 10'                                                                            = @{ Name = 'SpareColumn10' }
    }

    function Resolve-Field($label) {
        $normalized = ($label -replace '\s+', ' ').Trim()
        if ($fieldMap.ContainsKey($normalized)) { return $fieldMap[$normalized] }
        return @{ Name = $normalized }
    }

    # First box: alternating left/right sibling divs
    $firstBox = $html.SelectSingleNode("//div[@class='pm_details_first_box']")
    if ($firstBox) {
        foreach ($leftNode in $firstBox.SelectNodes("div[@class='pm_details_line_left']")) {
            $label = $leftNode.InnerText.Trim()
            $rightNode = $leftNode.SelectSingleNode("following-sibling::div[@class='pm_details_line_right'][1]")
            $value = if ($rightNode) { $rightNode.InnerText.Trim() } else { '' }
            $field = Resolve-Field $label
            Add-DetailProperty $result $field.Name $value ($field.Parts ?? @())
        }
    }

    # Second box: pairs wrapped in pm_details_line
    $secondBox = $html.SelectSingleNode("//div[@class='pm_details_second_box']")
    if ($secondBox) {
        foreach ($line in $secondBox.SelectNodes("div[@class='pm_details_line']")) {
            $leftNode = $line.SelectSingleNode("div[@class='pm_details_line_left']")
            $rightNode = $line.SelectSingleNode("div[contains(@class,'pm_details_line_right')]")
            if (-not $leftNode) { continue }

            $label = $leftNode.InnerText.Trim()

            # PM Status is represented by an image — extract filename as status code
            $imgNode = if ($rightNode) { $rightNode.SelectSingleNode(".//img") } else { $null }
            $value = if ($imgNode) {
                $imgNode.GetAttributeValue('src', '') -replace '^.*/', '' -replace '\.[^.]+$', ''
            }
            elseif ($rightNode) {
                $rightNode.InnerText.Trim()
            }
            else { '' }

            $field = Resolve-Field $label
            Add-DetailProperty $result $field.Name $value ($field.Parts ?? @())
        }
    }

    return $result
}