$ErrorActionPreference = "Stop"

$Root = "C:\UniDesk\personal-wechat"
$WechatRoot = Join-Path $Root "wechat-3.9.12.51"
$ExtractRoot = Join-Path $Root "wechat-3.9.12.51-extracted"
$VersionRoot = Join-Path $ExtractRoot "[3.9.12.51]"
$DataRoot = Join-Path $Root "data\profile"
$WcfRoot = Join-Path $Root "wcf\v39.5.2"
$PythonSite = Join-Path $WcfRoot "python-site"
$StateRoot = Join-Path $Root "wcf-state"
$DownloadRoot = Join-Path $Root "downloads"
$PrepareResult = Join-Path $StateRoot "prepare-result.json"
$ProgressLog = Join-Path $StateRoot "prepare-progress.log"
$Python = "C:\ProgramData\miniconda3\python.exe"
$PipIndex = "http://mirrors.aliyun.com/pypi/simple/"
$ReleaseBase = "https://github.com/lich0821/WeChatFerry/releases/download/v39.5.2"
$RegistryPath = "HKCU:\Software\Tencent\WeChat"

New-Item -ItemType Directory -Force $WechatRoot,$ExtractRoot,$VersionRoot,$DataRoot,$WcfRoot,$PythonSite,$StateRoot,$DownloadRoot | Out-Null
$StartedAt = (Get-Date).ToUniversalTime().ToString("o")

function Write-PrepareProgress {
  param([string]$Message)
  Add-Content -Encoding utf8 -Path $ProgressLog -Value "$((Get-Date).ToUniversalTime().ToString("o")) $Message"
}

trap {
  $message = $_.Exception.Message
  Write-PrepareProgress "error $message"
  $failed = [ordered]@{
    ok = $false
    startedAt = $StartedAt
    finishedAt = (Get-Date).ToUniversalTime().ToString("o")
    root = $Root
    stateRoot = $StateRoot
    python = $Python
    error = $message
    valuesPrinted = $false
  }
  $failed | ConvertTo-Json -Depth 8 | Set-Content -Encoding utf8 $PrepareResult
  exit 1
}

function Download-IfMissing {
  param([string]$Url, [string]$Path)
  if (Test-Path -LiteralPath $Path) { return }
  Write-PrepareProgress "download-start $Url"
  $tmp = "$Path.part"
  Invoke-WebRequest -Uri $Url -OutFile $tmp -UseBasicParsing
  Move-Item -Force $tmp $Path
  Write-PrepareProgress "download-done $Path"
}

function Get-SevenZipPath {
  $candidates = @(
    "C:\Program Files\7-Zip\7z.exe",
    "C:\Program Files (x86)\7-Zip\7z.exe",
    "7z.exe"
  )
  foreach ($candidate in $candidates) {
    $cmd = Get-Command $candidate -ErrorAction SilentlyContinue
    if ($cmd) { return $cmd.Source }
    if (Test-Path -LiteralPath $candidate) { return $candidate }
  }
  return $null
}

function Find-DedicatedWeChatExe {
  $candidates = @(
    (Join-Path $VersionRoot "WeChat.exe"),
    (Join-Path $ExtractRoot "WeChat.exe"),
    (Join-Path $WechatRoot "WeChat.exe")
  )
  foreach ($candidate in $candidates) {
    if (!(Test-Path -LiteralPath $candidate)) { continue }
    $dir = Split-Path -Parent $candidate
    if (Test-Path -LiteralPath (Join-Path $dir "WeChatWin.dll")) { return $candidate }
  }
  return $null
}

