# 插件部署主体（供 deploy-plugin.bat 调用）
# 关闭 Navisworks(Roamer)、等待文件解锁、复制 DLL 与资源、校验并设置可写权限。
$ErrorActionPreference = 'Stop'

$targetDir = [System.IO.Path]::GetFullPath('C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\TransportPlugin')
$buildDir = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot 'bin\x64\Release'))

$deployDllNames = @(
  'TransportPlugin.dll',
  'geometry4Sharp.dll',
  'Newtonsoft.Json.dll',
  'Roy-T.AStar.dll',
  'SQLite.Interop.dll',
  'System.Data.SQLite.dll',
  'Tomlyn.dll'
)
$deployRootFiles = @(
  'TransportRibbon.xaml',
  'TransportRibbon_16.png',
  'TransportRibbon_32.png'
)
$stalePluginFiles = @(
  'Autodesk.Navisworks.Api.dll',
  'NavisworksTransport.UnitTests.dll',
  'Microsoft.VisualStudio.TestPlatform.TestFramework.dll',
  'Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll'
)

function Test-FileUnlocked([string]$path) {
  if (-not (Test-Path $path)) { return $true }
  try {
    $stream = [System.IO.File]::Open($path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
    $stream.Close()
    return $true
  } catch {
    return $false
  }
}
function Wait-FileUnlocked([string]$path, [datetime]$deadline) {
  while (-not (Test-FileUnlocked $path)) {
    if ((Get-Date) -ge $deadline) { throw ('Target file still locked: ' + $path) }
    Start-Sleep -Milliseconds 500
  }
}

# 关闭 Navisworks 进程以解锁 DLL
Get-Process Roamer -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
$deadline = (Get-Date).AddSeconds(15)
while (Get-Process Roamer -ErrorAction SilentlyContinue) {
  if ((Get-Date) -ge $deadline) { throw 'Roamer.exe still running after 15 seconds.' }
  Start-Sleep -Milliseconds 500
}

$keyTargetFiles = @(
  (Join-Path $targetDir 'TransportPlugin.dll'),
  (Join-Path $targetDir 'geometry4Sharp.dll'),
  (Join-Path (Join-Path $targetDir 'resources') 'unit_cube.nwc'),
  (Join-Path (Join-Path $targetDir 'resources') 'unit_cylinder.nwc')
)
foreach ($keyFile in $keyTargetFiles) { Wait-FileUnlocked $keyFile $deadline }

New-Item -ItemType Directory -Force -Path $targetDir | Out-Null
foreach ($staleFileName in $stalePluginFiles) {
  $stalePath = Join-Path $targetDir $staleFileName
  if (Test-Path $stalePath) { Remove-Item $stalePath -Force }
}
foreach ($dllName in $deployDllNames) {
  $sourceDll = Join-Path $buildDir $dllName
  if (-not (Test-Path $sourceDll)) { throw ('Deployment source file missing: ' + $sourceDll) }
  Copy-Item $sourceDll $targetDir -Force
}
foreach ($rootFileName in $deployRootFiles) {
  $sourceRootFile = Join-Path $buildDir $rootFileName
  if (Test-Path $sourceRootFile) {
    Copy-Item $sourceRootFile $targetDir -Force
    foreach ($locale in @('en-US','zh-CN')) {
      $localeDir = Join-Path $targetDir $locale
      New-Item -ItemType Directory -Force -Path $localeDir | Out-Null
      Copy-Item $sourceRootFile $localeDir -Force
    }
  }
}
if (Test-Path (Join-Path $buildDir 'resources')) {
  New-Item -ItemType Directory -Force -Path (Join-Path $targetDir 'resources') | Out-Null
  Copy-Item (Join-Path $buildDir 'resources\*') (Join-Path $targetDir 'resources') -Recurse -Force
}

# 校验复制结果
$sourceFiles = @()
foreach ($dllName in $deployDllNames) { $sourceFiles += Get-Item (Join-Path $buildDir $dllName) }
foreach ($rootFileName in $deployRootFiles) {
  $sourceRootFile = Join-Path $buildDir $rootFileName
  if (Test-Path $sourceRootFile) { $sourceFiles += Get-Item $sourceRootFile }
}
if (Test-Path (Join-Path $buildDir 'resources')) {
  $sourceFiles += Get-ChildItem (Join-Path $buildDir 'resources') -File
}
foreach ($sourceFile in $sourceFiles) {
  $targetFile = if ($sourceFile.DirectoryName -eq $buildDir) { Join-Path $targetDir $sourceFile.Name } else { Join-Path (Join-Path $targetDir 'resources') $sourceFile.Name }
  if (-not (Test-Path $targetFile)) { throw ('Deployment verification failed: missing target file ' + $targetFile) }
  $targetInfo = Get-Item $targetFile
  if ($sourceFile.Length -ne $targetInfo.Length -or $sourceFile.LastWriteTime -ne $targetInfo.LastWriteTime) {
    throw ('Deployment verification failed for ' + $sourceFile.Name + ': source=' + $sourceFile.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss.fff') + ' (' + $sourceFile.Length + '), target=' + $targetInfo.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss.fff') + ' (' + $targetInfo.Length + ')')
  }
  Write-Host ('Verified ' + $sourceFile.Name + ': ' + $targetInfo.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss.fff'))
  if ($deployRootFiles -contains $sourceFile.Name) {
    foreach ($locale in @('en-US','zh-CN')) {
      $localeTargetFile = Join-Path (Join-Path $targetDir $locale) $sourceFile.Name
      if (-not (Test-Path $localeTargetFile)) { throw ('Deployment verification failed: missing locale target file ' + $localeTargetFile) }
      $localeTargetInfo = Get-Item $localeTargetFile
      if ($sourceFile.Length -ne $localeTargetInfo.Length -or $sourceFile.LastWriteTime -ne $localeTargetInfo.LastWriteTime) {
        throw ('Deployment verification failed for locale copy ' + $localeTargetFile)
      }
      Write-Host ('Verified ' + $locale + '\' + $sourceFile.Name + ': ' + $localeTargetInfo.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss.fff'))
    }
  }
}

# 设置目标文件可写权限，避免后续部署需要管理员提权（一次性管理员部署后免 UAC）
foreach ($f in Get-ChildItem $targetDir -File -Recurse -ErrorAction SilentlyContinue) {
  try {
    $acl = Get-Acl $f.FullName
    $rule = New-Object System.Security.AccessControl.FileSystemAccessRule('BUILTIN\Users','FullControl','Allow')
    $acl.SetAccessRule($rule)
    Set-Acl $f.FullName $acl
  } catch { }
}

Write-Host 'Plugin deployed successfully!'
