"use strict";

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 webRoot = path.join(root, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "Web");
const app = fs.readFileSync(path.join(webRoot, "app.js"), "utf8");
const styles = fs.readFileSync(path.join(webRoot, "styles.css"), "utf8");

function section(startToken, endToken) {
  const start = app.indexOf(startToken);
  const end = app.indexOf(endToken, start + startToken.length);
  assert.ok(start >= 0 && end > start, `missing ${startToken} section`);
  return app.slice(start, end);
}

test("UC5 Web keeps the original top-to-bottom index, industry, stock order", () => {
  const render = section("function renderOverseas(state)", "function renderComparison(state)");
  const fixed = render.indexOf('fixedHeading.textContent = "해외지수"');
  const industry = render.indexOf('searchGroup("industry", "해외 업종지수", "업종 검색"');
  const stock = render.indexOf('searchGroup("stock", "해외 종목", "종목 검색"');

  assert.ok(fixed >= 0 && fixed < industry && industry < stock);
  assert.match(render, /periodButtons\("fixedIndex"\)/);
  assert.match(render, /model\.isTruncated === true/);
  assert.match(render, /model\.isolatedInvalidRowCount/);
  assert.match(render, /표시명 없음/);
  assert.match(render, /검색 결과가 안전 상한을 초과해 일부만 표시됩니다\./);
  assert.doesNotMatch(render, /최대 500건/);
  assert.match(styles, /\.overseas-truncation/);
  assert.match(render, /actionButton\(current, "1열판"\)/);
  assert.match(render, /action\.periodDays \+ "일"/);
  assert.doesNotMatch(render, /overseas-action-panel|overseas-selected|overseas-note/);
  assert.doesNotMatch(render, /document\.createElement\("details"\)/);

  for (const selector of [
    ".overseas-workspace",
    ".overseas-fixed-body",
    ".overseas-period-actions",
    ".overseas-result-area"
  ]) {
    assert.match(styles, new RegExp(selector.replaceAll(".", "\\.")));
  }
  assert.match(styles, /grid-template-rows:\s*minmax\(176px.*minmax\(184px.*minmax\(210px/u);
});

test("UC5 rows are immediately selected, preserve their DOM on receipts, and keep data private", () => {
  const render = section("function renderOverseas(state)", "function renderComparison(state)");
  const update = section("function updateOverseasWorkspace", "function markOverseasRowSelected");
  const click = section(
    'categoryTree.addEventListener("click"',
    'categoryTree.addEventListener("change"');
  const overseasClick = click.slice(
    click.indexOf('const overseasTarget = event.target.closest("button[data-overseas-target-id]");'),
    click.indexOf("const comparisonChoice", click.indexOf("const overseasTarget")));

  assert.match(app, /function selectOverseasRow\(row\)[\s\S]*markOverseasRowSelected\(row\)/);
  assert.match(overseasClick, /selectOverseasRow\(overseasTarget\)/);
  assert.match(overseasClick, /selectOverseasRow\(overseasResult\)/);
  assert.doesNotMatch(overseasClick, /setTimeout/);
  assert.match(render,
    /existingWorkspace && structureKey === overseasRenderStructureKey[\s\S]*updateOverseasWorkspace\(existingWorkspace, overseas/);
  assert.doesNotMatch(update, /replaceChildren/);
  assert.doesNotMatch(render, /nationCode|FOREIGN_|symbol/i);
  assert.match(app, /event\.key === "Enter"[\s\S]*overseas-industry-search/);
});

test("UC5 listboxes keep one tab stop and move a single native selection by keyboard", () => {
  const helper = section("function moveOverseasListSelection", "function renderOverseas(state)");
  const keydown = section(
    'categoryTree.addEventListener("keydown"',
    'window.addEventListener("pointerup"');

  assert.match(helper, /list\.getAttribute\("aria-disabled"\) === "true"/);
  assert.match(helper, /querySelectorAll\("button"\)/);
  assert.match(helper, /selectOverseasRow\(nextRow\)/);
  assert.match(helper, /scrollIntoView\(\{ block: "nearest", inline: "nearest" \}\)/);
  assert.match(keydown, /const overseasList = event\.target\.closest\("\[data-overseas-list\]"\)/);
  assert.match(keydown, /event\.stopPropagation\(\);[\s\S]*moveOverseasListSelection\(overseasList, event\.key\)/);
  assert.match(keydown, /moveOverseasListSelection\(overseasList, event\.key\)/);
  assert.match(app, /button\.tabIndex = -1/g);

  const rows = [0, 1, 2].map(index => ({
    index,
    selected: false,
    scrolled: 0,
    getAttribute(name) { return name === "aria-selected" ? String(this.selected) : null; },
    scrollIntoView() { this.scrolled += 1; }
  }));
  const list = {
    busy: false,
    getAttribute(name) { return name === "aria-disabled" && this.busy ? "true" : "false"; },
    querySelectorAll(selector) { assert.equal(selector, "button"); return rows; }
  };
  const selected = [];
  const move = new Function("selectOverseasRow", `${helper}; return moveOverseasListSelection;`)(row => {
    rows.forEach(candidate => { candidate.selected = candidate === row; });
    selected.push(row.index);
  });

  assert.equal(move(list, "ArrowDown"), true);
  assert.equal(move(list, "ArrowDown"), true);
  assert.equal(move(list, "Home"), true);
  assert.equal(move(list, "ArrowUp"), false);
  assert.equal(move(list, "End"), true);
  assert.deepEqual(selected, [0, 1, 0, 2]);
  assert.equal(rows[0].scrolled, 2);
  assert.equal(rows[1].scrolled, 1);
  assert.equal(rows[2].scrolled, 1);

  list.busy = true;
  assert.equal(move(list, "ArrowUp"), false);
  assert.deepEqual(selected, [0, 1, 0, 2]);
  const empty = { getAttribute() { return "false"; }, querySelectorAll() { return []; } };
  assert.equal(move(empty, "ArrowDown"), false);
});
