import { psadtCatalog } from './psadtCatalog.js';

const powershellCoreUrl = 'https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/?view=powershell-5.1';

function article(id, category, title, summary, sections, tags = []) {
  return { id, category, title, summary, sections, tags };
}

function section(heading, body = [], code = '') {
  return { heading, body, code };
}

function apiExample(method, route, description, body = '') {
  const code = [
    '$base = "http://localhost:3000"',
    '$token = (Invoke-RestMethod -Method Post -Uri "$base/api/auth/login" -ContentType "application/json" -Body (@{ email = "admin@posh.local"; password = "change-me-now" } | ConvertTo-Json)).token',
    '$headers = @{ Authorization = "Bearer $token" }',
    body
      ? `Invoke-RestMethod -Method ${method} -Uri "$base${route}" -Headers $headers -ContentType "application/json" -Body (${body} | ConvertTo-Json -Depth 10)`
      : `Invoke-RestMethod -Method ${method} -Uri "$base${route}" -Headers $headers`
  ].join('\n');
  return section(`${method} ${route}`, [description], code);
}

const operationsArticles = [
  article('ops-overview', 'Operations', 'Application Operations Overview', 'How operators move through POSHManager day to day.', [
    section('Daily workflow', [
      'Build scripts in the Scripts workspace, assign credentials to hosts in Host Library and Credential Vault, create RunPlans, execute jobs, then review job and system logs.',
      'The UI is intentionally API-first. Every create, update, delete, execute, migration, and publishing action calls the Express API so automation can use the same workflows.'
    ]),
    section('Navigation map', [
      'Dashboard shows metrics, charts, recent jobs, and configurable widgets.',
      'Scripts contains the VS Code-style Monaco PowerShell editor, script library, variable studio, and metadata panel.',
      'PSADT contains the deployment factory, verifier, migration wizard, and Intune Publishing Wizard.',
      'Hosts, Credential Vault, RunPlans, Logs, Users & Groups, and Config are separate operational surfaces.'
    ])
  ], ['dashboard', 'operations', 'navigation']),
  article('ops-scripts', 'Operations', 'Scripts And Variables', 'Create folders, author scripts, use variables, and keep versions.', [
    section('Script storage', [
      'Use the Script Library rail to create folders and scripts. Right-click folders or scripts for contextual create/delete actions.',
      'Scripts are versioned by the API. Saving an existing script creates a new script_versions row.'
    ]),
    section('Variables', [
      'Open Variable Studio from the script toolbar. POSHManager runtime variables can be inserted as PowerShell variables or token syntax.',
      'Custom variables are encrypted at rest and can be personal, shared, or group-scoped.',
      'PSADT reference variables are cataloged for authoring, but POSHManager does not fake PSADT runtime values. Those are available only inside a valid PSADT session.',
      'The editor autocomplete suggests PowerShell cmdlets, PSADT functions, PSADT snippets, POSHManager variables, custom variables, and Asset Library reference tokens.'
    ])
  ], ['scripts', 'variables', 'monaco']),
  article('ops-assets', 'Operations', 'Asset Library', 'Upload, organize, link, preview, and reference package assets.', [
    section('What belongs here', [
      'Use Assets for installers, archives, icons, detection scripts, configs, PSADT Files content, SupportFiles content, and reusable files referenced by normal PowerShell scripts.',
      'The library has its own folder tree, separate from script folders, so deployment package content can be organized by app, vendor, platform, or lifecycle stage.',
      'Uploaded files are handled by multer and stored under the API FileLocker tree by asset type: packages, images, scripts, configs, documents, or generic.'
    ]),
    section('Using assets in scripts and packages', [
      'Each asset has a reference token such as {{asset:ast_123}}. Insert the token from the asset details panel into a script when you need the API container file path during RunPlan execution.',
      'Each asset also has a package path such as Files/setup.exe or SupportFiles/config.json. PSADT and Intune package-building workflows use that path to stage content into the correct deployment structure.',
      'Assets can be linked to scripts, RunPlans, PSADT profiles, or Intune deployment plans with a role such as installer, support-file, icon, detection-script, or reference.'
    ])
  ], ['assets', 'packages', 'psadt', 'intune', 'uploads']),
  article('ops-hosts-runplans', 'Operations', 'Hosts, Credential Vault, RunPlans, And Jobs', 'Manage target systems and execute scripts safely.', [
    section('Hosts and credentials', [
      'Create credentials in Credential Vault first, then attach them to hosts. Secrets are encrypted using AES-256-GCM.',
      'Hosts support WinRM, SSH, local, and API transport metadata. PowerShell remoting and firewall prerequisites must be configured outside POSHManager.'
    ]),
    section('RunPlans', [
      'A RunPlan joins one script with one or more hosts. The backend creates a job and host-level log rows during execution.',
      'RunPlans can be personal, shared, or group-scoped. Use the execute action to queue the plan.'
    ]),
    section('Logs', [
      'Job logs are aggregated by job and host. System Logs show Winston request/application logs for API request and response troubleshooting.'
    ])
  ], ['hosts', 'credentials', 'runplans', 'jobs', 'logs']),
  article('ops-admin-config', 'Operations', 'Administration And Configuration', 'Manage users, groups, settings, themes, and deployment variables.', [
    section('Users and groups', [
      'Users & Groups is a dedicated administration menu item. Add users and groups through modal create flows.',
      'Scripts, RunPlans, variables, PSADT profiles, and Intune deployment plans can use personal, shared, or group visibility.'
    ]),
    section('Configuration', [
      'Config is grouped into collapsible sections for Deployment, Authentication, Execution, Runtime, and Other settings, with Microsoft Graph Intune environments managed in the Config / Intune panel.',
      'Settings can be controlled through the UI and environment variables for Docker deployment. Trusted origins, server FQDN, Entra fields, PowerShell binary, and script execution switch are key operational settings.'
    ])
  ], ['admin', 'groups', 'settings', 'docker'])
];

