<#
.SYNOPSIS
    Retrieve ServiceNow records based on the provided parameters.
.DESCRIPTION
    Retrieve ServiceNow records based on the provided parameters. Use the ItemType parameter for frequently used tables.
    If the ItemType is not listed, then use the Table parameter to specify the ServiceNow table you wish to query.
.PARAMETER ItemType
    The type of item to retrieve. Valid values are 'Incident', 'Change Request', 'Catalog Task', and 'Request Item'.
.PARAMETER Table
    The name of the ServiceNow table to query if the ItemType is not listed.
.PARAMETER SysId
    The SysId of the record to retrieve.
.PARAMETER Number
    The number of the record to retrieve.
.PARAMETER Filter
    A filter to apply to the query.
.PARAMETER Limit
    The maximum number of records to retrieve. Must be a positive integer.
.PARAMETER Fields
    An array of fields to include in the results.
.PARAMETER IncludeCustomVariable
    A switch to include custom variables in the results.
.PARAMETER IncludeVariableSet
    A switch to include variable sets in the results.
.EXAMPLE
    Get-ITDServiceNowRecord -ItemType 'Incident' -Number 'INC0012345'
    This example retrieves the incident record with the specified number.
.EXAMPLE
    Get-ITDServiceNowRecord -Table 'cmdb_ci_win_server' -Filter 'active=true' -Limit 10
    This example retrieves up to 10 active Windows server records from the specified table.
.LINK
    https://developer.servicenow.com/
#>



