function Get-ModuleVersion
{
    '1.0.0'
}

function Invoke-InitializeModule
{
    Add-OutputType ([PSCustomObject]@{
        Name="Markdown (Experimental)"
        Value="md"
        #OutputOptions = (Add-MDOptionsControl)
        #Activate = { Invoke-MDActivate @args }
        PreProcess = { Invoke-MDPreProcessItems @args }
        NewObjectGroup = { Invoke-MDNewObjectGroup @args }
        Process = { Invoke-MDProcessItem @args }
        PostProcess = { Invoke-MDPostProcessItems @args }
        ProcessAllObjects = { Invoke-MDProcessAllObjects @args }
    })        
}



function Invoke-MDPreProcessItems
{
    $script:mdStrings = [System.Text.StringBuilder]::new()
    $script:sectionAnchors = @()
    $script:totAnchors = @()
}

function Invoke-MDPostProcessItems
{
    $userName = $global:me.displayName
    if($global:me.givenName -and $global:me.surname)
    {
        $userName = ($global:me.givenName + " " + $global:me.surname)
    }

    $script:mdContent = [System.Text.StringBuilder]::new()

    $script:mdContent.AppendLine("# $((?? $global:txtMDTitleProperty.Text "Intune documentation"))")
    $script:mdContent.AppendLine("")
    $script:mdContent.AppendLine("")

    $mail = ""
    if($global:me.mail)
    {
        $mail = " ($($global:me.mail))"
    }

    $script:mdContent.AppendLine("*Organization:* $($global:Organization.displayName)`n")
    $script:mdContent.AppendLine("*Generated by:* $userName$mail`n")
    $script:mdContent.AppendLine("*Generated:* $((Get-Date).ToShortDateString()) $((Get-Date).ToLongTimeString())`n")

    if($script:sectionAnchors.Count -gt 0)
    {
        $script:mdContent.AppendLine("")
        $script:mdContent.AppendLine("## Table of Contents")
    }

    foreach($header in $script:sectionAnchors)
    {
        $script:mdContent.AppendLine("[$($header.Name)](#$($header.Anchor))`n")
    }

    $script:mdContent.AppendLine("")
    $mdText = $script:mdContent.ToString() 
    $mdText += $script:mdStrings.ToString()
    
    $fileName = Expand-FileName "%MyDocuments%\%Organization%-%Date%.md"
    
    try
    {
        $mdText | Out-File -FilePath $fileName -Force -Encoding utf8 -ErrorAction Stop
        Write-Log "Markdown document $fileName saved successfully"
    }
    catch
    {
        Write-LogError "Failed to save Markdown file" $_.Exception
    }
}

function Invoke-MDNewObjectGroup
{
    param($obj, $documentedObj)

    $objectTypeString = Get-ObjectTypeString $obj.Object $obj.ObjectType

    Add-MDHeader "$((?? $objectTypeString $obj.ObjectType.Title))" -Level 1 -USEHtml

}

