# K_Recycle - PostInstall (RentRoom pattern: scripts from $PSScriptRoot = ZIP\install\)
param(
    [Parameter(Mandatory = $true)]
    [string]$AppDir
)

$ErrorActionPreference = 'Stop'

$InstallDir = $PSScriptRoot
$BundleRoot = Split-Path $InstallDir -Parent
$SqlSourceDir = Join-Path $BundleRoot 'sql'
$LogFile = Join-Path $AppDir 'install\install.log'

$SqlInstanceName = 'SQLEXPRESS'
$ServerName = ".\$SqlInstanceName"
$SaUser = 'sa'
$SaPassword = '1qaz@WSX'
$SaPasswordLegacy = @('StrongPassword123!', '1qaz#@WSX')
$DatabaseName = 'DB_PF_RECYCLE'

function Write-Log {
    param([string]$Message)
    $line = "[{0}] {1}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Message
    Add-Content -Path $LogFile -Value $line -Encoding UTF8
}

function Invoke-LoggedScript {
    param([string]$ScriptPath, [string]$WorkDir = $env:TEMP)
    Write-Log "Running: $ScriptPath -WorkDir $WorkDir"
    $out = Join-Path $env:TEMP "KRecycle-$(Split-Path $ScriptPath -Leaf).log"
    & $ScriptPath -WorkDir $WorkDir *>&1 | Tee-Object -FilePath $out
    $code = $LASTEXITCODE
    if (Test-Path $out) {
        Get-Content $out | ForEach-Object { Write-Log $_.ToString() }
    }
    if ($code -ne 0 -and $code -ne 3010) {
        throw "Script failed: $ScriptPath ExitCode=$code"
    }
}

function Find-SqlCmd {
    $candidates = @(
        "${env:ProgramFiles}\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\SQLCMD.EXE",
        "${env:ProgramFiles}\Microsoft SQL Server\Client SDK\ODBC\130\Tools\Binn\SQLCMD.EXE",
        "${env:ProgramFiles(x86)}\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\SQLCMD.EXE",
        "${env:ProgramFiles}\Microsoft SQL Server\150\Tools\Binn\SQLCMD.EXE"
    )
    foreach ($path in $candidates) {
        if (Test-Path $path) { return $path }
    }
    $cmd = Get-Command sqlcmd.exe -ErrorAction SilentlyContinue
    if ($cmd) { return $cmd.Source }
    return $null
}

function Wait-ForSqlService {
    param([int]$TimeoutSeconds = 600)
    $serviceName = "MSSQL`$$SqlInstanceName"
    $elapsed = 0
    while ($elapsed -lt $TimeoutSeconds) {
        $svc = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
        if ($svc -and $svc.Status -eq 'Running') {
            Start-Sleep -Seconds 8
            return $true
        }
        Start-Sleep -Seconds 5
        $elapsed += 5
    }
    return $false
}

function Test-SqlLogin {
    param([string]$SqlCmdPath, [string]$User, [string]$Password = '')
    if ($User -eq ':E') {
        $null = & $SqlCmdPath -S $ServerName -E -Q 'SELECT 1' -h -1 -W 2>&1
    }
    elseif ([string]::IsNullOrEmpty($Password)) {
        $null = & $SqlCmdPath -S $ServerName -U $User -Q 'SELECT 1' -h -1 -W 2>&1
    }
    else {
        $null = & $SqlCmdPath -S $ServerName -U $User -P $Password -Q 'SELECT 1' -h -1 -W 2>&1
    }
    return $LASTEXITCODE -eq 0
}

function Set-SaStandardPassword {
    param([string]$SqlCmdPath, [string]$AuthMode, [string]$AuthUser = '', [string]$AuthPassword = '')
    $alterSql = @"
ALTER LOGIN [$SaUser] ENABLE;
ALTER LOGIN [$SaUser] WITH PASSWORD = N'$SaPassword', CHECK_POLICY = OFF;
"@
    if ($AuthMode -eq 'Windows') {
        $null = & $SqlCmdPath -S $ServerName -E -Q $alterSql 2>&1
    }
    elseif ([string]::IsNullOrEmpty($AuthPassword)) {
        $null = & $SqlCmdPath -S $ServerName -U $AuthUser -Q $alterSql 2>&1
    }
    else {
        $null = & $SqlCmdPath -S $ServerName -U $AuthUser -P $AuthPassword -Q $alterSql 2>&1
    }
    if ($LASTEXITCODE -ne 0) { throw "Failed to set sa password (ExitCode=$LASTEXITCODE)" }
}

