#!/usr/bin/env pwsh
<#
.SYNOPSIS
    Freeze an approved model/dataset VersionSet for Phase 1 shadow run.

.DESCRIPTION
    Parameterized tool to INSERT approved model_id + dataset_id into:
    - governance.model_version_registry (FROZEN status)
    - evaluation.dataset_manifest (FROZEN status)

    NO default values; all parameters REQUIRED. Fails immediately if any parameter is missing.

.PARAMETER ModelId
    UUID of the approved model (e.g., "00000000-0000-0000-0000-000000000001")
    Required. No default.

.PARAMETER DatasetId
    UUID of the approved dataset (e.g., "00000000-0000-0000-0000-000000000002")
    Required. No default.

.PARAMETER ApprovedBy
    Email/ID of the approver (e.g., "kjh2064@gmail.com")
    Required. No default.

.PARAMETER ConfigVersion
    Configuration version string (e.g., "v1.0.0")
    Required. No default.

.PARAMETER CodeSha
    Git commit SHA (e.g., "acaa731b3f")
    Required. No default.

.PARAMETER ConnectionString
    PostgreSQL connection string.
    Default: $env:KARTSELL_POSTGRES

.EXAMPLE
    # Freeze a versionset (all parameters required)
    .\freeze-versionset.ps1 `
        -ModelId "00000000-0000-0000-0000-000000000001" `
        -DatasetId "00000000-0000-0000-0000-000000000002" `
        -ApprovedBy "kjh2064@gmail.com" `
        -ConfigVersion "v1.0.0" `
        -CodeSha "acaa731b3f"

.EXAMPLE
    # Will fail: missing -ConfigVersion
    .\freeze-versionset.ps1 `
        -ModelId "00000000-0000-0000-0000-000000000001" `
        -DatasetId "00000000-0000-0000-0000-000000000002" `
        -ApprovedBy "kjh2064@gmail.com" `
        -CodeSha "acaa731b3f"
    # Error: Cannot bind argument to parameter 'ConfigVersion' because it is an empty string.
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory, HelpMessage = "Model UUID (e.g., 00000000-0000-0000-0000-000000000001)")]
    [ValidateScript({ $_ -match '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' })]
    [string]$ModelId,

    [Parameter(Mandatory, HelpMessage = "Dataset UUID")]
    [ValidateScript({ $_ -match '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' })]
    [string]$DatasetId,

    [Parameter(Mandatory, HelpMessage = "Approver email/ID (e.g., kjh2064@gmail.com)")]
    [ValidateScript({ $_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' })]
    [string]$ApprovedBy,

    [Parameter(Mandatory, HelpMessage = "Config version (e.g., v1.0.0)")]
    [ValidateScript({ $_ -match '^v[0-9]+\.[0-9]+\.[0-9]+' })]
    [string]$ConfigVersion,

    [Parameter(Mandatory, HelpMessage = "Git commit SHA (at least 10 chars)")]
    [ValidateScript({ $_.Length -ge 10 })]
    [string]$CodeSha,

    [string]$ConnectionString = $env:KARTSELL_POSTGRES
)

$ErrorActionPreference = 'Stop'

Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan
Write-Host "Phase 1: Freeze VersionSet" -ForegroundColor Cyan
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan

# Validate connection string
if (-not $ConnectionString) {
    Write-Error "ConnectionString not provided and `$env:KARTSELL_POSTGRES not set. Aborting."
    exit 1
}

Write-Host "`n[1/3] PRE-FLIGHT CHECK"
Write-Host "  Model ID:        $ModelId"
Write-Host "  Dataset ID:      $DatasetId"
Write-Host "  Approved By:     $ApprovedBy"
Write-Host "  Config Version:  $ConfigVersion"
Write-Host "  Code SHA:        $CodeSha"
Write-Host "  Connection:      $(($ConnectionString -split 'Password=')[0])***"

# Verify 0032 migration is deployed
Write-Host "`n[2/3] VERIFY Migration 0032 deployed..."
try {
    $conn = New-Object System.Data.NpgsqlClient.NpgsqlConnection($ConnectionString)
    $conn.Open()

    $cmd = $conn.CreateCommand()
    $cmd.CommandText = @"
SELECT schema_version FROM schema_version_history
WHERE script_name = '0032_shadow_run_queued_status_contract.sql'
LIMIT 1
"@
    $result = $cmd.ExecuteScalar()

    if ($null -eq $result) {
        throw "Migration 0032 NOT FOUND. Run DbMigrator first."
    }

    Write-Host "  ✅ Migration 0032 deployed (schema_version: $result)"
    $conn.Close()
}
catch {
    Write-Error "  ❌ Pre-flight failed: $_`n`nCorrective: Run DbMigrator to deploy 0032_*.sql before freezing."
    exit 1
}

# Insert into governance.model_version_registry
Write-Host "`n[3/3] FREEZE VersionSet..."