function Invoke-MDProcessItem
{
    param($obj, $objectType, $documentedObj)

    if(!$documentedObj -or !$obj -or !$objectType) { return }

    $objName = Get-GraphObjectName $obj $objectType

    Add-MDHeader $objName -Level 2 -USEHtml

    $script:mdStrings.AppendLine("")

    try 
    {
        foreach($tableType in @("BasicInfo","FilteredSettings"))
        {
            if($tableType -eq "BasicInfo")
            {
                $properties = @("Name","Value")
            }
            elseif($global:cbMDDocumentationProperties.SelectedValue -eq 'extended' -and $documentedObj.DisplayProperties)
            {
                $properties = @("Name","Value","Description")
            }
            elseif($global:cbMDDocumentationProperties.SelectedValue -eq 'custom' -and $global:txtMDCustomProperties.Text)
            {
                $properties = @()
                
                foreach($prop in $global:txtMDCustomProperties.Text.Split(","))
                {
                    # This will add language support for custom columens (or replacing existing header)
                    $propInfo = $prop.Split('=')
                    if(($propInfo | measure).Count -gt 1)
                    {
                        $properties += $propInfo[0] 
                        Set-DocColumnHeaderLanguageId $propInfo[0] $propInfo[1]
                    }
                    else
                    {
                        $properties += $prop
                    }
                }
            }        
            else
            {
                $properties = (?? $documentedObj.DefaultDocumentationProperties (@("Name","Value")))
            }
            
            $lngId = ?: ($tableType -eq "BasicInfo") "SettingDetails.basics" "TableHeaders.settings" -AddCategories

            Add-MDTableItems $obj $objectType ($documentedObj.$tableType) $properties $lngId -AddCategories -AddSubcategories

            #Add-MDTableItems $obj $objectType ($documentedObj.$tableType) $properties $lngId `
            #    -AddCategories:($global:chkMDAddCategories.IsChecked -eq $true) `
            #    -AddSubcategories:($global:chkMDAddSubCategories.IsChecked -eq $true)                
        }

        if(($documentedObj.ComplianceActions | measure).Count -gt 0)
        {
            $properties = @("Action","Schedule","MessageTemplate","EmailCC")

            Add-MDTableItems $obj $objectType $documentedObj.ComplianceActions $properties "Category.complianceActionsLabel"
        }

        if(($documentedObj.ApplicabilityRules | measure).Count -gt 0)
        {
            $properties = @("Rule","Property","Value")

            Add-MDTableItems $obj $objectType $documentedObj.ApplicabilityRules $properties "SettingDetails.applicabilityRules"
        }

        Add-MDObjectSettings $obj $objectType $documentedObj

        if(($documentedObj.Assignments | measure).Count -gt 0)
        {
            $params = @{}
            if($documentedObj.Assignments[0].RawIntent)
            {
                $properties = @("GroupMode","Group","Filter","FilterMode")
            
                $settingsObj = $documentedObj.Assignments | Where { $_.Settings -ne $null } | Select -First 1

                if($settingsObj)
                {
                    foreach($objProp in $settingsObj.Settings.Keys)
                    {
                        if($objProp -in $properties) { continue }
                        if($objProp -in @("Category","RawIntent")) { continue }
                        $properties += ("Settings." + $objProp)
                    }
                }
            }
            else
            {
                $isFilterAssignment = $false
                foreach($assignment in $documentedObj.Assignments)
                {
                    if(($assignment.target.PSObject.Properties | Where Name -eq "deviceAndAppManagementAssignmentFilterType"))
                    {
                        $isFilterAssignment = $true
                        break
                    }
                }
                $properties = @("Group")
                if($isFilterAssignment)
                {
                    $properties += @("Filter","FilterMode")
                }
                $params.Add("AddCategories", $true)
            }

            Add-MDTableItems $obj $objectType $documentedObj.Assignments $properties "TableHeaders.assignments" @params
        }
    }
    catch 
    {
        Write-LogError "Failed to process object $objName" $_.Exception
    }    
}

