"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 read = relativePath => fs.readFileSync(path.join(root, relativePath), "utf8");
const app = read("Web/app.js");
const index = read("Web/index.html");
const styles = read("Web/styles.css");
const native = fs.readdirSync(root)
  .filter(name => /^MainWindow(?:\..+)?\.cs$/u.test(name))
  .map(name => read(name))
  .join("\n");

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

test("trading-halt results expose an accessible stock-name sort header", () => {
  assert.match(index,
    /class="trading-halt-results-header" role="group" aria-label="거래 정지 검색 결과 정렬"[\s\S]*id="tradingHaltNameSort"[\s\S]*aria-controls="tradingHaltResults"[\s\S]*data-sort-direction="none">종목명 ↕<\/button>/u);
  assert.match(styles, /\.trading-halt-results-header\s*\{/u);
  assert.match(styles, /\.trading-halt-results-header button:disabled\s*\{/u);
});

test("render sorts only a copied display view and preserves market-code selection identity", () => {
  const identity = functionBody(app, "tradingHaltIdentity", "toggleTradingHaltNameSort");
  const render = functionBody(app, "renderTradingHaltWorkflow", "requestTradingHaltSearch");

  assert.match(identity, /tradingHaltWorkflow\.tradingHaltIdentity\(value\)/u);
  assert.doesNotMatch(identity, /displayName/u);
  assert.match(render,
    /sortTradingHaltsForDisplay\(\s*workflow\.results,\s*workflow\.sortDirection\)/u);
  assert.match(render,
    /tradingHaltIdentity\(item\) === selectedIdentity/u);
  assert.doesNotMatch(render, /workflow\.results\.sort\(/u);
});

test("sort is blocked while pending, locked, or empty and otherwise toggles locally", () => {
  const toggle = functionBody(app, "toggleTradingHaltNameSort", "selectTradingHalt");
  const render = functionBody(app, "renderTradingHaltWorkflow", "requestTradingHaltSearch");

  assert.match(toggle,
    /isPlaylistSnapshotLocked\(\) \|\| workflow\.status !== "ready" \|\| !workflow\.results\.length/u);
  assert.match(toggle,
    /workflow\.sortDirection = tradingHaltWorkflow\.nextTradingHaltNameSort\(workflow\.sortDirection\)/u);
  assert.match(render,
    /const canSort = workflow\.status === "ready" && workflow\.results\.length > 0/u);
  assert.match(render, /tradingHaltNameSort\.disabled = locked \|\| !canSort/u);
  assert.doesNotMatch(toggle,
    /postNative|requestTradingHaltSearch|state\.playlist|renderPlaylist|updatePreview/u);
});

test("each new search and matching result restores the server-default order", () => {
  const request = functionBody(app, "requestTradingHaltSearch", "handleTradingHaltResults");
  const results = functionBody(app, "handleTradingHaltResults", "handleTradingHaltError");

  assert.match(request,
    /workflow\.status = "loading";[\s\S]*workflow\.results = \[\];[\s\S]*workflow\.sortDirection = null;/u);
  assert.match(results,
    /clearTradingHaltTimeout\(\);\s*workflow\.sortDirection = null;[\s\S]*workflow\.results = \[\.\.\.response\.results\]/u);
});

test("the display sort adds no native command surface or playlist mutation", () => {
  const toggle = functionBody(app, "toggleTradingHaltNameSort", "selectTradingHalt");
  assert.doesNotMatch(toggle,
    /postNative|state\.playlist|renderPlaylist|updatePreview|prepare|take-in|take-out/iu);
  assert.doesNotMatch(native, /sort-trading-halt|trading-halt-sort/iu);
  assert.doesNotMatch(app, /postNative\("(?:sort-trading-halt|trading-halt-sort)"/iu);
});