try {
    $conn = New-Object System.Data.NpgsqlClient.NpgsqlConnection($ConnectionString)
    $conn.Open()

    $correlationId = [System.Guid]::NewGuid()
    $now = [System.DateTime]::UtcNow

    $cmd = $conn.CreateCommand()
    $cmd.CommandText = @"
INSERT INTO governance.model_version_registry (
    id, model_id, dataset_id, status, approved_by, config_version, code_sha,
    effective_at, published_at, revision, correlation_id
) VALUES (
    @id, @model_id, @dataset_id, 'FROZEN', @approved_by, @config_version, @code_sha,
    @effective_at, @published_at, 1, @correlation_id
)
ON CONFLICT (model_id, dataset_id) DO UPDATE SET
    status = 'FROZEN',
    approved_by = EXCLUDED.approved_by,
    config_version = EXCLUDED.config_version,
    code_sha = EXCLUDED.code_sha,
    effective_at = EXCLUDED.effective_at,
    revision = governance.model_version_registry.revision + 1,
    published_at = EXCLUDED.published_at
RETURNING id, model_id, dataset_id, status, effective_at
"@

    $cmd.Parameters.AddWithValue("@id", [System.Guid]::NewGuid()) | Out-Null
    $cmd.Parameters.AddWithValue("@model_id", [System.Guid]$ModelId) | Out-Null
    $cmd.Parameters.AddWithValue("@dataset_id", [System.Guid]$DatasetId) | Out-Null
    $cmd.Parameters.AddWithValue("@approved_by", $ApprovedBy) | Out-Null
    $cmd.Parameters.AddWithValue("@config_version", $ConfigVersion) | Out-Null
    $cmd.Parameters.AddWithValue("@code_sha", $CodeSha) | Out-Null
    $cmd.Parameters.AddWithValue("@effective_at", $now) | Out-Null
    $cmd.Parameters.AddWithValue("@published_at", $now) | Out-Null
    $cmd.Parameters.AddWithValue("@correlation_id", $correlationId) | Out-Null

    $reader = $cmd.ExecuteReader()
    if ($reader.Read()) {
        $insertedId = $reader['id']
        $insertedModelId = $reader['model_id']
        $insertedDatasetId = $reader['dataset_id']
        $insertedStatus = $reader['status']

        Write-Host "  ✅ Inserted governance.model_version_registry:"
        Write-Host "     - ID:      $insertedId"
        Write-Host "     - Model:   $insertedModelId"
        Write-Host "     - Dataset: $insertedDatasetId"
        Write-Host "     - Status:  $insertedStatus"
    }
    $reader.Close()

    # Update evaluation.dataset_manifest
    $cmd2 = $conn.CreateCommand()
    $cmd2.CommandText = @"
INSERT INTO evaluation.dataset_manifest (
    id, dataset_id, model_id, status, freeze_reason,
    published_at, revision, correlation_id
) VALUES (
    @id, @dataset_id, @model_id, 'FROZEN', 'Phase 1 VersionSet freeze',
    @published_at, 1, @correlation_id
)
ON CONFLICT (dataset_id, model_id) DO UPDATE SET
    status = 'FROZEN',
    freeze_reason = 'Phase 1 VersionSet freeze',
    revision = evaluation.dataset_manifest.revision + 1,
    published_at = EXCLUDED.published_at
RETURNING id, dataset_id, model_id, status
"@

    $cmd2.Parameters.AddWithValue("@id", [System.Guid]::NewGuid()) | Out-Null
    $cmd2.Parameters.AddWithValue("@dataset_id", [System.Guid]$DatasetId) | Out-Null
    $cmd2.Parameters.AddWithValue("@model_id", [System.Guid]$ModelId) | Out-Null
    $cmd2.Parameters.AddWithValue("@published_at", $now) | Out-Null
    $cmd2.Parameters.AddWithValue("@correlation_id", $correlationId) | Out-Null

    $reader2 = $cmd2.ExecuteReader()
    if ($reader2.Read()) {
        $mId = $reader2['id']
        $mDatasetId = $reader2['dataset_id']
        $mModelId = $reader2['model_id']
        $mStatus = $reader2['status']

        Write-Host "  ✅ Inserted evaluation.dataset_manifest:"
        Write-Host "     - ID:      $mId"
        Write-Host "     - Dataset: $mDatasetId"
        Write-Host "     - Model:   $mModelId"
        Write-Host "     - Status:  $mStatus"
    }
    $reader2.Close()

    $conn.Close()

    Write-Host "`n✅ VersionSet FROZEN successfully"
    Write-Host "   Correlation ID: $correlationId"
    Write-Host "   Next: Run generate-shadow-run-identifiers.ps1 to create RunId/JobId"
}
catch {
    Write-Error "  ❌ Failed to freeze VersionSet: $_"
    exit 1
}

Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan
