<#
.SYNOPSIS
  Provision a PC for GE-Enforce + shopdb: write its identity (so it knows its PC
  type and bay), deploy the shopdb client kit, and register the enforcement
  scheduled task. Site-neutral and imaging-path independent - run it from a PXE
  step, an OOBE provisioning package (ppkg), Intune, or by hand.

  This is the "set up the PC to determine its PC type and such" step. There is no
  auto-detection: the caller supplies the type (and, where relevant, the bay
  machine number and CMM version), and this script writes the files/registry the
  GE-Enforce engine reads.

  This script does NOT contain the GE-Enforce engine (Install-FromManifest.ps1)
  or dispatcher - those are the GE-Enforce framework's. Point at your copy with
  -EngineSource, or ensure it is already present under -InstallRoot\lib.

.PARAMETER PCType
  The imaging PC type = the manifest scope this PC runs. One of the scope names
  (e.g. gea-shopfloor-cmm, gea-shopfloor-collections) or a legacy alias the
  engine maps. Written to C:\Enrollment\pc-type.txt. REQUIRED.

.PARAMETER MachineNumber
  The bay machine number (for TargetMachineNumbers gates). Written to
  machine-number.txt as a fallback; the DNC registry MachineNo wins if present.

.PARAMETER CmmVersion
  CMM bays only: the resolved PC-DMIS version (2016/2019/2026) for _CmmVersion
  gating. Written to C:\Enrollment\cmm\version.txt. Omit for non-CMM PCs.

.PARAMETER CmmId
  CMM bays only: the bay id. Written to C:\Enrollment\cmm\cmmid.txt.

.PARAMETER ShareRoot
  The GE-Enforce share root (UNC), written into site-config.json as
  shopfloorShareRoot.

.PARAMETER Site
  Site name, written into site-config.json.

.PARAMETER ShopdbUrl
  shopdb base URL (scheme + host) for the fetch/report client. Written to
  HKLM:\SOFTWARE\GE\ShopDB\BaseUrl.

.PARAMETER ShopdbToken
  A geenforce.fetch (+ geenforce.report) managed service token. Written to
  HKLM:\SOFTWARE\GE\ShopDB\ApiToken. (In many sites Azure DSC provisions this
  instead - omit here if so.)

.PARAMETER EngineSource
  Optional path (folder or share) containing the GE-Enforce engine to copy in:
  expects GE-Enforce.ps1 and lib\Install-FromManifest.ps1. If omitted, the engine
  is assumed already present under -InstallRoot.

.PARAMETER InstallRoot
  Where the client kit + engine live on the PC. Default C:\ProgramData\GE-Enforce.

.PARAMETER TaskName
  Scheduled task name. Default 'GE-Enforce'.

.PARAMETER IntervalMinutes
  How often the enforcement task repeats. Default 5.

.PARAMETER NoTask
  Provision identity + kit only; do not register the scheduled task.

.EXAMPLE
  .\Install-GEEnforce.ps1 -PCType gea-shopfloor-cmm -MachineNumber 0615 `
     -CmmVersion 2019 -ShareRoot \\server\share\dt\shopfloor -Site "Main Plant" `
     -ShopdbUrl https://shopdb.example.net -ShopdbToken shopdb_pat_xxx `
     -EngineSource \\server\share\dt\shopfloor\common
