functions/profile/Import-SldgGenerationProfile.ps1

function Import-SldgGenerationProfile {
    <#
    .SYNOPSIS
        Imports generation rules from a JSON profile file.

    .DESCRIPTION
        Loads a previously exported or manually created JSON profile that defines
        custom generation rules for specific tables and columns. This allows
        consistent, repeatable data generation across environments.

        Supported column rule keys: valueList, staticValue, generator, generatorParams,
        aiGenerationHint, crossColumnDependency, and valueExamples.
        scriptBlock keys are rejected during import to prevent code injection.

        The JSON format is:
        {
            "tables": {
                "dbo.Customer": {
                    "rowCount": 200,
                    "columns": {
                        "Status": { "valueList": ["Active", "Inactive"] },
                        "Currency": { "staticValue": "USD" },
                        "Email": { "generator": "Email" },
                        "ReportData": {
                            "generator": "Json",
                            "aiGenerationHint": "M365 usage report data",
                            "crossColumnDependency": "ReportType"
                        }
                    }
                }
            }
        }

    .PARAMETER Path
        Path to the JSON profile file.

    .PARAMETER Plan
        The generation plan to apply the profile to.

    .EXAMPLE
        PS C:\> $plan = New-SldgGenerationPlan -Schema $schema
        PS C:\> Import-SldgGenerationProfile -Path 'C:\profiles\retail.json' -Plan $plan

        Applies the retail profile to the generation plan.
    #>

    [OutputType([void])]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateScript({ Test-Path $_ })]
        [string]$Path,

        [Parameter(Mandatory)]
        [SqlLabDataGenerator.GenerationPlan]$Plan
    )

    Write-PSFMessage -Level Host -Message ($script:strings.'Profile.Importing' -f $Path)

    # Guard against excessively large profile files (default 10 MB limit)
    $maxProfileSizeMB = 10
    $fileSize = (Get-Item -Path $Path).Length
    if ($fileSize -gt ($maxProfileSizeMB * 1MB)) {
        Stop-PSFFunction -String 'Profile.FileTooLarge' -StringValues $Path, [math]::Round($fileSize / 1MB, 1), $maxProfileSizeMB -EnableException $true
    }

    $rawJson = Get-Content -Path $Path -Raw
    try {
        $profileData = $rawJson | ConvertFrom-Json -ErrorAction Stop
    }
    catch {
        Stop-PSFFunction -String 'Profile.InvalidJson' -StringValues $Path, $_.Exception.Message -EnableException $true
    }

    # Build known generator whitelist from the generator map
    $knownGenerators = @((Get-SldgGeneratorMap).Keys)

    $ruleCount = 0
    $columnOverrides = 0

    # Restore UseAIGeneration flag from profile
    if ($profileData.useAIGeneration) {
        $Plan.UseAIGeneration = $true
    }

    if ($profileData.tables) {
        $tableNames = $profileData.tables.PSObject.Properties.Name
        foreach ($tableName in $tableNames) {
            $tableProfile = $profileData.tables.$tableName

            # Override row count
            if ($tableProfile.rowCount) {
                $tablePlan = $Plan.Tables | Where-Object { $_.FullName -eq $tableName } | Select-Object -First 1
                if ($tablePlan) {
                    try {
                        $tablePlan.RowCount = [int]$tableProfile.rowCount
                    }
                    catch {
                        Write-PSFMessage -Level Warning -Message ($script:strings.'Profile.InvalidRowCount' -f $tableProfile.rowCount, $tableName)
                    }
                }
            }

            # Override column rules
            if ($tableProfile.columns) {
                $colNames = $tableProfile.columns.PSObject.Properties.Name
                foreach ($colName in $colNames) {
                    $colProfile = $tableProfile.columns.$colName

                    # Security guard: reject scriptBlock keys from JSON profiles to prevent code injection (case-insensitive)
                    $hasScriptBlock = $colProfile.PSObject.Properties.Name | Where-Object { $_ -ieq 'scriptBlock' }
                    if ($hasScriptBlock) {
                        Write-PSFMessage -Level Warning -Message ($script:strings.'Profile.ScriptBlockSkipped' -f $Path, $colName, $tableName)
                        continue
                    }

                    # Generator whitelist: reject unknown generator names to prevent injection
                    if ($colProfile.generator -and $colProfile.generator -notin $knownGenerators) {
                        Write-PSFMessage -Level Warning -Message ($script:strings.'Profile.UnknownGenerator' -f $Path, $colName, $tableName, $colProfile.generator, ($knownGenerators -join ', '))
                        continue
                    }

                    # Validate column exists in the plan to avoid silently applying rules to non-existent columns
                    $targetTable = $Plan.Tables | Where-Object { $_.FullName -eq $tableName } | Select-Object -First 1
                    if ($targetTable) {
                        $colExists = $targetTable.Columns | Where-Object { $_.ColumnName -eq $colName }
                        if (-not $colExists) {
                            Write-PSFMessage -Level Warning -Message ($script:strings.'Profile.ColumnNotFound' -f $colName, $tableName, $Path)
                            continue
                        }
                    }

                    $ruleParams = @{
                        Plan       = $Plan
                        TableName  = $tableName
                        ColumnName = $colName
                    }

                    if ($colProfile.valueList) { $ruleParams['ValueList'] = @($colProfile.valueList) }
                    if ($null -ne $colProfile.staticValue) { $ruleParams['StaticValue'] = $colProfile.staticValue }
                    if ($colProfile.generator) { $ruleParams['Generator'] = $colProfile.generator }
                    if ($colProfile.generatorParams) {
                        $params = @{}
                        $colProfile.generatorParams.PSObject.Properties | ForEach-Object { $params[$_.Name] = $_.Value }
                        $ruleParams['GeneratorParams'] = $params
                    }
                    if ($colProfile.aiGenerationHint) { $ruleParams['AIGenerationHint'] = $colProfile.aiGenerationHint }
                    if ($colProfile.crossColumnDependency) { $ruleParams['CrossColumnDependency'] = $colProfile.crossColumnDependency }
                    if ($colProfile.valueExamples) { $ruleParams['ValueExamples'] = @($colProfile.valueExamples) }

                    Set-SldgGenerationRule @ruleParams
                    $columnOverrides++
                }
            }

            $ruleCount++
        }
    }

    Write-PSFMessage -Level Host -Message ($script:strings.'Profile.RuleCount' -f $ruleCount, $columnOverrides)

    # Recalculate totals
    $Plan.TotalRows = ($Plan.Tables | Measure-Object -Property RowCount -Sum).Sum
}