const apiArticles = [
  article('api-auth-bootstrap', 'API', 'Authentication And Bootstrap API', 'Login, profile, health, and bootstrap examples with PowerShell.', [
    apiExample('Post', '/api/auth/login', 'Authenticate with local credentials and receive a JWT token.', '@{ email = "admin@posh.local"; password = "change-me-now" }'),
    apiExample('Get', '/api/auth/me', 'Return the current authenticated user.'),
    apiExample('Put', '/api/auth/profile', 'Update display name, profile fields, and avatar URL.', '@{ displayName = "POSH Admin"; email = "admin@posh.local"; jobTitle = "Platform Administrator"; phone = ""; timezone = "America/Chicago"; avatarUrl = "" }'),
    apiExample('Get', '/api/bootstrap', 'Return dashboard summary, settings payload, and Entra status.'),
    section('Notes', [
      'Use the Bearer token returned by /api/auth/login for every protected request.',
      'The default development login is seeded only when the users table is empty. Change defaults for real deployments.'
    ])
  ], ['api', 'auth', 'bootstrap', 'powershell']),
  article('api-library', 'API', 'Script Library API', 'Folder and script API usage with PowerShell examples.', [
    apiExample('Get', '/api/folders', 'List visible folders.'),
    apiExample('Post', '/api/folders', 'Create a script folder.', '@{ name = "Deployments"; parentId = $null; visibility = "shared" }'),
    apiExample('Get', '/api/scripts', 'List visible scripts.'),
    apiExample('Post', '/api/scripts', 'Create a script and initial version.', '@{ name = "Health Check.ps1"; folderId = $null; description = "Simple host health check"; content = "Get-Date"; visibility = "personal" }'),
    apiExample('Put', '/api/scripts/scr_123', 'Update a script. Replace scr_123 with the script id.', '@{ name = "Health Check.ps1"; folderId = $null; description = "Updated"; content = "Get-ComputerInfo"; visibility = "personal" }')
  ], ['api', 'scripts', 'folders']),
  article('api-assets', 'API', 'Asset Library API', 'Upload and manage package assets with PowerShell examples.', [
    apiExample('Get', '/api/assets/folders', 'List visible asset folders.'),
    apiExample('Post', '/api/assets/folders', 'Create an asset folder.', '@{ name = "Contoso VPN"; parentId = $null; description = "VPN package assets"; visibility = "shared" }'),
    apiExample('Get', '/api/assets', 'List visible assets with referenceToken, packagePath, checksum, viewUrl, and downloadUrl metadata.'),
    section('POST /api/assets', [
      'Upload an asset with multipart form-data. The file field must be named file; metadata fields such as folderId, name, description, packagePath, visibility, and groupId travel alongside it.',
      'The API uses multer to stage uploads into FileLocker/_incoming, then promotes them into FileLocker/assets/<bucket>/<assetId>/<filename>.'
    ], '$file = "/packages/install-notes.txt"\n$form = @{ file = Get-Item $file; folderId = ""; name = "install-notes.txt"; description = "Package note"; packagePath = "SupportFiles/install-notes.txt"; visibility = "shared" }\nInvoke-RestMethod -Method Post -Uri "$base/api/assets" -Headers $headers -Form $form'),
    apiExample('Get', '/api/assets/ast_123/download', 'Download an asset. Replace ast_123 with the asset id.'),
    apiExample('Post', '/api/assets/ast_123/links', 'Link an asset to a script, RunPlan, PSADT profile, or Intune deployment.', '@{ targetType = "script"; targetId = "scr_123"; linkRole = "reference"; packagePath = "SupportFiles/install-notes.txt" }')
  ], ['api', 'assets', 'uploads', 'packages']),
  article('api-hosts-credentials-runplans', 'API', 'Hosts, Credentials, RunPlans, Jobs, And Logs API', 'Manage execution targets and inspect results through the API.', [
    apiExample('Post', '/api/credentials', 'Create an encrypted username/password credential.', '@{ name = "WinRM Admin"; kind = "username_password"; username = "CONTOSO\\svc-posh"; secret = "change-me"; visibility = "personal" }'),
    apiExample('Post', '/api/hosts', 'Create a managed host.', '@{ name = "APP01"; address = "app01.contoso.local"; fqdn = "app01.contoso.local"; osFamily = "windows"; transport = "winrm"; port = 5986; credentialId = $null; tags = @("prod","web"); notes = "" }'),
    apiExample('Post', '/api/runplans', 'Create a RunPlan. hostIds should contain existing host ids.', '@{ name = "Patch Validation"; description = "Run validation script"; scriptId = "scr_123"; visibility = "shared"; parallel = $true; hostIds = @("hst_123") }'),
    apiExample('Post', '/api/runplans/rp_123/execute', 'Execute a RunPlan and create a job. Replace rp_123 with the RunPlan id.'),
    apiExample('Get', '/api/jobs', 'List job history.'),
    apiExample('Get', '/api/jobs/job_123', 'Read one job with host rows and logs.'),
    apiExample('Get', '/api/logs/system', 'Read system/request logs from the Winston log stream.')
  ], ['api', 'credentials', 'hosts', 'runplans', 'jobs']),
  article('api-psadt', 'API', 'PSADT And Intune API', 'Use the PSADT catalog, verifier, migration wizard, profiles, and Intune publishing plans through API calls.', [
    apiExample('Get', '/api/psadt/catalog', 'Return PSADT source links, module/function/ADMX catalogs, snippets, and Intune publishing guidance.'),
    apiExample('Post', '/api/psadt/validate', 'Validate raw PSADT script content.', '@{ platform = "intune"; content = "Invoke-AppDeployToolkit.exe -DeploymentType Install" }'),
    apiExample('Post', '/api/psadt/migration/plan', 'Plan a legacy script migration to PSADT 4.2.0.', `@{ targetVersion = "4.2.0"; content = "Deploy-Application.ps1\`nExecute-Process -Path setup.exe\`n$appName = 'Legacy App'" }`),
    apiExample('Post', '/api/psadt/profiles', 'Create a reusable PSADT deployment profile.', '@{ name = "Edge Enterprise"; appVendor = "Microsoft"; appName = "Edge"; appVersion = "126.0"; appArch = "x64"; appLang = "EN"; appRevision = "01"; templateVersion = "v4"; deploymentType = "Install"; deployMode = "Auto"; requireAdmin = $true; zeroConfig = $false; suppressReboot = $false; closeProcesses = @(); installTasks = @(@{ type = "exe"; phase = "Install"; filePath = "setup.exe"; arguments = "/S"; secureArguments = $false }); uiPlan = @{ welcome = $true }; configPlan = @{}; admxPlan = @{}; visibility = "shared" }'),
    apiExample('Post', '/api/psadt/intune/deployments', 'Create an Intune Publishing Wizard plan.', '@{ name = "Edge Pilot"; sourceFolder = "C:\\Packages\\Edge\\PSADT"; intunewinFile = "Edge.intunewin"; commandStyle = "v4"; installBehavior = "system"; restartBehavior = "return-code"; uiMode = "native-v4"; requirements = @{ architecture = "x64"; minOs = "Windows 10 22H2"; diskSpaceMb = 512; runAs32Bit = $false }; installCommand = "Invoke-AppDeployToolkit.exe -DeploymentType Install"; uninstallCommand = "Invoke-AppDeployToolkit.exe -DeploymentType Uninstall"; detectionType = "custom-script"; detectionRule = "Write-Output detected"; returnCodes = @(@{ code = 0; type = "success"; meaning = "OK" }, @{ code = 1602; type = "retry"; meaning = "Deferred" }, @{ code = 3010; type = "softReboot"; meaning = "Reboot" }); assignments = @(@{ ring = "Pilot"; intent = "available"; groupName = "IT Pilot"; notes = "Validate" }); status = "ready"; visibility = "shared" }')
  ], ['api', 'psadt', 'intune', 'migration'])
  ,
  article('api-graph-intune', 'API', 'Microsoft Graph Intune Tracking API', 'Configure Graph environments in Config / Intune and sync Intune deployment status for PSADT publishing plans.', [
    apiExample('Post', '/api/graph/connections', 'Create a Microsoft Graph environment. In the UI this belongs under Config / Intune. The client secret is encrypted and never returned.', '@{ name = "Production Intune"; tenantId = "contoso.onmicrosoft.com"; clientId = "00000000-0000-0000-0000-000000000000"; clientSecret = "secret"; cloud = "global"; graphBaseUrl = "https://graph.microsoft.com"; authorityHost = "https://login.microsoftonline.com"; defaultApiVersion = "v1.0"; enabled = $true; visibility = "shared" }'),
    apiExample('Post', '/api/graph/connections/graph_123/test', 'Test token acquisition and Intune app read access. Replace graph_123 with the connection id.'),
    apiExample('Get', '/api/graph/connections/graph_123/mobile-apps?q=Edge', 'List Intune mobile apps visible to the Graph app registration.'),
    apiExample('Post', '/api/psadt/intune/deployments/intune_123/graph/link', 'Link a POSHManager Intune deployment plan to an Intune mobileApp id.', '@{ connectionId = "graph_123"; graphAppId = "intune-mobile-app-id" }'),
    apiExample('Post', '/api/psadt/intune/deployments/intune_123/graph/sync', 'Sync device/user install status and failure details from Microsoft Graph Intune reports.', '@{ connectionId = "graph_123"; graphAppId = "intune-mobile-app-id"; mode = "reports" }'),
    apiExample('Get', '/api/psadt/intune/deployments/intune_123/graph/status', 'Read stored status rows, failure rows, and sync run history for a deployment.')
  ], ['api', 'graph', 'intune', 'failures'])
];

