const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const test = require("node:test");

const root = path.resolve(__dirname, "..", "..");
const harness = fs.readFileSync(path.join(
  root, "scripts", "Test-LegacyPackageAppearanceSmoke.mjs"), "utf8");
const wrapper = fs.readFileSync(path.join(
  root, "scripts", "Invoke-LegacyPackageAppearanceSmoke.ps1"), "utf8");

test("appearance smoke uses two exact launches and six physical select changes", () => {
  assert.match(wrapper, /-BuildFlavor DebugAppX/u);
  assert.match(wrapper, /-DefinitionsOnly/u);
  assert.match(wrapper, /Start-ExactAppearanceApplication \$registration 1/u);
  assert.match(wrapper, /Start-ExactAppearanceApplication \$registration 2/u);
  assert.equal((wrapper.match(/Close-ExactAppearanceApplication \$/gu) || []).length, 2);
  assert.match(wrapper, /physicalSelectCount = 6/u);
  assert.match(harness, /nextExchangeSequence !== 5/u);
  assert.match(harness, /evidence\.exchanges\.length !== 4/u);
  assert.match(harness, /for \(const appearanceKey of \["colorTheme", "viewMode", "startWorkspace"\]\)/u);
  assert.match(harness, /trustedChange: true/u);
  assert.match(harness, /physicalKeyCounts:/u);
  assert.match(harness, /home: ack\.homeKeyCalls/u);
  assert.match(harness, /arrowDown: ack\.arrowDownKeyCalls/u);
  assert.match(harness, /enter: ack\.enterKeyCalls/u);
  assert.match(harness, /A native HTML <select> popup consumes Home\/ArrowDown\/Enter/u);
  assert.doesNotMatch(harness, /trustedKeyDowns\.length >= expectedKeyCalls/u);
  assert.doesNotMatch(wrapper, /trustedKeyDownCount -lt/u);
  assert.match(wrapper, /selection\.physicalKeyCounts\.home -ne 1/u);
  assert.match(wrapper, /selection\.physicalKeyCounts\.arrowDown -ne \$expectedDownCount/u);
  assert.match(wrapper, /selection\.physicalKeyCounts\.enter -ne 1/u);
  assert.match(wrapper, /exchange\.physicalInput\.change\.isTrusted -ne \$true/u);
  assert.match(wrapper, /exchange\.physicalInput\.change\.value -cne/u);
  assert.match(wrapper, /exchange\.physicalKeyCounts\.arrowDown -ne/u);
  assert.match(harness, /event\.isTrusted === true/u);
  assert.match(wrapper, /SendApplicationClick\(/u);
  assert.match(wrapper, /SendClosedSelectKeys\(/u);
  assert.match(wrapper, /\[FieldOffset\(0\)\] public MouseInput Mouse/u);
  assert.match(wrapper, /\[FieldOffset\(0\)\] public KeyboardInput Keyboard/u);
  assert.match(wrapper, /\[FieldOffset\(0\)\] public HardwareInput Hardware/u);
  assert.match(wrapper, /IntPtr\.Size == 8 \? 40 : 28/u);
  assert.match(wrapper, /inputSize != ExpectedInputStructureBytes\(\)/u);
  assert.match(wrapper, /Assert-NoTornadoConnection/u);
  assert.match(wrapper, /inputRetryCount = 0/u);
});

test("appearance actions cannot use synthetic CDP input or bridge mutation", () => {
  for (const method of [
    "Input.dispatchMouseEvent",
    "Input.dispatchKeyEvent",
    "Input.insertText"
  ]) {
    assert.ok(harness.includes(`"${method}"`));
    assert.ok(!harness.includes(`rpc("${method}"`));
  }
  assert.doesNotMatch(harness,
    /postMessage\s*\(\s*\{\s*type:\s*["']set-operator-appearance/iu);
  assert.doesNotMatch(harness,
    /(?:\.value\s*=(?!=)|dispatchEvent\s*\(|\.click\s*\(|localStorage\.setItem)/u);
  assert.match(harness,
    /window\.chrome\.webview\.postMessage\(\{ type: "ready", payload: \{\} \}\)/u);
  assert.match(harness, /outbound\.length !== 1/u);
  assert.match(harness, /outbound\[0\]\.type !== "set-operator-appearance"/u);
});

test("relaunch verifies persisted appearance and the saved start-workspace behavior", () => {
  assert.match(harness, /configuration\.phase === "verify-restore"/u);
  assert.match(harness, /persisted-appearance-after-relaunch/u);
  assert.match(harness, /persisted start workspace behavior/u);
  assert.match(harness,
    /configuration\.expected\.startWorkspace === "lastWorkspace"\s*\? "settings"\s*:\s*"stock"/u);
  assert.match(harness, /snapshot\.dom\.activeWorkspace === expectedStartupWorkspace/u);
  assert.match(harness, /startWorkspaceBehaviorVerifiedBeforeInput = true/u);
  assert.match(wrapper, /startWorkspaceBehaviorVerifiedBeforeInput -ne \$true/u);
  assert.match(wrapper, /persistenceVerifiedBeforeInput/u);
  assert.match(wrapper, /logicalAppearanceRestored = \$true/u);
});

test("original operator settings are recoverable and restored byte-for-byte", () => {
  assert.match(wrapper, /Initialize-ExactBaselineRecovery/u);
  assert.match(wrapper, /operatorSettingsOriginallyAbsent/u);
  assert.match(wrapper, /Restore-ExactBaselineSettings/u);
  assert.match(wrapper, /BaselineRestoreAttempted/u);
  assert.match(wrapper, /restoration is one-shot and was already attempted/u);
  assert.match(wrapper, /Get-LegacyApplicationProcesses\)\.Count -ne 0/u);
  assert.match(wrapper, /\[IO\.File\]::Replace\(/u);
  assert.match(wrapper, /\$replacementBackupPath/u);
  assert.match(wrapper, /\[IO\.File\]::Delete\(\$replacementBackupPath\)/u);
  assert.doesNotMatch(wrapper,
    /\[IO\.File\]::Replace\(\$temporaryPath,\s*\$OperatorSettingsPath,\s*\$null/u);
  assert.match(wrapper, /\[IO\.File\]::Delete\(\$OperatorSettingsPath\)/u);
  assert.match(wrapper, /exactOriginalBytesRestored = \$true/u);
  assert.match(wrapper, /recoveryCopyRemoved/u);
  assert.match(wrapper, /The application was intentionally left open/u);
  assert.match(wrapper, /no input retry, close retry,/u);
  assert.match(wrapper, /one-shot settings restoration had an unclear or failed result/u);
  assert.match(wrapper, /retried\. Preserve the recovery evidence/u);
  assert.doesNotMatch(wrapper, /(?:Stop-Process|taskkill)/iu);
  assert.doesNotMatch(wrapper, /C:\\Users\\[^\\]+/iu);
});

test("default appearance evidence directory has one extension separator", () => {
  assert.match(wrapper, /\[IO\.Path\]::GetFileNameWithoutExtension\(\$Output\)/u);
  assert.doesNotMatch(wrapper,
    /\[IO\.Path\]::ChangeExtension\(\$Output,\s*\$null\)\s*\+\s*'\.exchanges'/u);
});

test("appearance evidence is bounded, sealed, and never overwritten", () => {
  assert.match(harness, /fs\.writeFileSync\(requestPath, requestBytes, \{ flag: "wx" \}\)/u);
  assert.match(harness, /fs\.writeFileSync\(configuration\.screenshotPath, bytes, \{ flag: "wx" \}\)/u);
  assert.match(harness, /fs\.writeFileSync\(configuration\.outputPath, bytes, \{ flag: "wx" \}\)/u);
  assert.match(wrapper, /\$item\.Length -gt 512KB/u);
  assert.match(wrapper, /phaseEvidenceSha256/u);
  assert.match(wrapper, /screenshotSha256/u);
  assert.match(wrapper, /\[IO\.FileMode\]::CreateNew/u);
  assert.match(wrapper, /\$stream\.Flush\(\$true\)/u);
});