function Ensure-WeChatExtracted {
  param([string]$Installer)
  $wechatExe = Find-DedicatedWeChatExe
  if ($wechatExe) { return [ordered]@{ mode = "dedicated-existing"; wechatExe = $wechatExe } }

  $sevenZip = Get-SevenZipPath
  if (!$sevenZip) { throw "7-Zip is required to extract the WeChat installer without administrator elevation" }
  $extractLog = Join-Path $StateRoot "7z-extract.log"
  Write-PrepareProgress "wechat-extract-start $Installer"
  & $sevenZip x -y "-o$ExtractRoot" $Installer > $extractLog 2>&1
  if ($LASTEXITCODE -ne 0) { throw "7-Zip extract failed; see $extractLog" }
  $wechatExe = Find-DedicatedWeChatExe
  if (!$wechatExe) { throw "Extracted installer did not produce dedicated WeChat.exe with WeChatWin.dll" }
  Write-PrepareProgress "wechat-extract-done $wechatExe"
  return [ordered]@{ mode = "nsis-extracted-hkcu-registry-shim"; wechatExe = $wechatExe; extractLog = $extractLog }
}

function Ensure-IsolatedProfile {
  $appData = Join-Path $DataRoot "AppData\Roaming"
  $localAppData = Join-Path $DataRoot "AppData\Local"
  $documents = Join-Path $DataRoot "Documents"
  $temp = Join-Path $localAppData "Temp"
  New-Item -ItemType Directory -Force $appData,$localAppData,$documents,$temp | Out-Null
  return [ordered]@{
    dataRoot = $DataRoot
    appData = $appData
    localAppData = $localAppData
    documents = $documents
    temp = $temp
  }
}