#>
[CmdletBinding()]
param(
    [Parameter(Mandatory)] [string]$PCType,
    [string]$MachineNumber,
    [string]$CmmVersion,
    [string]$CmmId,
    [string]$ShareRoot,
    [string]$Site,
    [string]$ShopdbUrl,
    [string]$ShopdbToken,
    [string]$EngineSource,
    [string]$InstallRoot = 'C:\ProgramData\GE-Enforce',
    [string]$EnrollmentRoot = 'C:\Enrollment',
    [string]$TaskName = 'GE-Enforce',
    [int]$IntervalMinutes = 5,
    [switch]$NoTask
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

function Write-TextFile {
    param([string]$Path, [string]$Value)
    $dir = Split-Path -Parent $Path
    if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
    Set-Content -LiteralPath $Path -Value $Value -Encoding ascii -NoNewline
    Write-Host "  wrote $Path"
}

try {
    Write-Host "GE-Enforce provisioning: PCType=$PCType"

    # --- 1. Identity: what the PC is (what the engine reads) -----------------
    Write-TextFile (Join-Path $EnrollmentRoot 'pc-type.txt') $PCType
    if ($MachineNumber) { Write-TextFile (Join-Path $EnrollmentRoot 'machine-number.txt') $MachineNumber }
    if ($CmmVersion) { Write-TextFile (Join-Path $EnrollmentRoot 'cmm\version.txt') $CmmVersion }
    if ($CmmId) { Write-TextFile (Join-Path $EnrollmentRoot 'cmm\cmmid.txt') $CmmId }

    $siteConfig = @{}
    if ($ShareRoot) { $siteConfig['shopfloorShareRoot'] = $ShareRoot }
    if ($Site) { $siteConfig['site'] = $Site }
    if ($siteConfig.Count) {
        $siteConfigPath = Join-Path $EnrollmentRoot 'site-config.json'
        $dir = Split-Path -Parent $siteConfigPath
        if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
        ($siteConfig | ConvertTo-Json) | Set-Content -LiteralPath $siteConfigPath -Encoding ascii
        Write-Host "  wrote $siteConfigPath"
    }

    # --- 2. shopdb client registry config ------------------------------------
    if ($ShopdbUrl -or $ShopdbToken) {
        $regPath = 'HKLM:\SOFTWARE\GE\ShopDB'
        if (-not (Test-Path $regPath)) { New-Item -Path $regPath -Force | Out-Null }
        if ($ShopdbUrl) { Set-ItemProperty -Path $regPath -Name BaseUrl -Value $ShopdbUrl }
        if ($ShopdbToken) { Set-ItemProperty -Path $regPath -Name ApiToken -Value $ShopdbToken }
        Write-Host "  wrote HKLM:\SOFTWARE\GE\ShopDB"
    }

    # --- 3. Deploy the client kit (ships alongside this script) --------------
    if (-not (Test-Path $InstallRoot)) { New-Item -ItemType Directory -Path $InstallRoot -Force | Out-Null }
    foreach ($file in 'ShopdbEnforceClient.psm1', 'Invoke-ShopdbEnforce.ps1') {
        $src = Join-Path $PSScriptRoot $file
        if (Test-Path $src) {
            Copy-Item -Path $src -Destination (Join-Path $InstallRoot $file) -Force
            Write-Host "  deployed $file"
        } else {
            Write-Warning "client kit file not found next to this script: $file"
        }
    }

    # --- 4. Engine (referenced, not vendored) --------------------------------
    if ($EngineSource) {
        Copy-Item -Path (Join-Path $EngineSource 'GE-Enforce.ps1') `
            -Destination (Join-Path $InstallRoot 'GE-Enforce.ps1') -Force -ErrorAction SilentlyContinue
        $libDir = Join-Path $InstallRoot 'lib'
        if (-not (Test-Path $libDir)) { New-Item -ItemType Directory -Path $libDir -Force | Out-Null }
        Copy-Item -Path (Join-Path $EngineSource 'lib\Install-FromManifest.ps1') `
            -Destination (Join-Path $libDir 'Install-FromManifest.ps1') -Force -ErrorAction SilentlyContinue
        Write-Host "  copied engine from $EngineSource"
    }
    $enginePath = Join-Path $InstallRoot 'lib\Install-FromManifest.ps1'
    if (-not (Test-Path $enginePath)) {
        Write-Warning "engine not present at $enginePath - provide -EngineSource or place it there before enforcement runs."
    }

    # --- 5. Scheduled task: run the enforcement client as SYSTEM -------------
    if (-not $NoTask) {
        $runner = Join-Path $InstallRoot 'Invoke-ShopdbEnforce.ps1'
        $arguments = "-NoProfile -ExecutionPolicy Bypass -File `"$runner`" -Scope `"$PCType`" -EnginePath `"$enginePath`""
        $action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument $arguments
        $triggers = @(
            (New-ScheduledTaskTrigger -AtLogOn),
            (New-ScheduledTaskTrigger -Once -At (Get-Date) `
                -RepetitionInterval (New-TimeSpan -Minutes $IntervalMinutes))
        )
        $principal = New-ScheduledTaskPrincipal -UserId 'NT AUTHORITY\SYSTEM' -RunLevel Highest
        $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries `
            -DontStopIfGoingOnBatteries -StartWhenAvailable
        Register-ScheduledTask -TaskName $TaskName -Action $action -Trigger $triggers `
            -Principal $principal -Settings $settings -Force | Out-Null
        Write-Host "  registered task '$TaskName' (at logon + every $IntervalMinutes min)"
    }

    Write-Host "GE-Enforce provisioning complete."
    exit 0
} catch {
    Write-Error "GE-Enforce provisioning FAILED: $($_.Exception.Message)"
    exit 1
}
