"use strict";

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

const root = path.resolve(__dirname, "..", "..");
const app = fs.readFileSync(path.join(root, "Web", "app.js"), "utf8");
const index = fs.readFileSync(path.join(root, "Web", "index.html"), "utf8");
const native = fs.readFileSync(path.join(root, "MainWindow.NamedKrxThemeRestore.cs"), "utf8");
const namedBridge = fs.readFileSync(path.join(root, "MainWindow.NamedPlaylists.cs"), "utf8");

function functionBody(name, nextName) {
  const start = app.indexOf(`function ${name}(`);
  const end = app.indexOf(`function ${nextName}(`, start + 1);
  assert.ok(start >= 0 && end > start, `${name} must precede ${nextName}`);
  return app.slice(start, end);
}

test("named KRX restore is correlated from one native load through page preflight", () => {
  assert.match(index,
    /src="named-krx-theme-restore-workflow\.js"[\s\S]*src="named-nxt-theme-restore-workflow\.js"/u);
  assert.match(namedBridge,
    /await PostNamedKrxThemeRestoreAsync\([\s\S]*await PostNamedNxtThemeRestoreAsync\(/u);
  assert.match(native, /PostMessage\("named-krx-theme-restore-results"/u);
  assert.match(app, /krxThemeRestorePending/u);
  assert.match(app, /case "named-krx-theme-restore-results"/u);
  assert.match(app, /case "named-krx-theme-restore-error"/u);
  const finalize = functionBody("finalizeNamedManualRestores", "handleNamedManualListResults");
  assert.match(finalize, /state\.namedPlaylist\.krxThemeRestorePending/u);
  assert.match(finalize, /prepareNamedPagePreflight/u);
});

test("generic theme restore cannot trust a historical KRX code before native verification", () => {
  const addTheme = functionBody("addThemeNamedCandidates", "addOverseasNamedCandidates");
  assert.match(addTheme,
    /rawRow\.groupCode === "테마" \|\| rawRow\.groupCode === "테마_NXT"/u);
  const load = functionBody("handleNamedPlaylistLoadResults", "failNamedComparisonRestore");
  assert.match(load, /namedKrxThemeRestoreWorkflow\.classify/u);
  assert.match(load, /pendingKrxThemes\.length === 0/u);
  assert.match(load, /krxThemeRestorePending = pendingKrxThemes\.length/u);
  const resolve = functionBody("resolveNamedPlaylistRawRow", "prepareNamedPagePreflight");
  assert.match(resolve,
    /rawRow\?\.groupCode === "테마" \|\| rawRow\?\.groupCode === "테마_NXT"[\s\S]*return null/u);
});

test("current KRX identity stays branded in memory and old code is retained only for save", () => {
  const materialize = functionBody("materializeNamedRestoration", "namedPlaylistPrepareBlockers");
  assert.match(materialize,
    /namedKrxThemeRestoreWorkflow\.isMaterializedEntry\(row\.entry\)/u);
  const synchronize = functionBody("synchronizeThemeEntries", "clearOverseasTimeout");
  assert.match(synchronize,
    /namedKrxThemeRestoreWorkflow\.isMaterializedEntry\(item\)[\s\S]*\? item/u);
  const fields = functionBody("namedLegacyFieldsForEntry", "isTrustedNamedPlaylistEntry");
  assert.match(fields, /namedKrxThemeRestoreWorkflow\.legacySelectionForEntry\(entry\)/u);
  assert.match(fields, /namedKrxThemeRestoreWorkflow\.matchesRaw\(entry, rawRow\)/u);
  assert.match(fields, /KRX 테마의 과거 code와 현재 송출 code/u);
});

test("KRX failures are terminal and never trigger an automatic retry or playout", () => {
  const failed = functionBody("failNamedKrxThemeRestore", "handleNamedKrxThemeRestoreResults");
  assert.match(failed, /krxThemeRestorePending = null/u);
  assert.doesNotMatch(app, /retryNamedKrxTheme|requestNamedKrxThemeRestore/u);
  assert.doesNotMatch(native, /IPlayoutEngine|PrepareAsync|TakeInAsync|NextAsync|TakeOutAsync/u);
  assert.match(native, /retryable = false/u);
});

test("KRX success accounting and post-load cancellation close every correlated busy record", () => {
  const results = functionBody("handleNamedKrxThemeRestoreResults", "handleNamedKrxThemeRestoreError");
  assert.match(results,
    /state\.playlist\[pending\.itemIndex\] = entry;\s*restoredCount \+= 1;/u);

  const clear = functionBody("clearNamedPlaylistLoadState", "saveNamedPlaylistBackup");
  assert.match(clear, /krxThemeRestorePending = null/u);
  const busy = functionBody("namedPlaylistBusy", "renderNamedPlaylist");
  assert.match(busy, /state\.namedPlaylist\.krxThemeRestorePending/u);
  const loadError = functionBody("handleNamedPlaylistError", "normalizePlayoutState");
  assert.match(loadError, /error\.operation !== "load"/u);
  assert.match(loadError,
    /state\.namedPlaylist\.krxThemeRestorePending\?\.requestId === error\.requestId[\s\S]*krxThemeRestorePending = null/u);
  assert.match(loadError, /복원 배치는 자동 재시도하지 않습니다/u);
});