function Ensure-WeChatRegistryShim {
  param([string]$WechatExe)
  $installPath = Split-Path -Parent $WechatExe
  New-Item -Path $RegistryPath -Force | Out-Null
  Set-ItemProperty -Path $RegistryPath -Name InstallPath -Value ($installPath + "\")
  Set-ItemProperty -Path $RegistryPath -Name Version -Value 0x03090c33 -Type DWord
  return $installPath + "\"
}

function Install-Wcferry {
  if (!(Test-Path -LiteralPath $Python)) { throw "Expected Python not found: $Python" }
  $pipOut = Join-Path $StateRoot "prepare-pip.stdout.log"
  $pipErr = Join-Path $StateRoot "prepare-pip.stderr.log"
  Write-PrepareProgress "pip-install-start"
  & $Python -m pip install --upgrade --target $PythonSite --trusted-host mirrors.aliyun.com --index-url $PipIndex --timeout 120 --retries 8 "wcferry==39.5.2.0" > $pipOut 2> $pipErr
  if ($LASTEXITCODE -ne 0) { throw "pip install wcferry failed; see $pipErr" }
  Write-PrepareProgress "pip-install-done"

  $probePy = Join-Path $StateRoot "prepare-probe.py"
  @'
import importlib.metadata
import json
import os
import wcferry

payload = {
    "ok": True,
    "wcferryVersion": importlib.metadata.version("wcferry"),
    "packageRoot": os.path.abspath(os.path.dirname(wcferry.__file__)),
}
print(json.dumps(payload, ensure_ascii=False))
'@ | Set-Content -Encoding utf8 $probePy
  $oldPythonPath = $env:PYTHONPATH
  try {
    $env:PYTHONPATH = if ($oldPythonPath) { "$PythonSite;$oldPythonPath" } else { $PythonSite }
    $pyProbe = (& $Python $probePy) | ConvertFrom-Json
  } finally {
    $env:PYTHONPATH = $oldPythonPath
  }
  return [ordered]@{
    ok = [bool]$pyProbe.ok
    version = $pyProbe.wcferryVersion
    packageRoot = $pyProbe.packageRoot
    stdout = $pipOut
    stderr = $pipErr
  }
}

function Sync-WcfDlls {
  param([string]$PackageRoot)
  $dlls = @()
  foreach ($name in @("sdk.dll","spy.dll","spy_debug.dll")) {
    $src = Join-Path $WcfRoot $name
    $dst = Join-Path $PackageRoot $name
    if (!(Test-Path -LiteralPath $src)) { throw "Missing WCF release asset: $src" }
    if (!(Test-Path -LiteralPath $dst)) { throw "Missing wcferry package dll target: $dst" }
    $backup = "$dst.unidesk-bak"
    if (!(Test-Path -LiteralPath $backup)) {
      Copy-Item -LiteralPath $dst -Destination $backup -Force
    }
    Copy-Item -LiteralPath $src -Destination $dst -Force
    $srcItem = Get-Item -LiteralPath $src
    $dstItem = Get-Item -LiteralPath $dst
    $dlls += [ordered]@{
      name = $name
      sourceBytes = $srcItem.Length
      targetBytes = $dstItem.Length
      targetVersion = $dstItem.VersionInfo.FileVersion
      backup = $backup
    }
  }
  return $dlls
}

function Ensure-Firewall {
  try {
    if (-not (Get-NetFirewallRule -DisplayName "UniDesk Personal WeChat WCF 10086" -ErrorAction SilentlyContinue)) {
      New-NetFirewallRule `
        -DisplayName "UniDesk Personal WeChat WCF 10086" `
        -Direction Inbound `
        -Action Allow `
        -Protocol TCP `
        -LocalPort 10086,10087 `
        -RemoteAddress 172.26.0.0/16,10.42.0.0/16,127.0.0.1 `
        -Profile Any `
        -ErrorAction Stop | Out-Null
      return [ordered]@{ ok = $true; applied = $true }
    }
    return [ordered]@{ ok = $true; applied = $false; alreadyPresent = $true }
  } catch {
    Write-PrepareProgress "firewall-skip $($_.Exception.Message)"
    return [ordered]@{ ok = $false; skipped = $true; reason = $_.Exception.Message }
  }
}

Write-PrepareProgress "prepare-start"
$installer = Join-Path $DownloadRoot "WeChatSetup-3.9.12.51.exe"
Download-IfMissing "$ReleaseBase/WeChatSetup-3.9.12.51.exe" $installer
Download-IfMissing "$ReleaseBase/sdk.dll" (Join-Path $WcfRoot "sdk.dll")
Download-IfMissing "$ReleaseBase/spy.dll" (Join-Path $WcfRoot "spy.dll")
Download-IfMissing "$ReleaseBase/spy_debug.dll" (Join-Path $WcfRoot "spy_debug.dll")

Copy-Item -Force "$PSScriptRoot\wcf_host.py" (Join-Path $WcfRoot "wcf_host.py")

$wechat = Ensure-WeChatExtracted $installer
$profile = Ensure-IsolatedProfile
$installPath = Ensure-WeChatRegistryShim $wechat.wechatExe
$wcferry = Install-Wcferry
$dlls = Sync-WcfDlls $wcferry.packageRoot
$firewall = Ensure-Firewall

$summary = [ordered]@{
  ok = [bool]($wechat.wechatExe -and $wcferry.ok)
  startedAt = $StartedAt
  finishedAt = (Get-Date).ToUniversalTime().ToString("o")
  root = $Root
  mode = $wechat.mode
  wechatInstaller = $installer
  wechatRoot = $WechatRoot
  extractRoot = $ExtractRoot
  versionRoot = $VersionRoot
  wechatExe = $wechat.wechatExe
  installPath = $installPath
  registryKey = $RegistryPath
  requiredVersion = "3.9.12.51"
  profile = $profile
  wcfRoot = $WcfRoot
  pythonSite = $PythonSite
  stateRoot = $StateRoot
  python = $Python
  wcferryVersion = $wcferry.version
  wcferryPackageRoot = $wcferry.packageRoot
  dllOverride = $dlls
  firewall = $firewall
  valuesPrinted = $false
  next = "Run start.ps1 and scan the isolated WeChat login QR."
}
Write-PrepareProgress "prepare-done ok=$($summary.ok)"
$summary | ConvertTo-Json -Depth 10 | Set-Content -Encoding utf8 $PrepareResult
$summary | ConvertTo-Json -Depth 10
