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-LegacyPackageLocalStateSmoke.mjs"), "utf8");
const wrapper = fs.readFileSync(path.join(
  root, "scripts", "Invoke-LegacyPackageLocalStateSmoke.ps1"), "utf8");
const shared = fs.readFileSync(path.join(
  root, "scripts", "Invoke-LegacyPackageInputSmoke.ps1"), "utf8");

test("local-state package smoke is a closed thirteen-step physical-input plan", () => {
  assert.match(harness, /nextInputSequence !== 14/u);
  assert.match(harness, /evidence\.exchanges\.length !== 13/u);
  assert.match(wrapper, /exchangeCount = \$ExpectedExchangePlan\.Count/u);
  assert.match(wrapper, /physicalClickCount/u);
  assert.match(wrapper, /folderPickerCancelCount/u);
  assert.match(wrapper, /\[string\]\$LegacyDataDirectory/u);
  assert.match(wrapper,
    /'\.\.\\MBN_STOCK_N\\MBN_STOCK_N\\bin\\Debug\\Data'/u);
  assert.doesNotMatch(wrapper, /C:\\Users\\[^\\]+/iu);
  assert.match(wrapper, /fileObservationCount/u);
  assert.match(wrapper, /inputRetryCount = 0/u);
  assert.match(wrapper, /function Read-LocalHarnessEvidenceFile/u);
  assert.match(wrapper, /item\.Length -gt 128KB/u);
  assert.doesNotMatch(wrapper,
    /Read-SmallJsonEvidenceFile \$EvidencePath 'Local-state harness evidence'/u);
});

test("three app-owned folder pickers are clicked once and Escape-cancelled", () => {
  for (const [target, kind] of [
    ["design-folder-picker", "design"],
    ["resource-folder-picker", "resource"],
    ["background-folder-picker", "background"]
  ]) {
    assert.ok(harness.includes(`[\"${target}\", \"${kind}\"]`));
  }
  assert.match(wrapper, /Wait-UniqueOwnedFolderPicker/u);
  assert.match(wrapper, /OwnerChainContains/u);
  assert.match(wrapper, /VisibleTopLevelWindows/u);
  assert.match(wrapper, /EnumWindows\(callback, IntPtr\.Zero\)/u);
  assert.match(wrapper, /AutomationElement\]::FromHandle\(\$handle\)/u);
  assert.match(wrapper, /\$windowClass -cne '#32770'/u);
  assert.match(wrapper, /\$revalidated\[0\]\.Handle -ne \$picker\.Handle/u);
  assert.match(wrapper, /ControlType\]::Button/u);
  assert.match(wrapper, /Current\.ClassName -ceq 'Button'/u);
  assert.match(wrapper, /\$automationId -ceq '1'/u);
  assert.match(wrapper, /\$automationId -ceq '2'/u);
  assert.match(wrapper, /WindowPattern\]::Pattern/u);
  assert.match(wrapper, /\$windowPattern\.Current\.IsModal/u);
  assert.match(wrapper, /AcquireOwnedForeground/u);
  assert.match(wrapper, /OwnerChainContains\(window, expectedOwner\)/u);
  assert.match(wrapper, /SendEscapeToForegroundWindow/u);
  assert.match(harness, /waitForTrustedPointerClick/u);
  assert.match(harness, /isTrusted: event\.isTrusted === true/u);
  assert.match(wrapper, /closedAfterEscape = \$true/u);
  assert.match(wrapper, /not destroyed after the one Escape input/u);
  assert.match(wrapper, /settings file changed during a cancel-only smoke/u);
});

test("comparison import preflight and idempotence are exact", () => {
  for (const hash of [
    "1EE76BC464FB1C44C8B6546E99CDC21C726C0E2C24AD344F5C19AE41BFC0D2F2",
    "13C07BA64587549EDA9C1A694F3DFA19875CB1F888F02C9E071F17C47739E087",
    "2575C2420800670B0022EBEE819BA3D9640DB14E9552426DF46075D079F1F697"
  ]) {
    assert.ok(harness.includes(hash));
    assert.ok(wrapper.includes(hash));
  }
  assert.match(harness, /baselineMode === "fresh" \? 8 : 0/u);
  assert.match(harness, /baselineMode === "fresh" \? 0 : 8/u);
  assert.match(harness,
    /waitFor\(`comparison \$\{baselineMode\} baseline`[\s\S]*?\{ allowBusy: true \}\);/u);
  assert.match(harness, /receipt\?\.addedPairCount === expectedFirstAdded/u);
  assert.match(harness, /receipt\?\.skippedDuplicateCount === expectedFirstSkipped/u);
  assert.match(harness, /receipt\?\.addedPairCount === 0/u);
  assert.match(harness, /receipt\?\.skippedDuplicateCount === 8/u);
  assert.match(harness,
    /initialDestinationMode = isFresh \? "fresh" : "alreadyImported"/u);
  assert.match(wrapper, /\$script:DestinationBaselineMode = if \(\$isFresh\)/u);
  assert.match(wrapper,
    /Test-JsonEquivalent \$files\.destination \$script:InitialDestinationState/u);
  assert.equal((harness.match(
    /allowBusy: true, allowDialog: true, timeoutMilliseconds: 90_000/g) || []).length, 2);
  assert.match(harness, /secondImportIdempotent = true/u);
  assert.match(harness, /rowId: pair\.rowId/u);
  assert.match(harness, /displayLabel: pair\.displayLabel/u);
  assert.match(harness, /initialPair\.displayLabel !== "KRX100지수 ↔ 코스피 지수"/u);
  assert.doesNotMatch(harness, /pair\.first\?\.displayName|pair\.second\?\.displayName/u);
  assert.match(wrapper, /second import changed the comparison file/u);
});

test("tracked harness cannot synthesize WebView clicks or close the app", () => {
  assert.match(harness, /"Input\.dispatchMouseEvent"/u);
  assert.doesNotMatch(harness, /rpc\("Input\.dispatchMouseEvent"/u);
  assert.doesNotMatch(harness, /rpc\("Input\.dispatchKeyEvent"/u);
  assert.doesNotMatch(harness, /rpc\("(?:Browser|Page)\.close"/u);
  assert.match(shared, /\[switch\]\$DefinitionsOnly/u);
  assert.match(shared, /public static void SendApplicationClick\(/u);
  assert.match(shared, /public static void SendEscapeToForegroundWindow\(/u);
  assert.match(shared, /Key-up only releases the/u);
  assert.match(shared, /caller separately proves that this exact/u);
  assert.doesNotMatch(shared, /lost foreground before Escape was released/u);
});

test("initial native-state race is input-free and stdin cannot hold the helper open", () => {
  assert.match(harness, /process\.stdin\.unref/u);
  assert.match(harness,
    /label !== "DryRun IDLE preflight"[\s\S]*Only the input-free initial preflight/u);
  assert.match(harness,
    /\{ allowBusy: false, allowMissingState: true \}/u);
  assert.match(harness,
    /last\.safety\.outboundMessages\.map\(row => row\.type\)/u);
  assert.match(harness,
    /last\.safety\.blockedOutboundMessages\.length/u);
  assert.match(harness,
    /last\.dom\.connectionText !== "DRY RUN"/u);
});
