param(
  [int]$SmokePort = 4319,
  [string]$SmokeToken = 'smoke-token',
  [string]$BaseOutputDir,
  [string]$AppExePath
)

$ErrorActionPreference = 'Stop'

function Write-Utf8File {
  param([string]$FilePath, [string]$Content)
  $encoding = New-Object System.Text.UTF8Encoding $false
  [System.IO.File]::WriteAllText($FilePath, $Content, $encoding)
}

function Copy-ProjectBundleSource {
  param(
    [string]$SourceRoot,
    [string]$DestinationRoot
  )

  $projectJsonPath = Join-Path $SourceRoot 'project.json'
  $excludePaths = @()
  if (Test-Path $projectJsonPath) {
    $projectConfig = Get-Content -Path $projectJsonPath -Raw | ConvertFrom-Json
    $configuredExcludes = $projectConfig.bundlePackaging.excludePaths
    if ($configuredExcludes) {
      $excludePaths = @($configuredExcludes | ForEach-Object { [string]$_ })
    }
  }
  $excludeSet = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
  foreach ($entry in $excludePaths) {
    if ($entry) {
      [void]$excludeSet.Add($entry)
    }
  }

  New-Item -ItemType Directory -Force -Path $DestinationRoot | Out-Null
  foreach ($entry in Get-ChildItem -LiteralPath $SourceRoot -Force) {
    if ($excludeSet.Contains($entry.Name)) {
      continue
    }
    if ($entry.PSIsContainer -and $entry.Name -match '^tmp[a-z0-9]{6,}$') {
      Write-Warning "Skipping transient temp directory from bundle source: $($entry.FullName)"
      continue
    }
    try {
      Copy-Item -LiteralPath $entry.FullName -Destination (Join-Path $DestinationRoot $entry.Name) -Recurse -Force
    }
    catch [System.UnauthorizedAccessException] {
      Write-Warning "Skipping inaccessible bundle source entry: $($entry.FullName)"
      continue
    }
  }
}

function New-ExpertFixtureProject {
  param(
    [string]$ProjectsRoot,
    [string]$ProjectId,
    [string]$ProjectName,
    [string]$Platform,
    [string]$Description,
    [string]$UpdatedAt
  )

  $projectRoot = Join-Path $ProjectsRoot $ProjectId
  New-Item -ItemType Directory -Force -Path $projectRoot, (Join-Path $projectRoot 'memory') | Out-Null

  $projectPayload = [ordered]@{
    id = $ProjectId
    name = $ProjectName
    description = $Description
    platform = $Platform
    ready = $true
    updatedAt = $UpdatedAt
    boundSkillIds = @()
    workspaceEntryEnabled = $true
  }

  Write-Utf8File (Join-Path $projectRoot 'project.json') ($projectPayload | ConvertTo-Json -Depth 8)
  Write-Utf8File (Join-Path $projectRoot 'README.md') "# $ProjectName`n`nFixture expert project for manual Douyin validation."
  Write-Utf8File (Join-Path $projectRoot 'AGENTS.md') "# $ProjectName`n`nPassive fixture expert used to keep the experts list above two items."
}

$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
if (-not $BaseOutputDir) {
  $BaseOutputDir = Join-Path $repoRoot '.tmp\douyin-expert-manual-launch'
}
if (-not $AppExePath) {
  $AppExePath = Join-Path $repoRoot 'dist\installer\win-unpacked\千匠问天.exe'
}

$BaseOutputDir = [System.IO.Path]::GetFullPath($BaseOutputDir)
$AppExePath = [System.IO.Path]::GetFullPath($AppExePath)
$douyinSourceRoot = Join-Path $repoRoot 'workspace\douyin'
$userDataPath = Join-Path $BaseOutputDir 'user-data'
$logsPath = Join-Path $BaseOutputDir 'logs'
$bundleSourceRoot = Join-Path $BaseOutputDir 'bundle-src'
$bundleZipPath = Join-Path $BaseOutputDir 'douyin-expert-manual-launch.zip'
$bundleFileName = 'douyin-expert-manual-launch.zip'
$bundleSkillId = 'douyin-project-bundle'
$bundleConfigVersion = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ')