function Get-ITDServiceNowRecord {
    [CmdletBinding(SupportsPaging)]
    param (
        [Parameter(ParameterSetName = 'ItemType')]
        [ValidateSet('Incident', 'Change Request', 'Catalog Task', 'Request Item')]
        [string]
        $ItemType,

        [Parameter(ParameterSetName = 'Table')]
        [string]
        $Table,

        [string]
        $SysId,
        
        [string]
        $Number,
        
        [string]
        $Filter,

        [ValidateRange(1, [int]::MaxValue)]
        [int]
        $Limit,

        [string[]]
        $Fields,

        [switch]
        $IncludeCustomVariable,

        [switch]
        $IncludeVariableSet

    )
    
    begin {
        
    }
    
    process {
        switch ($PSCmdlet.ParameterSetName) {
            'ItemType' {
                $Table = Get-ITDServiceNowTable -ItemType $ItemType
            }
            'Table' {
                # examples: 'cmdb_ci_win_server', 'cmdb_ci_ip_network', 'cmdb_ci_service_auto', 'sc_item_option_mtom'
                # don't do anything
            }
        }

        $Uri = ($Script:ServiceNowSession.Uri + "/api/now/table/" + $Table )

        $Body = @{}
        $sysparm_query = @()

        switch ($PSBoundParameters.Keys) {
            SysId {
                $sysparm_query += "sys_id=$SysId"
            }
            Number {
                $sysparm_query += "number=$Number"
            }
            Filter {
                $sysparm_query += $Filter
            }
            Fields {
                $sysparm_fields = $Fields -join ','
            }
        }
        
        If ($PSCmdlet.PagingParameters.IncludeTotalCount) {
        }
        Else {
            If ($PSBoundParameters.ContainsKey('Limit')) {
                $sysparm_limit = $Limit
            }
            Else {
                Write-Verbose "Limited to 10 records returned unless specified with Limit parameter"
                $sysparm_limit = 10;
            }
        }
        
        Write-Verbose $uri
        $Body = @{
            sysparm_limit         = $sysparm_limit;
            sysparm_query         = $sysparm_query -join '^';
            sysparm_display_value = 'all';
            sysparm_fields        = $sysparm_fields;
        }
        
        $InvokeRestMethodParams = @{
            Method      = 'Get';
            Uri         = $Uri
            Headers     = $Script:ServiceNowSession.Headers;
            ContentType = $Script:ServiceNowSession.ContentType;
            Body        = $Body;
        }

        Write-Verbose -Message ($Body.sysparm_query)
        
        try {
            $Result = (Invoke-RestMethod @InvokeRestMethodParams).Result
        }
        catch [System.UriFormatException] {
            Write-Error "Invalid URI session.  Did you run New-ITDServiceNowSession before execution?"
        }
        

        If ($IncludeCustomVariable) {
            ForEach ($Record in $Result) {
                $RecordSysId = $Record.sys_id
                <#
                $CustomFieldsParams = @{
                    Method      = 'Get';
                    Uri         = ($Script:ServiceNowSession.Uri + "/api/now/table/sc_item_option_mtom?request_item=" + $Record.Sys_id)
                    Headers     = $Script:ServiceNowSession.Headers;
                    ContentType = $Script:ServiceNowSession.ContentType;
                }
                $CustomFieldsLookup = (Invoke-RestMethod @CustomFieldsParams).result

                $sc_item_options = ForEach ($CustomField in $CustomFieldsLookup) {
                    #$scitemsysid = $sc_item_option.sc_item_option.value
                    $params = @{
                        Method      = 'Get';
                        Uri         = ($Script:ServiceNowSession.Uri + "/api/now/table/sc_item_option?sys_id=" + $CustomField.sc_item_option.value ); #+ "&sysparm_limit=100"
                        Headers     = ($Script:ServiceNowSession.Headers);
                        ContentType = "application/json"
                    }
                    (Invoke-RestMethod @params).result
                }

                $MyArrayList = [System.Collections.ArrayList]@()
                ForEach ($sc_item_option in $sc_item_options) {
                    $params = @{
                        Method      = 'Get';
                        Uri         = ($Script:ServiceNowSession.Uri + "/api/now/table/item_option_new?sys_id=" + $sc_item_option.item_option_new.value);
                        Headers     = ($Script:ServiceNowSession.Headers);
                        ContentType = "application/json"
                    }
                    $vars = (Invoke-RestMethod @params).result
                    $obj = [PSCustomObject]@{
                        #sc_item_option_sysid = $sc_item_option.sys_id
                        #item_option_new_sysid = $vars.sys_id
                        name          = $vars.name
                        question_text = $vars.question_text
                        value         = $sc_item_option.value
                        type          = $vars.type
                        # YES_NO = 1; MULTI_LINE_TEXT = 2; MULTIPLE_CHOICE = 3; NUMERIC_SCALE = 4; SELECT_BOX = 5; SINGLE_LINE_TEXT = 6; CHECKBOX = 7; REFERENCE = 8; DATE = 9; DATE_TIME = 10; LABEL = 11; BREAK = 12; MACRO = 14; UI_PAGE = 15; WIDE_SINGLE_LINE_TEXT = 16; MACRO_WITH_LABEL = 17; LOOKUP_SELECT_BOX = 18; CONTAINER_START = 19; CONTAINER_END = 20; LIST_COLLECTOR = 21; LOOKUP_MULTIPLE_CHOICE = 22; HTML = 23; SPLIT = 24; MASKED = 25;
                    }
                    $null = $MyArrayList.Add($obj)
                }
                
                $Record | Add-Member @{'CustomFields' = $MyArrayList }
                $Record
            }#>

                $Record | Add-Member @{
                    'CustomVariable' = [pscustomobject]@{}
                }
            
                $InvokeRestMethodParams = @{
                    Method      = 'Get';
                    Uri         = ($Script:ServiceNowSession.Uri + "/api/now/table/sc_item_option_mtom");
                    ContentType = ($Script:ServiceNowSession.ContentType);
                    Headers     = ($Script:ServiceNowSession.Headers);
                    Body        = @{
                        request_item   = $Record.sys_id.value;
                        sysparm_fields = (@('sc_item_option.item_option_new.name', 
                                'sc_item_option.value', 
                                'sc_item_option.item_option_new.type', 
                                'sc_item_option.item_option_new.question_text', 
                                'sc_item_option.item_option_new.reference') -join ',');
                        #sysparm_query  = "sc_item_option.item_option_new.typeIN1,2,3,4,5,6,7,8,9,10,16,18,21,22,26"
                        # YES_NO = 1; MULTI_LINE_TEXT = 2; MULTIPLE_CHOICE = 3; NUMERIC_SCALE = 4; SELECT_BOX = 5; SINGLE_LINE_TEXT = 6; CHECKBOX = 7; REFERENCE = 8; DATE = 9; DATE_TIME = 10; LABEL = 11; BREAK = 12; MACRO = 14; UI_PAGE = 15; WIDE_SINGLE_LINE_TEXT = 16; MACRO_WITH_LABEL = 17; LOOKUP_SELECT_BOX = 18; CONTAINER_START = 19; CONTAINER_END = 20; LIST_COLLECTOR = 21; LOOKUP_MULTIPLE_CHOICE = 22; HTML = 23; SPLIT = 24; MASKED = 25;
                    };
                }
                
                $customVars = (Invoke-RestMethod @InvokeRestMethodParams).result #-ov c
            
                ForEach ($var in $customVars) {
                    $newVar = [pscustomobject] @{
                        Value       = $var.'sc_item_option.value'
                        DisplayName = $var.'sc_item_option.item_option_new.question_text'
                        Type        = $var.'sc_item_option.item_option_new.type'
                    }
                
                    # show the underlying value if the option is a reference type
                    <#if ($newVar.Type -eq 'Reference' ) {
                    $newVar.Value = (Get-ServiceNowRecord -Table $var.'sc_item_option.item_option_new.reference' -ID $var.'sc_item_option.value' -Property name -AsValue -ServiceNowSession $ServiceNowSession)
                    #>
                    $Record.CustomVariable | Add-Member @{ $var.'sc_item_option.item_option_new.name' = $newVar }
                }
                
            }
        }
        else {
            
        }
        If ($IncludeVariableSet) {
            ForEach ($Record in $Result) {
                $InvokeRestMethodParams = @{
                    Method      = 'Get';
                    Uri         = ($Script:ServiceNowSession.Uri + "/api/now/table/sc_multi_row_question_answer?parent_id=" + $Record.sys_id.value);
                    ContentType = ($Script:ServiceNowSession.ContentType);
                    Headers     = ($Script:ServiceNowSession.Headers);
                }
                $AllRows = (Invoke-RestMethod @InvokeRestMethodParams).result

                $Row_Indexes = ($AllRows | Select-Object -Unique row_index).row_index
                
                $ArrayList = [System.Collections.ArrayList]@()
                ForEach ($Row in $Row_Indexes) {
                    $obj = [PSCustomObject]@{}
                    $RowProperties = $AllRows | Where-Object row_index -EQ $Row
                    $RowProperties | ForEach-Object -ThrottleLimit 10 -Parallel {
                        Write-Verbose -Message ("Property start " + ($USING:Script:ServiceNowSession.Uri + "/api/now/table/item_option_new?sys_id=" + $_.item_option_new.value) )
                        $params = @{
                            Method            = 'Get';
                            Uri               = ($USING:Script:ServiceNowSession.Uri + "/api/now/table/item_option_new?sys_id=" + $_.item_option_new.value);
                            ContentType       = ($USING:Script:ServiceNowSession.ContentType);
                            Headers           = ($USING:Script:ServiceNowSession.Headers);
                            MaximumRetryCount = 10;
                            RetryIntervalSec  = 5;
                        }
                        $vars = (Invoke-RestMethod @params).result
                        $USING:obj | Add-Member -MemberType NoteProperty -Name $vars.name -Value $_.value
                    }
                        

                    $null = $ArrayList.Add($obj)
                }

                $Record | Add-Member @{
                    'VariableSet' = $ArrayList
                }
            }
        }
        Write-Output $Result
    }

    end {

    }
}