"use strict";

const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const workflow = require("../../Web/manual-financial-workflow.js");

const repositoryRoot = path.resolve(__dirname, "..", "..");
const bridge = fs.readFileSync(
  path.join(repositoryRoot, "MainWindow.ManualFinancial.cs"),
  "utf8");
const playoutBridge = fs.readFileSync(
  path.join(repositoryRoot, "MainWindow.Playout.cs"),
  "utf8");
const operatorGate = fs.readFileSync(
  path.join(repositoryRoot, "src", "MBN_STOCK_WEBVIEW.Core", "Playout", "OperatorMutationGate.cs"),
  "utf8");

test("native partial exposes every strict workflow request and response", () => {
  for (const [name, value] of Object.entries(workflow.bridgeContract)) {
    if (name.endsWith("RequestType") || name.endsWith("ResultType") || name.endsWith("ErrorType")) {
      assert.match(bridge, new RegExp(`"${value}"`));
    }
  }
  assert.match(bridge, /private bool TryHandleManualFinancialRequest\(/);
  assert.match(bridge, /HasOnlyProperties\(payload, "requestId", "screen", "stock", "record"\)/);
  assert.match(bridge, /element\.GetArrayLength\(\) != 5/);
  assert.match(bridge, /element\.GetArrayLength\(\) != 4/);
  assert.match(bridge, /element\.GetArrayLength\(\) != 6/);
});

test("runtime helper composes the typed service with the non-retrying Oracle executor", () => {
  assert.match(bridge,
    /new LegacyManualFinancialScreenService\(\s*runtime\.Executor,\s*new OracleManualFinancialMutationExecutor\(/s);
  assert.match(bridge, /runtime\.ConnectionFactory/);
  assert.match(bridge, /runtime\.Options\.Resilience/);
});

test("list, load and selection reads own independent correlation lanes", () => {
  assert.match(bridge,
    /Dictionary<string, ManualFinancialReadRequest> _manualFinancialReadLanes/);
  assert.match(bridge,
    /new ManualFinancialReadRequest\(\s*operation,\s*requestId,/s);
  assert.match(bridge, /RegisterManualFinancialRead\(request\)/);
  assert.match(bridge, /_manualFinancialReadLanes\[request\.Lane\] = request/);
  assert.doesNotMatch(bridge, /_manualFinancialReadCancellation/);
  assert.match(bridge, /await _databaseActivityGate\.WaitAsync\(requestToken\)/);
  assert.ok((bridge.match(/Volatile\.Read\(ref _playoutCommandInFlight\) != 0/g) || []).length >= 2);
  assert.match(bridge, /browserGeneration != Volatile\.Read\(ref _manualFinancialBrowserGeneration\)/);
  assert.match(bridge, /!TryCompleteManualFinancialReadIfCurrent\(request\)/);
});

test("same-lane supersede emits one correlated terminal cancellation", () => {
  assert.match(bridge, /CancelRequest\(superseded\.Cancellation\)/);
  assert.match(bridge, /superseded\?\.TryComplete\(\)/);
  assert.match(bridge, /"CANCELLED"/);
  assert.match(bridge, /newer request replaced it/);
  assert.match(bridge,
    /Interlocked\.CompareExchange\(ref _terminalState, 1, 0\) == 0/);
  assert.match(bridge,
    /TryCompleteManualFinancialReadIfCurrent\(request\)[\s\S]*PostMessage\(reply\.MessageType/s);
  assert.match(bridge,
    /ReferenceEquals\(current, request\) &&[\s\S]*request\.TryComplete\(\)/s);
});

test("writes are single-flight and impossible during command, PREPARED, PROGRAM or refresh", () => {
  assert.match(bridge, /_manualFinancialWriteGate\.WaitAsync\(0\)/);
  assert.match(bridge, /_playoutCommandGate\.WaitAsync\(0, requestToken\)/);
  assert.match(bridge, /_databaseActivityGate\.WaitAsync\(0, requestToken\)/);
  assert.match(bridge, /CanStartManualFinancialWrite\(\)/);
  assert.match(bridge,
    /CanStartOperatorMutation\(IsManualFinancialWriteQuarantined\(\)\)/);
  assert.match(playoutBridge, /private bool CanStartOperatorMutation\(/);
  assert.match(playoutBridge, /new OperatorMutationGateSnapshot\(/);
  assert.match(playoutBridge, /IsEngineAvailable: engine is not null/);
  assert.match(playoutBridge, /IsWorkflowAvailable: workflow is not null/);
  assert.match(playoutBridge, /IsRefreshTaskRunning: _legacyRefreshTask is \{ IsCompleted: false \}/);
  for (const condition of [
    "IsCommandAvailable", "IsPlayCompletionPending", "PreparedSceneName", "OnAirSceneName",
    "PreparedCutCode", "OnAirCutCode", "IsRefreshActive", "IsRefreshTaskRunning"
  ]) {
    assert.match(operatorGate, new RegExp(`snapshot\\.${condition}`));
  }
  assert.match(bridge, /"PLAYOUT_ACTIVE"/);
});

test("OutcomeUnknown and browser correlation loss latch a process-lifetime no-retry quarantine", () => {
  assert.match(bridge, /catch \(ManualFinancialMutationException exception\)/);
  assert.match(bridge, /if \(exception\.OutcomeUnknown\)/);
  assert.match(bridge,
    /Interlocked\.CompareExchange\(ref _manualFinancialWriteQuarantined, 1, 0\)/);
  assert.match(bridge, /retryable = false/);
  assert.match(bridge, /rolled back and was not retried/i);
  assert.doesNotMatch(bridge, /for\s*\([^)]*retry|while\s*\([^)]*retry/i);
});

test("browser, playout and shutdown hooks cancel correlation without clearing quarantine", () => {
  assert.match(bridge, /private void InvalidateManualFinancialBrowserRequests\(\)/);
  assert.match(bridge, /Interlocked\.Increment\(ref _manualFinancialBrowserGeneration\)/);
  assert.match(bridge, /Volatile\.Read\(ref _manualFinancialWriteInFlight\) != 0/);
  assert.match(bridge,
    /Interlocked\.Exchange\(ref _manualFinancialWriteCancellation, null\)/);
  assert.match(bridge, /private void CancelManualFinancialReadsForPlayout\(\)/);
  assert.match(bridge, /private void ShutdownManualFinancialRuntime\(\)/);
  assert.ok((bridge.match(/SnapshotManualFinancialReads\(clear: true\)/g) || []).length >= 2);
  assert.match(bridge,
    /CancelManualFinancialReadsForPlayout\(\)[\s\S]*SnapshotManualFinancialReads\(clear: false\)/s);
});

test("selection and restore boundaries re-read row version before exposing a cut", () => {
  assert.match(bridge, /var snapshot = await service\.GetAsync\(identity, cancellationToken\)/);
  assert.match(bridge, /EnsureManualFinancialRowVersion\(snapshot, rowVersion\)/);
  assert.match(bridge, /ResolveManualFinancialStockAsync\(/);
  assert.match(bridge, /ManualFinancialCutContracts\.CreateSelection\(snapshot, verified\)/);
  assert.match(bridge, /"manual-financial-selection-results"/);
});

test("successful writes return the real transaction receipt fields", () => {
  assert.match(bridge, /operationId = receipt\.OperationId\.ToString\("N"/);
  assert.match(bridge, /receipt\.CommittedAt/);
  assert.match(bridge, /receipt\.AffectedRows/);
});