const psadtArticles = [
  article('psadt-integration-overview', 'PSADT', 'PSADT Integration Overview', 'How POSHManager supports PSAppDeployToolkit authoring, verification, migration, and publishing.', [
    section('What is modeled', [
      'POSHManager catalogs PSADT variables, functions, ADMX policy surface, deployment structure, launch commands, snippets, and upstream v4 template shape.',
      'Profiles generate Invoke-AppDeployToolkit scaffolds and Intune-ready commands. The verifier checks known best practices and gotchas. The migration wizard upgrades common legacy patterns.'
    ]),
    section('What is not faked', [
      'POSHManager does not emulate PSADT runtime session variables. They exist when PSADT opens an ADTSession during deployment.',
      'POSHManager does not redistribute PSADT modules/templates. Operators bring the actual PSADT deployment package content.'
    ])
  ], ['psadt', 'integration']),
  article('psadt-authoring', 'PSADT', 'Authoring PSADT Scripts', 'Use profiles, variables, snippets, and generated scaffolds to create package scripts.', [
    section('Recommended authoring path', [
      'Create a PSADT profile with application metadata, deployment type, install tasks, close-process list, and UI plan.',
      'Render or create the script from the profile, then continue editing in the Scripts workspace.',
      'Use Variable Studio for PSADT variables and POSHManager custom variables. Use snippets for common UI, installer, reboot, and logging patterns.'
    ]),
    section('Session guidance', [
      'Current v4 scaffolds use ADTSession metadata, package-local module import, Remove-ADTHashtableNullOrEmptyValues, Open-ADTSession, phase invocation, and Close-ADTSession.',
      'DeployMode should remain Auto unless the package intentionally requires Interactive, NonInteractive, or Silent.'
    ])
  ], ['psadt', 'authoring', 'profiles']),
  article('psadt-verifier-migration', 'PSADT', 'Best Practice Verifier And Migration Wizard', 'Validate and migrate PSADT scripts before publishing.', [
    section('Verifier targets', [
      'Validate a saved script, a rendered PSADT profile, or pasted raw content. Choose platform context such as Intune so platform-specific rules apply.',
      'Findings include severity, rule id, category, line/excerpt, and remediation.'
    ]),
    section('Migration wizard', [
      'The migration wizard plans automatic replacements and manual review steps for saved scripts or raw legacy content.',
      'Automatic replacements include common legacy function names, Deploy-Application naming, and $appName-style variables.',
      'Manual review flags include ServiceUI wrappers, raw msiexec, missing Open-ADTSession, legacy phase shape, and missing DeferRunInterval for Intune deferrals.'
    ])
  ], ['psadt', 'verifier', 'migration']),
  article('psadt-intune-deploy', 'PSADT', 'Deploying PSADT Applications With Intune', 'End-to-end PSADT Win32 app publishing guidance.', [
    section('Core workflow', [
      'Place installers in Files and supporting files in SupportFiles. Keep icons/assets, config, and strings in the correct PSADT folders.',
      'Edit Invoke-AppDeployToolkit.ps1 for variables, pre/main/post install, uninstall, and repair logic.',
      'Wrap the entire PSADT folder with the Microsoft Win32 Content Prep Tool into a .intunewin package.',
      'Create a Windows app (Win32) in Intune, upload the package, configure commands, requirements, detection, return codes, and assignments.'
    ]),
    section('Commands and UI context', [
      'For PSADT v4 packages, prefer Invoke-AppDeployToolkit.exe -DeploymentType Install and Invoke-AppDeployToolkit.exe -DeploymentType Uninstall.',
      'Older v3 examples often use Deploy-Application.exe -DeploymentType "Install" -DeployMode "Interactive". Keep this only for legacy compatibility packages.',
      'Install behavior should normally be System. PSADT v4.1+ supports native user-session UI for Intune SYSTEM installs without ServiceUI. ServiceUI should be legacy-only.'
    ]),
    section('Return codes and detection', [
      'Map 0 as success, 1602 as retry/user defer, 3010 as soft reboot, and keep custom PSADT app codes out of 60000-68999.',
      'Some historical guidance uses 1703 as a soft reboot mapping; POSHManager includes it for compatibility.',
      'Use MSI product code, file/version, registry, or custom PowerShell detection. Custom scripts should be fast, side-effect free, and return success only when the app is installed.'
    ])
  ], ['psadt', 'intune', 'deployment', 'serviceui'])
  ,
  article('psadt-graph-tracking', 'PSADT', 'Tracking Intune Deployments With Microsoft Graph', 'Use Graph environments to view deployment reach, failures, devices, and users.', [
    section('Graph environment setup', [
      'Create a Microsoft Entra app registration with application permissions such as DeviceManagementApps.Read.All for read-only tracking. Use DeviceManagementApps.ReadWrite.All only when you intend to manage Intune app objects or assignments.',
      'Store tenant id, client id, and client secret in Config / Intune Graph environments. Client secrets are encrypted and hidden after save.',
      'Use Test to validate token acquisition and read access to deviceAppManagement.'
    ]),
    section('Deployment tracking workflow', [
      'Create or open an Intune Publishing Wizard plan, then link it to a Graph environment and Intune mobileApp id.',
      'Sync status to read Intune report data into POSHManager. Stored rows include device name, user principal name, install state, error code, detail, and raw Graph/report data.',
      'Use the failures count and status table to quickly identify who and which devices failed, then correlate with Intune Management Extension logs and PSADT logs.'
    ]),
    section('Graph reporting notes', [
      'POSHManager prefers Intune reporting endpoints for install status tracking because older mobileApp deviceStatuses/userStatuses relationships have changed over time.',
      'Microsoft Graph returns request ids and status codes that should be kept for troubleshooting tenant permission, throttling, and report availability issues.',
      'This brings POSHManager closer to full Intune publishing and package lifecycle management. Package content/module redistribution is still a separate future capability unless explicitly implemented.'
    ])
  ], ['psadt', 'graph', 'intune', 'tracking', 'failures'])
];

