"use strict";

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

const fixed = require("../../Web/legacy-fixed-workflow.js");
const industry = require("../../Web/industry-workflow.js");
const stock = require("../../Web/operator-workflow.js");
const comparison = require("../../Web/comparison-workflow.js");

const now = new Date("2026-07-11T12:00:00+09:00");
const kospiStock = Object.freeze({
  market: "kospi",
  stockName: "삼성전자",
  displayName: "삼성전자",
  stockCode: "005930",
  isNxt: false
});
const primaryIndustry = Object.freeze({
  market: "kospi",
  code: "001",
  name: "전기전자"
});
const secondaryIndustry = Object.freeze({
  market: "kospi",
  code: "002",
  name: "금융업"
});
const kosdaqPrimaryIndustry = Object.freeze({
  market: "kosdaq",
  code: "101",
  name: "IT"
});
const kosdaqSecondaryIndustry = Object.freeze({
  market: "kosdaq",
  code: "102",
  name: "제약"
});
const comparisonPair = Object.freeze([
  Object.freeze({ kind: "krx-stock", market: "kospi", stockName: "삼성전자", stockCode: "005930" }),
  Object.freeze({ kind: "krx-stock", market: "kospi", stockName: "SK하이닉스", stockCode: "000660" })
]);

test("the original operator command matrix has exactly 412 visible slots", () => {
  assert.equal(fixed.actions.length, 328);
  assert.equal(industry.cuts.length * industry.markets.length, 44);
  assert.equal(stock.stockCuts.length, 31);
  assert.equal(comparison.actions.length, 9);
  assert.equal(
    fixed.actions.length + industry.cuts.length * industry.markets.length +
      stock.stockCuts.length + comparison.actions.length,
    412);

  assert.equal(new Set(fixed.actions.map(value => value.id)).size, 328);
  assert.equal(new Set(industry.cuts.map(value => value.id)).size, 22);
  assert.equal(new Set(stock.stockCuts.map(value => value.id)).size, 31);
  assert.equal(new Set(comparison.actions.map(value => value.id)).size, 9);
});

test("all 322 non-manual fixed slots create and strictly round-trip", () => {
  const available = fixed.actions.filter(value => value.available);
  assert.equal(available.length, 322);

  for (const [index, action] of available.entries()) {
    const created = fixed.createFixedPlaylistEntry(action.id, {
      id: `fixed-matrix-${index + 1}`,
      fadeDuration: 6,
      now,
      ma5: true,
      ma20: true
    });
    const restored = fixed.restoreFixedPlaylistEntry(created, { now });
    assert.ok(restored, `${action.id} ${action.label}`);
    assert.equal(restored.builderKey, action.builderKey);
    assert.equal(restored.code, action.code);
  }
});

test("the six fixed manual placeholders resolve only through their dedicated editors", () => {
  const manual = fixed.actions.filter(value => !value.available);
  assert.deepEqual(
    manual.map(value => [value.id, value.label, value.builderKey, value.code]),
    [
      ["fixed-245", "개인 순매도 상위(수동)", "s5025", "5025"],
      ["fixed-246", "외국인 순매도 상위(수동)", "s5025", "5025"],
      ["fixed-247", "기관 순매도 상위(수동)", "s5025", "5025"],
      ["fixed-262", "VI 발동(수동)", "s5074", "5074"],
      ["fixed-293", "VI 발동(수동)", "s5074", "5074"],
      ["fixed-320", "VI 발동(수동)", "s5074", "5074"]
    ]);
  for (const action of manual) {
    assert.throws(() => fixed.createFixedPlaylistEntry(action.id, {
      id: `blocked-${action.id}`,
      fadeDuration: 6,
      now
    }), /manual|수동|입력/i);
  }
});

test("all 44 industry slots create and strictly round-trip with explicit selections", () => {
  let ordinal = 0;
  for (const market of industry.markets) {
    const selected = market === "kospi" ? primaryIndustry : kosdaqPrimaryIndustry;
    const pair = market === "kospi"
      ? [primaryIndustry, secondaryIndustry]
      : [kosdaqPrimaryIndustry, kosdaqSecondaryIndustry];
    for (const cut of industry.cuts) {
      ordinal += 1;
      const created = industry.createIndustryPlaylistEntry(market, cut.id, {
        id: `industry-matrix-${ordinal}`,
        fadeDuration: 6,
        selected,
        pair,
        now,
        ma5: true,
        ma20: true
      });
      const restored = industry.restoreIndustryPlaylistEntry(created, { now });
      assert.ok(restored, `${market} ${cut.id}`);
      assert.equal(restored.builderKey, created.builderKey);
      assert.equal(restored.code, created.code);
    }
  }
  assert.equal(ordinal, 44);
});

test("all 31 stock and nine comparison slots create and strictly round-trip", () => {
  for (const [index, cut] of stock.stockCuts.entries()) {
    const created = stock.createStockPlaylistEntry(kospiStock, cut.id, {
      id: `stock-matrix-${index + 1}`,
      fadeDuration: 6,
      ma5: true,
      ma20: true
    });
    assert.ok(stock.restoreStockPlaylistEntry(created), cut.id);
  }

  for (const [index, action] of comparison.actions.entries()) {
    const created = comparison.createComparisonPlaylistEntry(
      action.id,
      comparisonPair,
      { id: `comparison-matrix-${index + 1}`, fadeDuration: 6 });
    assert.ok(comparison.restoreComparisonPlaylistEntry(created), action.id);
  }
});

test("the four GraphE buttons remain outside the 412 slots and map to exact INPUT tables", () => {
  assert.deepEqual(
    stock.manualStockActions.map(value => [value.id, value.builderKey, value.prerequisiteTable]),
    [
      ["manual-revenue-mix", "s5076", "INPUT_PIE"],
      ["manual-growth-metrics", "s5079", "INPUT_GROW"],
      ["manual-sales", "s5080", "INPUT_SELL"],
      ["manual-operating-profit", "s5081", "INPUT_PROFIT"]
    ]);
});
