"use strict";

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

function raw(overrides = {}) {
  return {
    itemIndex: 0,
    enabled: true,
    groupCode: "코스피,코스닥",
    subject: "삼성전자,에이비엘바이오",
    graphicType: "종목별 비교분석_캔들 그래프",
    subtype: "",
    pageText: "1/1",
    dataCode: "",
    ...overrides
  };
}

function pending(value = raw(), id = "db-comparison-0") {
  return workflow.classify(value, { id, fadeDuration: 6 });
}

function response(rows, requestId = "named-load-1") {
  return {
    requestId,
    retrievedAt: "2026-07-12T12:00:00+09:00",
    totalRowCount: rows.length,
    rows
  };
}

test("the exact original action grammar classifies all nine comparison leaves", () => {
  const cases = [
    ["2열판", "", "two-column-current"],
    ["2열판", "예상체결", "two-column-expected"],
    ["종목별 비교분석_캔들 그래프", "", "comparison-candle"],
    ["종목별 비교분석_라인 그래프", "", "comparison-line"],
    ["종목별 수익률 비교", "5일", "return-5d"],
    ["종목별 수익률 비교", "1개월", "return-1m"],
    ["종목별 수익률 비교", "3개월", "return-3m"],
    ["종목별 수익률 비교", "6개월", "return-6m"],
    ["종목별 수익률 비교", "12개월", "return-12m"]
  ];
  for (let index = 0; index < cases.length; index += 1) {
    const [graphicType, subtype, actionId] = cases[index];
    const value = pending(raw({
      itemIndex: index,
      groupCode: graphicType === "2열판" ? "지수" : "코스피,코스닥",
      subject: graphicType === "2열판"
        ? "코스피 지수,코스닥 지수"
        : "삼성전자,에이비엘바이오",
      graphicType,
      subtype
    }), `comparison-${index}`);
    assert.ok(value);
    assert.equal(value.actionId, actionId);
  }
});

test("market-lost stock rows are submitted but can only normalize as a failed outcome", () => {
  const value = pending(raw({
    groupCode: "종목",
    subject: "삼성전자,엔비디아",
    graphicType: "2열판"
  }));
  assert.ok(value);
  const normalized = workflow.normalizeResponse(response([{
    itemIndex: 0,
    status: "failed",
    failure: "MISSING_MARKET_IDENTITY"
  }]), "named-load-1", [value]);
  assert.equal(normalized.rows[0].failure, "MISSING_MARKET_IDENTITY");
  assert.equal(workflow.materialize(value, normalized.rows[0]), null);
});

test("a correlated fixed-pair result materializes the explicit comparison selection", () => {
  const value = pending(raw({
    groupCode: "지수",
    subject: "코스피 지수,코스닥 지수",
    graphicType: "2열판"
  }));
  const normalized = workflow.normalizeResponse(response([{
    itemIndex: 0,
    status: "resolved",
    actionId: "two-column-current",
    first: { kind: "market-target", target: "Kospi" },
    second: { kind: "market-target", target: "Kosdaq" }
  }]), "named-load-1", [value]);
  const entry = workflow.materialize(value, normalized.rows[0]);

  assert.equal(entry.operator.source, "legacy-comparison-workflow");
  assert.equal(entry.operator.actionId, "two-column-current");
  assert.equal(entry.selection.subject, "Kospi,Kosdaq");
  assert.equal(entry.builderKey, "s8018");
  assert.equal(entry.enabled, true);
});

test("a correlated exact KRX result materializes candle and preserves disabled state", () => {
  const value = pending(raw({ enabled: false }), "db-comparison-disabled");
  const normalized = workflow.normalizeResponse(response([{
    itemIndex: 0,
    status: "resolved",
    actionId: "comparison-candle",
    first: {
      kind: "krx-stock", market: "kospi", stockName: "삼성전자", stockCode: "005930"
    },
    second: {
      kind: "krx-stock", market: "kosdaq", stockName: "에이비엘바이오", stockCode: "298380"
    }
  }]), "named-load-1", [value]);
  const entry = workflow.materialize(value, normalized.rows[0]);

  assert.equal(entry.builderKey, "s5026");
  assert.equal(entry.operator.pair[0].stockCode, "005930");
  assert.equal(entry.selection.dataCode, "KOSPI:005930|KOSDAQ:298380");
  assert.equal(entry.enabled, false);
});

test("tampered correlation, ordering, action, target, and failure codes are rejected", () => {
  const first = pending(raw(), "first");
  const second = pending(raw({
    itemIndex: 1,
    graphicType: "종목별 비교분석_라인 그래프"
  }), "second");
  const validRows = [
    {
      itemIndex: 0,
      status: "failed",
      failure: "IDENTITY_NOT_FOUND"
    },
    {
      itemIndex: 1,
      status: "failed",
      failure: "IDENTITY_AMBIGUOUS"
    }
  ];
  assert.ok(workflow.normalizeResponse(response(validRows), "named-load-1", [first, second]));
  assert.equal(workflow.normalizeResponse(response(validRows, "stale"), "named-load-1", [first, second]), null);
  assert.equal(workflow.normalizeResponse(response([...validRows].reverse()), "named-load-1", [first, second]), null);
  assert.equal(workflow.normalizeResponse(response([
    { ...validRows[0], failure: "GUESS_MARKET" }, validRows[1]
  ]), "named-load-1", [first, second]), null);

  const wrongAction = response([{
    itemIndex: 0,
    status: "resolved",
    actionId: "comparison-line",
    first: { kind: "krx-stock", market: "kospi", stockName: "삼성전자", stockCode: "005930" },
    second: { kind: "krx-stock", market: "kosdaq", stockName: "에이비엘바이오", stockCode: "298380" }
  }]);
  assert.equal(workflow.normalizeResponse(wrongAction, "named-load-1", [first]), null);
});

test("malformed raw fields and retryable native errors are rejected", () => {
  assert.equal(pending(raw({ pageText: "1/2" })), null);
  assert.equal(pending(raw({ dataCode: "005930" })), null);
  assert.equal(pending(raw({ subject: "삼성전자" })), null);
  assert.equal(pending(raw({ subject: " 삼성전자,기아" })), null);
  assert.equal(pending(raw({ subtype: "20일", graphicType: "종목별 수익률 비교" })), null);

  assert.deepEqual(workflow.normalizeError({
    requestId: "named-load-1",
    code: "DATABASE_UNAVAILABLE",
    message: "현재 DB를 사용할 수 없습니다.",
    retryable: false
  }, "named-load-1"), {
    requestId: "named-load-1",
    code: "DATABASE_UNAVAILABLE",
    message: "현재 DB를 사용할 수 없습니다.",
    retryable: false
  });
  assert.equal(workflow.normalizeError({
    requestId: "named-load-1",
    code: "DATABASE_UNAVAILABLE",
    message: "현재 DB를 사용할 수 없습니다.",
    retryable: true
  }, "named-load-1"), null);
});