function Resolve-SaCredentials {
    param([string]$SqlCmdPath)
    if (Test-SqlLogin -SqlCmdPath $SqlCmdPath -User $SaUser -Password $SaPassword) {
        Write-Log 'SQL sa login OK (standard password).'
        return
    }
    foreach ($legacy in $SaPasswordLegacy) {
        if (-not (Test-SqlLogin -SqlCmdPath $SqlCmdPath -User $SaUser -Password $legacy)) { continue }
        Write-Log 'Upgrading sa password from legacy...'
        Set-SaStandardPassword -SqlCmdPath $SqlCmdPath -AuthMode 'Sql' -AuthUser $SaUser -AuthPassword $legacy
        return
    }
    if (Test-SqlLogin -SqlCmdPath $SqlCmdPath -User 'scale') {
        Set-SaStandardPassword -SqlCmdPath $SqlCmdPath -AuthMode 'Sql' -AuthUser 'scale'
        return
    }
    if (Test-SqlLogin -SqlCmdPath $SqlCmdPath -User ':E') {
        Set-SaStandardPassword -SqlCmdPath $SqlCmdPath -AuthMode 'Windows'
        return
    }
    throw 'Cannot connect to SQL Server (sa, scale, Windows auth all failed).'
}

function Invoke-SqlFile {
    param([string]$SqlCmdPath, [string]$FilePath)
    Write-Log "Running SQL file: $FilePath"
    $output = & $SqlCmdPath -S $ServerName -U $SaUser -P $SaPassword -b -f 65001 -i $FilePath 2>&1
    if ($output) { $output | ForEach-Object { Write-Log $_.ToString() } }
    if ($LASTEXITCODE -ne 0) { throw "SQL script failed: $FilePath (ExitCode=$LASTEXITCODE)" }
}

function Restart-SqlService {
    $serviceName = "MSSQL`$$SqlInstanceName"
    $svc = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
    if (-not $svc) { return }
    Restart-Service -Name $serviceName -Force
    if (-not (Wait-ForSqlService)) { throw 'SQL service failed to restart.' }
}

function Ensure-Database {
    param([string]$SqlCmdPath, [string]$CreateSqlPath)
    $exists = & $SqlCmdPath -S $ServerName -U $SaUser -P $SaPassword -Q "SET NOCOUNT ON; SELECT DB_ID(N'$DatabaseName')" -h -1 -W
    if ($exists -and $exists.Trim() -ne '' -and $exists.Trim() -ne 'NULL') {
        Write-Log "Database $DatabaseName already exists."
        return
    }
    Invoke-SqlFile -SqlCmdPath $SqlCmdPath -FilePath $CreateSqlPath
}

function Copy-ReportsToPfRecycle {
    $srcDir = Join-Path $AppDir 'Report'
    $dstDir = 'C:\PFRECYCLE\Report'
    if (-not (Test-Path $srcDir)) { return }
    if (-not (Test-Path $dstDir)) { New-Item -ItemType Directory -Path $dstDir -Force | Out-Null }
    Get-ChildItem -Path $srcDir -File | ForEach-Object {
        $dst = Join-Path $dstDir $_.Name
        if (-not (Test-Path $dst)) { Copy-Item -LiteralPath $_.FullName -Destination $dst -Force }
    }
}

try {
    New-Item -ItemType Directory -Force -Path (Join-Path $AppDir 'install') | Out-Null
    Write-Log "PostInstall started. AppDir=$AppDir InstallDir=$InstallDir"

    $appSql = Join-Path $AppDir 'sql'
    if (Test-Path $SqlSourceDir) {
        New-Item -ItemType Directory -Path $appSql -Force | Out-Null
        Copy-Item (Join-Path $SqlSourceDir '*') $appSql -Force
        Write-Log "Copied sql from $SqlSourceDir"
    }

    $dotnetScript = Join-Path $InstallDir 'Install-DotNet48.ps1'
    $sqlScript = Join-Path $InstallDir 'Install-SqlExpress.ps1'
    if (-not (Test-Path $dotnetScript)) { throw "Missing $dotnetScript" }
    if (-not (Test-Path $sqlScript)) { throw "Missing $sqlScript" }

    Invoke-LoggedScript -ScriptPath $dotnetScript -WorkDir $env:TEMP
    Invoke-LoggedScript -ScriptPath $sqlScript -WorkDir $env:TEMP

    if (-not (Wait-ForSqlService)) { throw 'SQL Express service is not running.' }

    $sqlCmd = Find-SqlCmd
    if (-not $sqlCmd) { throw 'sqlcmd.exe not found after SQL install.' }

    Resolve-SaCredentials -SqlCmdPath $sqlCmd

    $configScript = Join-Path $InstallDir 'Configure-SqlLogin.ps1'
    $authSql = Join-Path $appSql 'ConfigureAuthenticationAndScaleLogin.sql'
    & $configScript -InstanceName $SqlInstanceName -SaPassword $SaPassword -SqlScriptPath $authSql
    if ($LASTEXITCODE -ne 0) { throw "Configure-SqlLogin failed (ExitCode=$LASTEXITCODE)" }

    Restart-SqlService
    Resolve-SaCredentials -SqlCmdPath $sqlCmd

    $createSql = Join-Path $appSql 'CreateDatabase_PFRecycle.sql'
    Ensure-Database -SqlCmdPath $sqlCmd -CreateSqlPath $createSql

    Copy-ReportsToPfRecycle
    Write-Log 'PostInstall completed successfully.'
    exit 0
}
catch {
    Write-Log "ERROR: $($_.Exception.Message)"
    exit 1
}
