# Shared config — project DB always lives in data/postgres on port 54320
$script:LocalDbPort = 54320
$script:LocalDbUser = 'eee_admin'
$script:LocalDbPassword = 'eee_password'
$script:LocalDbName = 'eee_dashboard'

function Get-ProjectRoot {
  param([string]$FromScript = $PSScriptRoot)
  return (Resolve-Path (Join-Path $FromScript '..')).Path
}

function Get-PgDataDir {
  param([string]$Root)
  return Join-Path $Root 'data\postgres'
}

function Get-PgCtlLogPath {
  param([string]$Root)
  return Join-Path $Root 'data\pg_ctl.log'
}

function Find-PgBin {
  $cmd = Get-Command initdb -ErrorAction SilentlyContinue
  if ($cmd) { return (Split-Path $cmd.Path -Parent) }

  $candidates = @(
    'C:\Program Files\PostgreSQL\16\bin',
    'C:\Program Files\PostgreSQL\15\bin',
    'C:\Program Files\PostgreSQL\14\bin'
  )
  foreach ($dir in $candidates) {
    if (Test-Path (Join-Path $dir 'initdb.exe')) { return $dir }
  }
  return $null
}

function Test-DbPortOpen {
  param([int]$Port = $script:LocalDbPort)
  $client = $null
  try {
    $client = New-Object System.Net.Sockets.TcpClient
    $connect = $client.BeginConnect('127.0.0.1', $Port, $null, $null)
    if (-not $connect.AsyncWaitHandle.WaitOne(500, $false)) { return $false }
    $client.EndConnect($connect)
    return $client.Connected
  } catch {
    return $false
  } finally {
    if ($client) { $client.Dispose() }
  }
}

function Clear-StalePostmasterLock {
  param([string]$PgData)
  $pidFile = Join-Path $PgData 'postmaster.pid'
  if (-not (Test-Path $pidFile)) { return }

  $firstLine = Get-Content $pidFile -TotalCount 1 -ErrorAction SilentlyContinue
  $oldPid = 0
  [void][int]::TryParse($firstLine, [ref]$oldPid)

  $alive = $false
  if ($oldPid -gt 0) {
    $proc = Get-Process -Id $oldPid -ErrorAction SilentlyContinue
    if ($proc -and $proc.ProcessName -match 'postgres') { $alive = $true }
  }

  if (-not $alive) {
    Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
    Write-Host '  Cleared stale postmaster.pid (folder moved or crash)'
  }
}

function Get-DatabaseUrl {
  return "postgresql://$($script:LocalDbUser):$($script:LocalDbPassword)@localhost:$($script:LocalDbPort)/$($script:LocalDbName)"
}

function Set-EnvLine {
  param(
    [string]$Content,
    [string]$Key,
    [string]$Value
  )
  $pattern = "(?m)^$Key="
  $line = "$Key=`"$Value`""
  if ($Content -match $pattern) {
    return ($Content -replace "(?m)^$Key=.*$", $line)
  }
  return "$line`r`n$Content"
}

function Ensure-BackendEnv {
  param([string]$Root)

  $envPath = Join-Path $Root 'backend\.env'
  $examplePath = Join-Path $Root 'backend\.env.example'
  if (-not (Test-Path $envPath)) {
    Copy-Item $examplePath $envPath
  }

  $url = Get-DatabaseUrl
  $content = Get-Content $envPath -Raw -Encoding UTF8
  $content = Set-EnvLine $content 'DATABASE_URL' $url
  $content = Set-EnvLine $content 'HR_DATA_PATH' '../data/seed/hr-data.json'
  $content = Set-EnvLine $content 'UPLOAD_DIR' '../uploads'
  Set-Content -Path $envPath -Value $content.TrimEnd() -Encoding UTF8 -NoNewline
  Add-Content -Path $envPath -Value '' -Encoding UTF8
}

function Set-PostgresPort {
  param(
    [string]$PgData,
    [int]$Port = $script:LocalDbPort
  )
  $auto = Join-Path $PgData 'postgresql.auto.conf'
  $wanted = @{
    'port' = "port = $Port"
    'logging_collector' = 'logging_collector = off'
  }
  $existing = @()
  if (Test-Path $auto) {
    $existing = @(Get-Content $auto -Encoding UTF8 -ErrorAction SilentlyContinue)
  }
  foreach ($key in $wanted.Keys) {
    $line = $wanted[$key]
    $found = $false
    $existing = @($existing | ForEach-Object {
      if ($_ -match "^\s*$key\s*=") { $found = $true; $line } else { $_ }
    })
    if (-not $found) { $existing += $line }
  }
  $utf8 = New-Object System.Text.UTF8Encoding $false
  [System.IO.File]::WriteAllLines($auto, $existing, $utf8)
}

function Test-DockerReady {
  if (-not (Get-Command docker -ErrorAction SilentlyContinue)) { return $false }
  docker info 2>$null | Out-Null
  return ($LASTEXITCODE -eq 0)
}

function Invoke-Psql {
  param(
    [string]$PgBin,
    [int]$Port = $script:LocalDbPort,
    [string]$User = $script:LocalDbUser,
    [string]$Database = 'postgres',
    [string]$Sql
  )
  $psql = Join-Path $PgBin 'psql.exe'
  & $psql -h 127.0.0.1 -p $Port -U $User -d $Database -v ON_ERROR_STOP=1 -c $Sql 2>&1 | Out-Null
  if ($LASTEXITCODE -ne 0) { throw "psql failed ($Sql)" }
}
