functions/ai/Set-SldgAIProvider.ps1

function Set-SldgAIProvider {
    <#
    .SYNOPSIS
        Configures the AI provider for semantic analysis and data generation.

    .DESCRIPTION
        One-command setup for the AI backend. Configures which AI provider to use
        (Ollama, OpenAI, or AzureOpenAI), the model, endpoint, and generation features.

        For Ollama, no API key is required — just specify the model name and optionally
        the endpoint (defaults to http://localhost:11434).

        Optionally enables AI-powered data generation and AI-powered locale generation.

        Use -Purpose to configure a different AI model for a specific task. This allows
        combining models — e.g. GPT-4 for column analysis but a local Ollama model
        for structured JSON/XML generation.

    .PARAMETER Provider
        The AI provider: Ollama, OpenAI, AzureOpenAI, LiteLLM, or None (to disable AI).
        LiteLLM is a self-hosted proxy that speaks the OpenAI wire format in front of any backend
        (Anthropic, Gemini, Bedrock, Mistral, Ollama, ...); the model name is whatever the proxy
        exposes and the API key is the proxy's virtual key, if it uses one.

    .PARAMETER Model
        The model name (e.g., 'llama3', 'mistral', 'codellama', 'gpt-4', 'gpt-4o').

    .PARAMETER Endpoint
        The API endpoint URL.
        - Ollama: defaults to http://localhost:11434 if not specified
        - AzureOpenAI: required (e.g., https://myinstance.openai.azure.com)
        - OpenAI: not needed (uses api.openai.com); set it to point at another OpenAI-compatible
          server (https only)
        - LiteLLM: defaults to http://localhost:4000; plain http is accepted for loopback only

    .PARAMETER ApiKey
        API key for the provider. Required for OpenAI and AzureOpenAI. Not needed for Ollama.

    .PARAMETER MaxTokens
        Maximum tokens for AI responses. Default: 4096.

    .PARAMETER Temperature
        Temperature for Ollama responses (0.0 = deterministic, 1.0 = creative). Default: 0.3.

    .PARAMETER EnableAIGeneration
        Enable AI-powered data generation. AI generates entire rows of contextually-consistent data.

    .PARAMETER EnableAILocale
        Enable AI-powered locale generation. AI creates locale data on-the-fly for any language.

    .PARAMETER SkipCertificateCheck
        Skip TLS certificate validation (for self-signed certs on Ollama dev servers).

    .PARAMETER Locale
        Set the default locale for data generation (e.g., 'cs-CZ', 'de-DE').

    .PARAMETER Credential
        PSCredential object whose password is used as the API key. Alternative to -ApiKey.

    .PARAMETER Purpose
        Set a per-purpose AI model override instead of the global default. Valid purposes:
        column-analysis, batch-generation, plan-advice, schema-analysis, structured-value,
        locale-data, locale-category.
        When AI runs for that purpose, the override is used instead of the global config.

        Two-tier AI setup example: use a smart cloud model for schema-analysis and a fast
        local model for batch-generation:
          Set-SldgAIProvider -Provider OpenAI -Model 'o3' -ApiKey $key
          Set-SldgAIProvider -Provider Ollama -Model 'llama3' -Purpose batch-generation

    .EXAMPLE
        PS C:\> Set-SldgAIProvider -Provider Ollama -Model 'llama3'

        Configures Ollama with llama3 model on default localhost endpoint.

    .EXAMPLE
        PS C:\> Set-SldgAIProvider -Provider Ollama -Model 'my-custom-model' -Endpoint 'http://gpu-server:11434' -EnableAIGeneration -EnableAILocale -Locale 'cs-CZ'

        Configures a custom Ollama model on a remote server with full AI features and Czech locale.

    .EXAMPLE
        PS C:\> Set-SldgAIProvider -Provider OpenAI -Model 'gpt-4o' -ApiKey $key -EnableAIGeneration

        Configures OpenAI GPT-4o with AI data generation enabled.

    .EXAMPLE
        PS C:\> Set-SldgAIProvider -Provider AzureOpenAI -Model 'gpt-4' -Endpoint 'https://myinstance.openai.azure.com' -ApiKey $key

        Configures Azure OpenAI.

    .EXAMPLE
        PS C:\> Set-SldgAIProvider -Provider LiteLLM -Model 'claude-sonnet' -Endpoint 'http://localhost:4000' -ApiKey $virtualKey

        Routes every AI call through a local LiteLLM proxy; 'claude-sonnet' is the model alias the
        proxy exposes and $virtualKey its virtual key (omit -ApiKey when the proxy runs without one).

    .EXAMPLE
        PS C:\> Set-SldgAIProvider -Provider None

        Disables AI entirely. Falls back to pattern matching and static generators.

    .EXAMPLE
        PS C:\> Set-SldgAIProvider -Provider Ollama -Model 'codellama' -Purpose 'structured-value'

        Uses Ollama codellama specifically for JSON/XML structured value generation,
        while other AI tasks use the global provider.

    .EXAMPLE
        PS C:\> Set-SldgAIProvider -Provider OpenAI -Model 'gpt-4o' -ApiKey $key
        PS C:\> Set-SldgAIProvider -Provider Ollama -Model 'llama3' -Endpoint 'http://gpu:11434' -Purpose 'batch-generation'

        Global: GPT-4o for classification and planning. Override: Ollama for batch data generation.
    #>

    [OutputType([SqlLabDataGenerator.AIProviderInfo])]
    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory)]
        [ValidateSet('None', 'OpenAI', 'AzureOpenAI', 'Ollama', 'LiteLLM')]
        [string]$Provider,

        [string]$Model,

        [string]$Endpoint,

        [SecureString]$ApiKey,

        [PSCredential]$Credential,

        [int]$MaxTokens,

        [double]$Temperature,

        [switch]$EnableAIGeneration,

        [switch]$EnableAILocale,

        [switch]$SkipCertificateCheck,

        [string]$Locale,

        [ValidateSet('column-analysis', 'batch-generation', 'plan-advice', 'schema-analysis', 'structured-value', 'locale-data', 'locale-category')]
        [string]$Purpose
    )

    if (-not $PSCmdlet.ShouldProcess($Provider, 'Set AI provider')) { return }

    # Helper: validate endpoint URI for cloud providers
    $validateEndpoint = {
        param ([string]$EndpointUri, [string]$ProviderName)
        if ($ProviderName -notin @('OpenAI', 'AzureOpenAI', 'LiteLLM')) { return }
        try {
            $parsedUri = [System.Uri]::new($EndpointUri)
            if ($parsedUri.UserInfo) {
                Stop-PSFFunction -String 'AI.EndpointCredentialsForbidden' -EnableException $true
            }
            # A LiteLLM proxy is commonly self-hosted next to the caller; plain http is accepted for
            # loopback only, the same rule Ollama gets. Anything reachable over the network needs TLS.
            $loopback = $parsedUri.IsLoopback
            if ($parsedUri.Scheme -ne 'https' -and -not ($ProviderName -eq 'LiteLLM' -and $loopback)) {
                Stop-PSFFunction -String 'AI.EndpointHttpsForbidden' -StringValues $ProviderName, $parsedUri.Scheme, $parsedUri.Host -EnableException $true
            }
        } catch [System.UriFormatException] {
            Stop-PSFFunction -String 'AI.EndpointInvalidUri' -StringValues $ProviderName -EnableException $true
        }
    }

    # Per-purpose override mode
    if ($Purpose) {
        $override = @{ Provider = $Provider }

        if ($Model) { $override['Model'] = $Model }
        elseif ($Provider -eq 'Ollama') { $override['Model'] = 'llama3' }

        if ($Endpoint) {
            & $validateEndpoint $Endpoint $Provider
            $override['Endpoint'] = $Endpoint
        }
        elseif ($Provider -eq 'Ollama') { $override['Endpoint'] = 'http://localhost:11434' }
        elseif ($Provider -eq 'LiteLLM') { $override['Endpoint'] = 'http://localhost:4000' }

        if ($Credential) {
            $override['ApiKey'] = $Credential.Password
        }
        elseif ($ApiKey) {
            $override['ApiKey'] = $ApiKey
        }

        if ($MaxTokens -gt 0) { $override['MaxTokens'] = $MaxTokens }
        if ($PSBoundParameters.ContainsKey('Temperature')) { $override['Temperature'] = $Temperature }

        $script:SldgState.AIModelOverrides[$Purpose] = $override
        Write-PSFMessage -Level Host -Message ($script:strings.'AI.OverrideSet' -f $Purpose, $Provider, $override['Model'])

        return [SqlLabDataGenerator.AIModelOverride]@{
            Purpose    = $Purpose
            Provider   = $Provider
            Model      = $override['Model']
            Endpoint   = $override['Endpoint']
            MaxTokens  = $override['MaxTokens']
        }
    }

    # Global provider configuration
    Set-PSFConfig -FullName 'SqlLabDataGenerator.AI.Provider' -Value $Provider

    # Model
    if ($Model) {
        Set-PSFConfig -FullName 'SqlLabDataGenerator.AI.Model' -Value $Model
    }
    elseif ($Provider -eq 'Ollama' -and -not (Get-PSFConfigValue -FullName 'SqlLabDataGenerator.AI.Model')) {
        Set-PSFConfig -FullName 'SqlLabDataGenerator.AI.Model' -Value 'llama3'
    }

    # Endpoint
    if ($Endpoint) {
        & $validateEndpoint $Endpoint $Provider
        Set-PSFConfig -FullName 'SqlLabDataGenerator.AI.Endpoint' -Value $Endpoint
    }
    elseif ($Provider -in @('Ollama', 'LiteLLM')) {
        $current = Get-PSFConfigValue -FullName 'SqlLabDataGenerator.AI.Endpoint'
        if (-not $current) {
            $defaultEndpoint = if ($Provider -eq 'Ollama') { 'http://localhost:11434' } else { 'http://localhost:4000' }
            Set-PSFConfig -FullName 'SqlLabDataGenerator.AI.Endpoint' -Value $defaultEndpoint
        }
    }

    # API Key (store as SecureString)
    if ($Credential) {
        $secureKey = $Credential.Password
        Set-PSFConfig -FullName 'SqlLabDataGenerator.AI.ApiKey' -Value $secureKey
    }
    elseif ($ApiKey) {
        Set-PSFConfig -FullName 'SqlLabDataGenerator.AI.ApiKey' -Value $ApiKey
    }

    # MaxTokens
    if ($MaxTokens -gt 0) {
        Set-PSFConfig -FullName 'SqlLabDataGenerator.AI.MaxTokens' -Value $MaxTokens
    }

    # Temperature (Ollama)
    if ($PSBoundParameters.ContainsKey('Temperature')) {
        Set-PSFConfig -FullName 'SqlLabDataGenerator.AI.Ollama.Temperature' -Value $Temperature
    }

    # SkipCertificateCheck (Ollama)
    if ($SkipCertificateCheck) {
        Write-PSFMessage -Level Warning -Message $script:strings.'AI.TLSDisabledWarning'
        Set-PSFConfig -FullName 'SqlLabDataGenerator.AI.Ollama.SkipCertificateCheck' -Value $true
    }

    # AI Generation
    if ($EnableAIGeneration) {
        Set-PSFConfig -FullName 'SqlLabDataGenerator.Generation.AIGeneration' -Value $true
    }

    # AI Locale
    if ($EnableAILocale) {
        Set-PSFConfig -FullName 'SqlLabDataGenerator.Generation.AILocale' -Value $true
    }

    # Locale
    if ($Locale) {
        Set-PSFConfig -FullName 'SqlLabDataGenerator.Generation.Locale' -Value $Locale
    }

    # Clear caches when provider changes
    $script:SldgState.ClearCaches()

    # Display summary
    $config = Get-SldgAIProvider
    Write-PSFMessage -Level Host -Message ($script:strings.'AI.ProviderConfigured' -f $Provider, (Get-PSFConfigValue -FullName 'SqlLabDataGenerator.AI.Model'))

    $config
}