const cmdletArticles = [
  article('cmdlets-core-reference', 'PowerShell', 'Microsoft.PowerShell.Core Cmdlet Reference', 'Common core cmdlets and links to the Microsoft reference.', [
    section('Reference source', [
      `Microsoft documents the Microsoft.PowerShell.Core snap-in and common cmdlets at ${powershellCoreUrl}. The snap-in is loaded automatically by Windows PowerShell and cannot be imported or removed like a normal module.`
    ]),
    section('Common cmdlets', [
      'Get-Help: display help for commands and concepts.',
      'Get-Command: discover cmdlets, functions, aliases, and applications.',
      'Get-Module and Import-Module: inspect and import modules.',
      'Invoke-Command: run commands locally or against remote sessions.',
      'New-PSSession, Enter-PSSession, Get-PSSession, Remove-PSSession: manage PowerShell remoting sessions.',
      'Start-Job, Get-Job, Receive-Job, Stop-Job, Remove-Job, Wait-Job: manage background jobs.',
      'ForEach-Object and Where-Object: pipeline iteration and filtering.',
      'Set-StrictMode: enforce safer script practices.',
      'Update-Help and Save-Help: maintain local help content.'
    ]),
    section('Discovery examples', [], 'Get-Help Invoke-Command -Detailed\nGet-Command -Module Microsoft.PowerShell.Core\nGet-Command *PSSession*\nUpdate-Help -Force')
  ], ['powershell', 'cmdlets', 'reference']),
  article('cmdlets-remoting', 'PowerShell', 'PowerShell Remoting Cmdlets', 'Useful cmdlets for WinRM/PSSession workflows used around POSHManager.', [
    section('Session workflow', [
      'Enable-PSRemoting configures a computer to receive remote commands. This must be done on targets outside POSHManager.',
      'New-PSSession creates reusable remote sessions. Invoke-Command can run commands through a session or directly against computers.',
      'Get-PSSession shows current sessions. Remove-PSSession closes them.'
    ], '$session = New-PSSession -ComputerName "APP01"\nInvoke-Command -Session $session -ScriptBlock { Get-Service }\nGet-PSSession\nRemove-PSSession $session'),
    section('Interactive troubleshooting', [
      'Enter-PSSession starts an interactive remote shell. Exit-PSSession returns to the local shell.',
      'Use Test-WSMan outside the Core module to verify WinRM reachability before adding a host.'
    ], 'Enter-PSSession -ComputerName "APP01"\nExit-PSSession')
  ], ['powershell', 'remoting', 'winrm']),
  article('cmdlets-jobs-pipeline', 'PowerShell', 'Jobs And Pipeline Cmdlets', 'Common cmdlets for async work and object processing.', [
    section('Jobs', [
      'Start-Job runs a command in the background. Get-Job inspects state, Receive-Job collects output, Stop-Job stops work, Wait-Job blocks until completion, and Remove-Job cleans up.',
      'Use jobs for local async work. POSHManager jobs are application records and not the same thing as PowerShell Start-Job jobs.'
    ], '$job = Start-Job -ScriptBlock { Get-Process }\nWait-Job $job\nReceive-Job $job\nRemove-Job $job'),
    section('Pipeline processing', [
      'Where-Object filters pipeline objects. ForEach-Object performs an action for each item.',
      'Prefer object properties over text parsing whenever possible.'
    ], 'Get-Service | Where-Object Status -eq "Running" | ForEach-Object { $_.Name }')
  ], ['powershell', 'jobs', 'pipeline'])
];

