"use strict";

const test = require("node:test");
const assert = require("node:assert/strict");
const workflow = require("../../Web/industry-workflow.js");

const kospi = Object.freeze({ market: "kospi", name: "전기전자", code: "013" });
const kospiSecond = Object.freeze({ market: "kospi", name: "운수장비", code: "015" });
const kosdaq = Object.freeze({ market: "kosdaq", name: "반도체", code: "027" });
const kosdaqSecond = Object.freeze({ market: "kosdaq", name: "IT부품", code: "029" });

test("industry runtime assets expose 22 exact cut templates per market", () => {
  assert.equal(workflow.cuts.length, 22);
  assert.equal(new Set(workflow.cuts.map(value => value.id)).size, 22);
  assert.equal(workflow.runtimeAssets.kospi.sha256, "F21DE58003315EAB41F9FE7B5A573C71653056203E6743D05AA96E7FF1B8BF52");
  assert.equal(workflow.runtimeAssets.kosdaq.sha256, "F25B8926E8F20FC5FBC94A1891A9E2EAD22852E8C829321EF1A001FE3F42ECE4");
});

test("native industry rows normalize only bounded KOSPI and KOSDAQ identities", () => {
  assert.deepEqual(workflow.normalizeIndustry({ market: "KOSPI", name: " 전기전자 ", code: "013" }), kospi);
  assert.equal(workflow.normalizeIndustry({ market: "nxt-kospi", name: "전기전자", code: "013" }), null);
  assert.equal(workflow.normalizeIndustry({ market: "kospi", name: "전기\n전자", code: "013" }), null);
  assert.equal(workflow.normalizeIndustry({ market: "kospi", name: "전기전자", code: "01-3" }), null);
});

test("single, pair, yield and candle actions project closed legacy selections", () => {
  const single = workflow.createIndustryPlaylistEntry("kospi", "one-column", {
    id: "single", selected: kospi
  });
  assert.equal(single.builderKey, "s5001");
  assert.equal(single.code, "5001");
  assert.deepEqual(single.selection, {
    groupCode: "INDUSTRY_KOSPI", subject: "전기전자",
    graphicType: "1열판", subtype: "CURRENT", dataCode: ""
  });

  const pair = workflow.createIndustryPlaylistEntry("kosdaq", "two-column", {
    id: "pair", pair: [kosdaq, kosdaqSecond]
  });
  assert.equal(pair.builderKey, "s8018");
  assert.equal(pair.code, "8032");
  assert.equal(pair.selection.subject, "반도체-IT부품");

  const yieldEntry = workflow.createIndustryPlaylistEntry("kospi", "yield-120일", {
    id: "yield", selected: kospi
  });
  assert.equal(yieldEntry.builderKey, "s5086");
  assert.equal(yieldEntry.selection.subtype, "OneHundredTwentyDays");

  const candle = workflow.createIndustryPlaylistEntry("kosdaq", "candle-volume-240일", {
    id: "candle", selected: kosdaq
  });
  assert.equal(candle.builderKey, "s8010");
  assert.equal(candle.code, "8056");
  assert.equal(candle.selection.groupCode, "KOSDAQ_INDUSTRY");
  assert.equal(candle.selection.subtype, "VOLUME");
});

test("market-wide industry actions need no selected industry and use explicit aliases", () => {
  const now = new Date(2026, 6, 11, 10, 0, 0);
  const five = workflow.createIndustryPlaylistEntry("kosdaq", "five-row", { id: "five", now });
  assert.equal(five.builderKey, "s5074");
  assert.equal(five.selection.groupCode, "PAGED_DOMESTIC_KOSDAQ");
  assert.equal(five.selection.subtype, "INDUSTRY");
  assert.equal(five.selection.dataCode, "2026-07-11");

  const square = workflow.createIndustryPlaylistEntry("kosdaq", "square", { id: "square" });
  assert.equal(square.builderKey, "s8001");
  assert.equal(square.code, "8002");
  assert.equal(square.selection.subject, "KOSDAQ");

  const sector = workflow.createIndustryPlaylistEntry("kospi", "sector", { id: "sector" });
  assert.equal(sector.builderKey, "s5078");
  assert.equal(sector.selection.graphicType, "SECTOR_INDEX");
});

test("industry candles carry and restore the global moving-average flags", () => {
  const value = workflow.createIndustryPlaylistEntry("kospi", "candle-120일", {
    id: "industry-candle-flags",
    selected: kospi,
    ma5: true,
    ma20: true
  });
  assert.equal(value.selection.graphicType, "MA5,MA20");
  assert.deepEqual(value.operator.movingAverages, { ma5: true, ma20: true });
  assert.deepEqual(workflow.restoreIndustryPlaylistEntry(value), value);
  assert.equal(workflow.restoreIndustryPlaylistEntry({
    ...value,
    selection: { ...value.selection, graphicType: "MA20" }
  }), null);
});

test("legacy industry candle entries gain closed moving-average metadata on restore", () => {
  const value = workflow.createIndustryPlaylistEntry("kosdaq", "candle-volume-20일", {
    id: "industry-candle-legacy",
    selected: kosdaq
  });
  const legacy = {
    ...value,
    operator: Object.freeze(Object.fromEntries(
      Object.entries(value.operator).filter(([key]) => key !== "movingAverages")))
  };
  assert.deepEqual(
    workflow.restoreIndustryPlaylistEntry(legacy).operator.movingAverages,
    { ma5: false, ma20: false });
});

test("selection prerequisites and cross-market values fail closed", () => {
  assert.equal(workflow.isCutAllowed("kospi", "one-column", null, null, null), false);
  assert.equal(workflow.isCutAllowed("kospi", "two-column", kospi, kospi, null), false);
  assert.equal(workflow.isCutAllowed("kospi", "two-column", null, kospi, kospiSecond), true);
  assert.equal(workflow.isCutAllowed("kospi", "five-row", null, null, null), true);
  assert.throws(() => workflow.createIndustryPlaylistEntry("kospi", "one-column", {
    id: "cross", selected: kosdaq
  }));
});

test("stored industry entries restore from trusted bindings and reject tampering", () => {
  const value = workflow.createIndustryPlaylistEntry("kospi", "two-column", {
    id: "stored-pair", pair: [kospi, kospiSecond]
  });
  assert.ok(workflow.restoreIndustryPlaylistEntry(value));
  assert.equal(workflow.restoreIndustryPlaylistEntry({ ...value, code: "5032" }), null);
  assert.equal(workflow.restoreIndustryPlaylistEntry({
    ...value,
    selection: { ...value.selection, subject: "전기전자-화학" }
  }), null);
  assert.equal(workflow.restoreIndustryPlaylistEntry({
    ...value,
    operator: { ...value.operator, assetSha256: "0".repeat(64) }
  }), null);
});

test("paged industry dates refresh at restore time", () => {
  const original = workflow.createIndustryPlaylistEntry("kospi", "five-row", {
    id: "paged", now: new Date(2026, 6, 10, 23, 59, 0)
  });
  const refreshed = workflow.restoreIndustryPlaylistEntry(original, {
    now: new Date(2026, 6, 11, 0, 1, 0)
  });
  assert.equal(refreshed.selection.dataCode, "2026-07-11");
});