function Add-MDTableItems
{
    param($obj, $objectType, $items, $properties, $lngId, [switch]$AddCategories, [switch]$AddSubcategories, $captionOverride)

    if($captionOverride)
    {
        $caption = $captionOverride
    }
    elseif($lngId)
    {
        $caption = "$((Get-LanguageString $lngId)) - $((Get-GraphObjectName $obj $objectType))"
    }
    else
    {
        $caption = "$((Get-GraphObjectName $obj $objectType)) ($($objectType.Title))"
    }

    $tableText =  [System.Text.StringBuilder]::new()
    $tableText.AppendLine("<table>")
    $tableText.AppendLine("<tr>")
    $columnHeaders = "|"
    $columnChars = "|"
    $columnCount = 0
    foreach($prop in $properties)
    {
        $tableText.AppendLine("<td> $($prop.Split(".")[-1]) </td>")
        $columnCount++

        $columnHeaders += ((Invoke-DocTranslateColumnHeader ($prop.Split(".")[-1])) + "|")
        $columnChars += "----|"
    }
    $tableText.AppendLine("</tr>")

    #Add-MDText $columnHeaders
    #Add-MDText $columnChars
    
    $curCategory = ""
    $curSubCategory = ""

    $columnCategory = $null
    $columnSubCategory = $null

    foreach($itemObj in $items)
    {
        if($itemObj.Category -and $curCategory -ne $itemObj.Category -and $AddCategories -eq $true)
        {
            $tableText.AppendLine("<tr>")
            $tableText.AppendLine("<td colspan=`"$($columnCount)`">`n`n**$((Set-MDText $itemObj.Category))**`n`n</td>")
            $tableText.AppendLine("</tr>")

            #$columnCategory = "|**" + (Set-MDText $itemObj.Category) + "**|"
            #Add-MDText $columnCategory
            $curCategory = $itemObj.Category
            $curSubCategory = ""
        }

        if($itemObj.SubCategory -and $curSubCategory -ne $itemObj.SubCategory -and $AddSubcategories -eq $true)
        {
            $tableText.AppendLine("<tr>")
            $tableText.AppendLine("<td colspan=`"$($columnCount)`">`n`n***$((Set-MDText $itemObj.SubCategory))***`n`n</td>")
            $tableText.AppendLine("</tr>")

            #$columnSubCategory = "|***" + (Set-MDText $itemObj.SubCategory) + "***|"
            #Add-MDText $columnSubCategory
            $curSubCategory = $itemObj.SubCategory
        }        

        #$columnData = "|"
        try 
        {   
            $tableText.AppendLine("<tr>")

            foreach($prop in $properties)
            {
                try
                {
                    # This adds support for properties like Settings.PropName
                    $propArr = $prop.Split('.')
                    $tmpObj = $itemObj
                    $propName = $propArr[-1]
                    for($x = 0; $x -lt ($propArr.Count - 1);$x++)
                    {
                        $tmpObj = $tmpObj."$($propArr[$x])"
                    }
                    $tableText.AppendLine("<td>$((Set-MDText "$($tmpObj.$propName)" -CodeBlock))</td>")
                    #$columnData += "$((Set-MDText "$($tmpObj.$propName)"))|"
                }
                catch
                {
                    #$columnData += "|"
                    Write-LogError "Failed to add property value for $prop" $_.Exception
                }
            }
                          
        }
        catch 
        {
            Write-Log "Failed to process property" 2    
        }
        finally 
        {
            $tableText.AppendLine("</tr>")
        }

        #Add-MDText $columnData 
    }

    $tableText.AppendLine("</table>")
    Add-MDText $tableText.ToString()
    
    Add-MDHeader $caption -Level 6 -TOT -AddParagraph
}

function Add-MDText
{
    param($text, [switch]$AddParagraph)

    $script:mdStrings.AppendLine($text)

    if($AddParagraph -eq $true)
    {
        # Add new paragraph by default
        $script:mdStrings.AppendLine("")
    }
}

function Set-MDText
{
    param($text, [switch]$CodeBlock)

    if($CodeBlock -eq $true)
    {
        $trimText = $text.Trim()
        if($trimText.StartsWith("<") -and $trimText.EndsWith(">"))
        {
            return ([Environment]::NewLine + [Environment]::NewLine + "``````xml" + [Environment]::NewLine + $text  + [Environment]::NewLine + "``````" + [Environment]::NewLine + [Environment]::NewLine)
        }
    }

    $text = $text.Replace("|", '`|')
    $text = $text.Replace("*", '`*')
    $text = $text.Replace("$", '`$')
    $text = $text.Replace("`r`n", "<br />")
    $text = $text.Replace("`n", "<br />")

    $text
}

function Add-MDHeader
{
    param($text, [int]$level = 1, [switch]$AddParagraph, [switch]$UseHTML, [switch]$ToT, [switch]$SkipTOC)

    $prefix = ""
    if($ToT -eq $true)
    {
        $prefix = "Table $(($script:totAnchors.Count + 1)). "
    }    

    if($UseHTML -eq $true)
    {
        if($ToT -eq $true)
        {
            $sectionAnchor = "table-$(($script:totAnchors.Count + 1))"            
        }
        else
        {
            $sectionAnchor = "section-$(($script:sectionAnchors.Count + 1))"
        }
        
        $script:mdStrings.AppendLine("<h$level id=`"$prefix$($sectionAnchor)`">$text</h$level>")
    }
    else 
    {
        # Warnig: Not complete! Use HTML if not working...
        $text = "$prefix$text"
        $sectionAnchor = $text.ToLower().Replace(" ","-").Replace("[","").Replace("]","")

        $mdHeader = [String]::new('#',$level)
        $script:mdStrings.AppendLine("$mdHeader $text")            
    }
    
    if($ToT -eq $true)
    {
        $script:totAnchors += [PSCustomObject]@{
            Name = $text
            Anchor = $sectionAnchor
        }
    }
    elseif($SkipTOC -ne $true)
    {
        $script:sectionAnchors += [PSCustomObject]@{
            Name = $text
            Anchor = $sectionAnchor
        }
    }    

    if($AddParagraph -eq $true)
    {
        # Add new paragraph by default
        $script:mdStrings.AppendLine("`n")
    } 
}

function Add-MDObjectSettings 
{
    param($obj, $objectType, $documentedObj)

    if($obj."@OData.Type" -eq "#microsoft.graph.deviceManagementScript")
    {
        if($obj.ScriptContent)
        {
            $script:mdStrings.AppendLine("~~~powershell")
            $script:mdStrings.AppendLine((Get-DocScriptContent $obj.ScriptContent))
            $script:mdStrings.AppendLine("~~~")
            $caption = "{1} - {0}" -f $obj.fileName,(Get-LanguageString "WindowsManagement.powerShellScriptObjectName")            
            Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
        }
    }
    if($obj."@OData.Type" -eq "#microsoft.graph.deviceShellScript")
    {
        if($obj.ScriptContent)
        {
            $script:mdStrings.AppendLine("~~~shell")
            $script:mdStrings.AppendLine((Get-DocScriptContent $obj.ScriptContent))
            $script:mdStrings.AppendLine("~~~")

            $caption = "{1} - {0}" -f $obj.fileName,(Get-LanguageString "WindowsManagement.shellScriptObjectName")
            Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
        }
    }
    elseif($obj."@OData.Type" -eq "#microsoft.graph.deviceHealthScript")
    {
        if($obj.detectionScriptContent)
        {
            $script:mdStrings.AppendLine("~~~powershell")
            $script:mdStrings.AppendLine((Get-DocScriptContent $obj.detectionScriptContent))
            $script:mdStrings.AppendLine("~~~")
            $caption = Get-LanguageString "ProactiveRemediations.Create.Settings.DetectionScriptMultiLineTextBox.label"
            Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
        }

        if($obj.remediationScriptContent)
        {
            $script:mdStrings.AppendLine("~~~powershell")
            $script:mdStrings.AppendLine((Get-DocScriptContent $obj.remediationScriptContent))
            $script:mdStrings.AppendLine("~~~")
            $caption = Get-LanguageString "ProactiveRemediations.Create.Settings.RemediationScriptMultiLineTextBox.label"
            Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
        }        
    }
    elseif($obj."@OData.Type" -eq "#microsoft.graph.win32LobApp")
    {
        foreach($rule in ($obj.requirementRules | Where { $_.'@OData.Type' -eq "#microsoft.graph.win32LobAppPowerShellScriptRequirement" } ))
        {
            $script:mdStrings.AppendLine("~~~powershell")
            $script:mdStrings.AppendLine((Get-DocScriptContent $obj.scriptContent))
            $script:mdStrings.AppendLine("~~~")
            $caption = "{0} - {1}" -f @($obj.displayName, "Requirement script")
            Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
        }

        foreach($rule in ($obj.detectionRules | Where { $_.'@OData.Type' -eq "#microsoft.graph.win32LobAppPowerShellScriptDetection" } ))
        {
            $script:mdStrings.AppendLine("~~~powershell")
            $script:mdStrings.AppendLine((Get-DocScriptContent $obj.scriptContent))
            $script:mdStrings.AppendLine("~~~")
            $caption = "{0} - {1}" -f @($obj.displayName,(Get-LanguageString "ProactiveRemediations.Create.Settings.DetectionScriptMultiLineTextBox.label"))
            Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
        }        
    }
}