if (-not (Test-Path $AppExePath)) {
  throw "Packaged desktop executable was not found: $AppExePath"
}
if (-not (Test-Path $douyinSourceRoot)) {
  throw "Douyin workspace source was not found: $douyinSourceRoot"
}

$runningDesktop = Get-Process -Name '千匠问天' -ErrorAction SilentlyContinue
if ($runningDesktop) {
  $processIds = ($runningDesktop | Select-Object -ExpandProperty Id) -join ', '
  throw "千匠问天 is already running (PID: $processIds). Close the desktop app first, then rerun this launcher."
}

if (Test-Path $BaseOutputDir) {
  Remove-Item -LiteralPath $BaseOutputDir -Recurse -Force -ErrorAction SilentlyContinue
}
if (Test-Path $BaseOutputDir) {
  throw "Failed to reset manual launch directory: $BaseOutputDir"
}

New-Item -ItemType Directory -Force -Path $BaseOutputDir, $userDataPath, $logsPath, $bundleSourceRoot | Out-Null

Copy-ProjectBundleSource -SourceRoot $douyinSourceRoot -DestinationRoot (Join-Path $bundleSourceRoot 'douyin')
if (Test-Path $bundleZipPath) {
  Remove-Item -LiteralPath $bundleZipPath -Force
}
Compress-Archive -Path (Join-Path $bundleSourceRoot 'douyin') -DestinationPath $bundleZipPath -Force

$projectsRoot = Join-Path $userDataPath 'projects'
$manifestsRoot = Join-Path $userDataPath 'manifests'
New-Item -ItemType Directory -Force -Path $projectsRoot, $manifestsRoot | Out-Null

New-ExpertFixtureProject -ProjectsRoot $projectsRoot -ProjectId 'xhs-expert-smoke' -ProjectName 'XHS Expert Fixture' -Platform 'xiaohongshu' -Description 'Fixture project that keeps the experts list above two items.' -UpdatedAt '2026-04-03T00:00:00.000Z'
New-ExpertFixtureProject -ProjectsRoot $projectsRoot -ProjectId 'browser-expert-smoke' -ProjectName 'Browser Expert Fixture' -Platform 'browser' -Description 'Fixture project that keeps the experts list above two items.' -UpdatedAt '2026-04-03T00:01:00.000Z'
Write-Utf8File (Join-Path $manifestsRoot 'active-project.json') (@{ projectId = 'browser-expert-smoke' } | ConvertTo-Json -Depth 3)

$env:QJCLAW_USER_DATA_PATH = $userDataPath
$env:QJCLAW_LOGS_PATH = $logsPath
$env:QJCLAW_RUNTIME_MODE = 'bundled-runtime'
$env:QJCLAW_SMOKE_CLOUD_API_BASE_URL = "http://127.0.0.1:$SmokePort"
$env:QJCLAW_SMOKE_AUTH_TOKEN = $SmokeToken
$env:QJCLAW_SMOKE_RUNTIME_CLOUD_API_KEY = 'smoke-runtime-api-key'
$env:QJCLAW_SMOKE_BUNDLE_ZIP_PATH = $bundleZipPath
$env:QJCLAW_SMOKE_BUNDLE_FILE_NAME = $bundleFileName
$env:QJCLAW_SMOKE_BUNDLE_SKILL_ID = $bundleSkillId
$env:QJCLAW_SMOKE_BUNDLE_SKILL_TITLE = 'Douyin Project Bundle'
$env:QJCLAW_SMOKE_BUNDLE_SKILL_DESCRIPTION = 'Local mock employee-config bundle for manual Douyin expert validation.'
$env:QJCLAW_SMOKE_BUNDLE_CONFIG_VERSION = $bundleConfigVersion

$null = Start-Process -FilePath $AppExePath -PassThru

Write-Host "Launched packaged desktop app with local mock employee-config."
Write-Host "User data path: $userDataPath"
Write-Host "Bundle zip path: $bundleZipPath"
Write-Host "Open the Experts view, select douyin, and send your manual prompt."
