"use strict";

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

const root = path.resolve(__dirname, "..", "..");
const native = fs.readFileSync(path.join(root, "MainWindow.ManualLists.cs"), "utf8");
const dispatch = fs.readFileSync(path.join(root, "MainWindow.xaml.cs"), "utf8");
const importer = fs.readFileSync(path.join(
  root,
  "src",
  "MBN_STOCK_WEBVIEW.Infrastructure",
  "Playout",
  "LegacyManualOperatorDataImporter.cs"), "utf8");
const playout = fs.readFileSync(path.join(root, "MainWindow.Playout.cs"), "utf8");
const factory = fs.readFileSync(path.join(root, "LegacySceneRuntimeFactory.cs"), "utf8");
const app = fs.readFileSync(path.join(root, "Web/app.js"), "utf8");

test("generic catalog cannot add the s5025 sample outside the trusted manual-list workflow", () => {
  assert.match(app, /operatorInputBuilderKeys[\s\S]*"s5025"/u);
  assert.match(app,
    /item\.builderKey === "s5025"[\s\S]*투자자별 수동 목록 화면에서 추가/u);
});

test("native VI responses expose the canonical version and no-op persistence receipt", () => {
  assert.match(native, /ReadSnapshotAsync\(_lifetimeCancellation\.Token\)/u);
  assert.match(native, /version = snapshot\.RowVersion/u);
  assert.match(native, /persisted = result\.Persisted/u);
  assert.match(native, /version = result\.Snapshot\.RowVersion/u);
});

test("VI writes require a closed expected version and compare it under the data gate before mutation", () => {
  assert.match(native, /HasOnlyProperties\(payload, "requestId", "expectedVersion", "items"\)/u);
  assert.match(native, /TrustedViManualReference\.IsRowVersion\(expectedVersion\)/u);

  const methodStart = native.indexOf("private async Task HandleViManualListWriteAsync");
  const methodEnd = native.indexOf("private async Task<bool> TryEnterManualMutationGatesAsync", methodStart);
  const method = native.slice(methodStart, methodEnd);
  const gate = method.indexOf("TryEnterManualMutationGatesAsync");
  const reread = method.indexOf("var currentSnapshot = await store.ReadSnapshotAsync");
  const compare = method.indexOf("currentSnapshot.RowVersion");
  const stale = method.indexOf('"STALE_DATA"');
  const mutation = method.indexOf("var result = await store.WriteAsync");
  assert.ok(methodStart >= 0 && methodEnd > methodStart);
  assert.ok(gate >= 0 && gate < reread && reread < compare && compare < stale && stale < mutation);
  assert.match(method.slice(stale, mutation), /retryable: false,[\s\S]*outcomeUnknown: false/u);
});

test("different post-error readback always enters OutcomeUnknown quarantine", () => {
  assert.equal(native.includes('"SAVE_FAILED"'), false);
  assert.match(native, /수동 순매도 저장 중 파일 내용이 달라져 결과를 확정할 수 없습니다/u);
  assert.match(native, /VI 수동 목록 저장 중 파일 내용이 달라져 결과를 확정할 수 없습니다/u);
  assert.ok((native.match(/PostManualOperatorQuarantine\(requestId, "save-/gu) || []).length >= 4);
});

test("configured external operator paths are disabled before any directory creation", () => {
  const configuredGuard = native.indexOf("if (!string.IsNullOrWhiteSpace(configuredDirectory))");
  const privatePrepare = native.indexOf("TrustedManualDirectory.PreparePrivateWritableDirectory");
  assert.ok(configuredGuard >= 0);
  assert.ok(privatePrepare > configuredGuard);
  assert.equal(native.includes("Directory.CreateDirectory(directory)"), false);
});

test("interrupted import guard runs before either manual store can be constructed", () => {
  const inspection = native.indexOf("LegacyManualOperatorDataRuntimeGuard.Inspect(directory)");
  const readyGuard = native.indexOf("if (!inspection.IsReady)", inspection);
  const failClosedReturn = native.indexOf("return;", readyGuard);
  const netStore = native.indexOf("new S5025TrustedManualFileStore(directory)", inspection);
  const viStore = native.indexOf("new ViTrustedManualFileStore(directory)", inspection);
  assert.ok(inspection >= 0 && readyGuard > inspection && failClosedReturn > readyGuard);
  assert.ok(netStore > failClosedReturn && viStore > failClosedReturn);
  assert.match(importer, /if \(EntryExists\(intentPath\)\)[\s\S]*Do not read any production file/u);
});

test("legacy import commit has a durable intent before moves and marker remains last", () => {
  const commitStart = importer.indexOf("private void CommitAndVerify");
  const commitEnd = importer.indexOf("private void WriteIntentDurably", commitStart);
  const commit = importer.slice(commitStart, commitEnd);
  const intent = commit.indexOf("WriteIntentDurably(intentPath, intentBytes)");
  const dataMove = commit.indexOf("File.Move(file.TemporaryPath, file.FinalPath");
  const readback = commit.indexOf("VerifyImportedData(snapshot)");
  const markerMove = commit.indexOf("File.Move(marker.TemporaryPath, marker.FinalPath");
  const intentRemoval = commit.indexOf("DeleteOwnedFile(", markerMove);
  assert.ok(intent >= 0 && intent < dataMove && dataMove < readback);
  assert.ok(readback < markerMove && markerMove < intentRemoval);
  assert.match(importer, /FileOptions\.WriteThrough[\s\S]*Flush\(flushToDisk: true\)/u);
});

test("trusted VI source is injected and checked for both page plan and page load", () => {
  assert.match(playout, /trustedViSource: _viManualListStore/u);
  assert.match(factory, /ITrustedViStockNameSnapshotSource\? trustedViSource/u);
  assert.ok((factory.match(/TrustedViManualReference\.ResolveAsync/gu) || []).length >= 2);
});

test("legacy manual import bridge is closed, fixed under UserProfile, and never accepts a path", () => {
  assert.match(dispatch, /case "import-legacy-manual-operator-data"/u);
  const methodStart = native.indexOf("private async Task HandleLegacyManualOperatorImportAsync");
  const methodEnd = native.indexOf("private async Task HandleManualNetSellReadAsync", methodStart);
  const method = native.slice(methodStart, methodEnd);
  assert.ok(methodStart >= 0 && methodEnd > methodStart);
  assert.match(method, /HasOnlyProperties\(payload, "requestId"\)/u);
  assert.equal(/GetProperty\([^)]*(?:path|directory|source)/iu.test(method), false);
  assert.match(importer, /Environment\.SpecialFolder\.UserProfile/u);
  assert.match(importer, /FixedRelativeDirectory/u);
  assert.equal(importer.includes("MBN_STOCK_OPERATOR_DATA_DIRECTORY"), false);
  assert.equal(importer.includes("C:\\Users\\MD"), false);
});

test("legacy manual import returns only a versioned receipt and terminal no-retry errors", () => {
  assert.match(native, /PostMessage\("legacy-manual-operator-import-result"/u);
  assert.match(native, /markerVersion = result\.MarkerVersion/u);
  assert.match(native, /sourceSha256 = result\.SourceSha256/u);
  assert.match(native, /retryable: false,[\s\S]*outcomeUnknown: false/u);
  assert.match(native, /PostManualOperatorQuarantine\(requestId, operation\)/u);
  assert.equal(native.includes("result.SourcePath"), false);
});