function snippetArticles() {
  const catalog = psadtCatalog();
  const snippetItems = (catalog.snippets || []).map((snippet) => section(snippet.title, [
    `${snippet.category} snippet for ${snippet.functionName}. Use Send to editor from the old snippet flow or copy the snippet from Help.`
  ], snippet.body));
  return [
    article('snippets-psadt', 'Snippets', 'PSADT Snippet Library', 'Common PSADT examples moved into searchable help.', snippetItems, ['snippets', 'psadt', 'examples']),
    article('snippets-api-powershell', 'Snippets', 'PowerShell API Snippets', 'Reusable PowerShell snippets for POSHManager API automation.', [
      section('Login helper', [], '$base = "http://localhost:3000"\n$token = (Invoke-RestMethod -Method Post -Uri "$base/api/auth/login" -ContentType "application/json" -Body (@{ email = "admin@posh.local"; password = "change-me-now" } | ConvertTo-Json)).token\n$headers = @{ Authorization = "Bearer $token" }'),
      section('Create script and RunPlan', [], '$script = Invoke-RestMethod -Method Post -Uri "$base/api/scripts" -Headers $headers -ContentType "application/json" -Body (@{ name = "Inventory.ps1"; content = "Get-ComputerInfo"; visibility = "personal" } | ConvertTo-Json)\n$plan = Invoke-RestMethod -Method Post -Uri "$base/api/runplans" -Headers $headers -ContentType "application/json" -Body (@{ name = "Inventory"; scriptId = $script.id; parallel = $true; hostIds = @() } | ConvertTo-Json -Depth 5)')
    ], ['snippets', 'api', 'powershell'])
  ];
}

export function helpCatalog() {
  return [
    ...operationsArticles,
    ...apiArticles,
    ...psadtArticles,
    ...cmdletArticles,
    ...snippetArticles()
  ];
}

export function helpCategories() {
  return [...new Set(helpCatalog().map((item) => item.category))].sort();
}

export function helpSearch(query = '', category = '') {
  const needle = query.trim().toLowerCase();
  return helpCatalog().filter((item) => {
    const categoryMatch = !category || item.category === category;
    if (!needle) return categoryMatch;
    const haystack = [
      item.title,
      item.summary,
      item.category,
      ...(item.tags || []),
      ...item.sections.flatMap((part) => [part.heading, ...(part.body || []), part.code || ''])
    ].join(' ').toLowerCase();
    return categoryMatch && haystack.includes(needle);
  });
}
