/**
 * 三型分支零件「真的接上引擎」的實測（SDD workflow-discovery 3.11）
 *
 * 為什麼要另立這一支（總管 08-01 抽驗要求，正確的要求）：
 *   conditional-edges.test.ts 是用 Input 節點**手餵分支形狀**測引擎走邊邏輯，
 *   那證明的是「引擎依標籤選邊」，**沒有證明「真零件吐出來的標籤真的對得上」**。
 *   leo 特別點名 switch／try_catch，且 `ON_CASE`／`ON_CATCH` grep=0
 *   ⇒ 必須排除「機制通用所以理論上支援」這種推論。
 *
 * 本檔的 given 全部是**真 WASM 零件的實跑輸出**（wasmtime 執行 .component-builds/*.wasm
 * 抓回來的原文，非杜撰），再送進引擎驗證走對邊。
 *
 * 真零件實跑指令（可復驗）：
 *   cd .component-builds
 *   echo '{"condition":"status == active","input":{"status":"active"}}' | wasmtime if_control/component.wasm
 *   echo '{"value":"pending","cases":[...],"default_branch":"branch_default"}' | wasmtime switch/component.wasm
 *   echo '{"result":null,"error":"boom"}' | wasmtime try_catch/component.wasm
 */
import { SELF } from 'cloudflare:test';
import { describe, it, expect } from 'vitest';

async function run(graph: unknown) {
  const res = await SELF.fetch('http://localhost/execute', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ graph, context: {} }),
  });
  const body = (await res.json()) as {
    success: boolean;
    trace?: Array<{ nodeId: string }>;
  };
  return { body, visited: (body.trace ?? []).map(t => t.nodeId) };
}

/** 真零件輸出 → 當作上游節點的 output 餵進圖 */
function graphWith(realOutput: unknown, edges: Array<Record<string, unknown>>, extraNodes: string[]) {
  return {
    id: 'real-branch',
    name: '真零件輸出走邊',
    nodes: [
      { id: 'ctrl', type: 'Input', data: realOutput },
      ...extraNodes.map(id => ({
        id, type: 'Component', componentId: 'comp_uppercase', data: { text: id },
      })),
    ],
    edges,
  };
}

describe('if_control 真輸出 → 引擎走對邊', () => {
  // 真跑：echo '{"condition":"status == active","input":{"status":"active"}}' | wasmtime if_control/component.wasm
  const REAL_TRUE = { data: { branch: 'true', result: true }, success: true };
  // 真跑：input.status = "inactive"
  const REAL_FALSE = { data: { branch: 'false', result: false }, success: true };

  const edges = [
    { from: 'ctrl', to: 'yes', type: 'ON_TRUE' },
    { from: 'ctrl', to: 'no', type: 'ON_FALSE' },
  ];

  it('條件成立（真輸出 branch="true"）→ 走 ON_TRUE', async () => {
    const { body, visited } = await run(graphWith(REAL_TRUE, edges, ['yes', 'no']));
    expect(body.success).toBe(true);
    expect(visited).toContain('yes');
    expect(visited).not.toContain('no');
  });

  it('條件不成立（真輸出 branch="false"）→ 走 ON_FALSE', async () => {
    const { visited } = await run(graphWith(REAL_FALSE, edges, ['yes', 'no']));
    expect(visited).toContain('no');
    expect(visited).not.toContain('yes');
  });
});

describe('switch 真輸出 → 引擎走對邊（多路＋default，leo：「switch 更嚴重」）', () => {
  // 真跑（三個 case + default_branch）：
  //   value="active"  → {"data":{"branch":"branch_active"},"success":true}
  //   value="pending" → {"data":{"branch":"branch_pending"},"success":true}
  //   value="zzz"     → {"data":{"branch":"branch_default"},"success":true}
  const REAL_CASE1 = { data: { branch: 'branch_active' }, success: true };
  const REAL_CASE3 = { data: { branch: 'branch_pending' }, success: true };
  const REAL_DEFAULT = { data: { branch: 'branch_default' }, success: true };

  const targets = ['p_active', 'p_inactive', 'p_pending', 'p_default'];
  const edges = [
    { from: 'ctrl', to: 'p_active', type: 'ON_BRANCH', branch: 'branch_active' },
    { from: 'ctrl', to: 'p_inactive', type: 'ON_BRANCH', branch: 'branch_inactive' },
    { from: 'ctrl', to: 'p_pending', type: 'ON_BRANCH', branch: 'branch_pending' },
    { from: 'ctrl', to: 'p_default', type: 'ON_BRANCH', branch: 'branch_default' },
  ];

  it('第 1 條 case（真輸出 branch_active）→ 只走 p_active', async () => {
    const { body, visited } = await run(graphWith(REAL_CASE1, edges, targets));
    expect(body.success).toBe(true);
    expect(visited).toContain('p_active');
    expect(visited).not.toContain('p_inactive');
    expect(visited).not.toContain('p_pending');
    expect(visited).not.toContain('p_default');
  });

  it('第 3 條 case（真輸出 branch_pending）→ 只走 p_pending（證明第 N 條路走得對）', async () => {
    const { visited } = await run(graphWith(REAL_CASE3, edges, targets));
    expect(visited).toContain('p_pending');
    expect(visited).not.toContain('p_active');
    expect(visited).not.toContain('p_inactive');
    expect(visited).not.toContain('p_default');
  });

  it('無匹配（真輸出 branch_default）→ 只走 p_default', async () => {
    const { visited } = await run(graphWith(REAL_DEFAULT, edges, targets));
    expect(visited).toContain('p_default');
    expect(visited).not.toContain('p_active');
    expect(visited).not.toContain('p_pending');
  });
});

describe('try_catch 真輸出 → 引擎走對邊（ok／catch 兩路都驗）', () => {
  // 真跑：echo '{"result":{"value":42},"error":""}' | wasmtime try_catch/component.wasm
  const REAL_TRY = { data: { branch: 'try', result: { value: 42 } }, success: true };
  // 真跑：echo '{"result":null,"error":"boom"}' | wasmtime try_catch/component.wasm
  const REAL_CATCH = { data: { branch: 'catch', error: 'boom' }, success: true };

  const edges = [
    { from: 'ctrl', to: 'normal', type: 'ON_BRANCH', branch: 'try' },
    { from: 'ctrl', to: 'rescue', type: 'ON_BRANCH', branch: 'catch' },
  ];

  it('成功（真輸出 branch="try"）→ 走 normal，不走 rescue', async () => {
    const { body, visited } = await run(graphWith(REAL_TRY, edges, ['normal', 'rescue']));
    expect(body.success).toBe(true);
    expect(visited).toContain('normal');
    expect(visited).not.toContain('rescue');
  });

  it('失敗（真輸出 branch="catch"）→ 走 rescue，不走 normal', async () => {
    const { visited } = await run(graphWith(REAL_CATCH, edges, ['normal', 'rescue']));
    expect(visited).toContain('rescue');
    expect(visited).not.toContain('normal');
  });

  it('try_catch 的 catch 路承接了「上游失敗」——不必寫 code try 一遍', async () => {
    // 這是 leo 點名 try_catch 的原因：schema 用文字寫「走 catch 分支」但機器層沒有那條路。
    // 現在有了：catch 標籤 → ON_BRANCH branch="catch" → 補救節點。
    const { visited } = await run(graphWith(REAL_CATCH, edges, ['normal', 'rescue']));
    expect(visited).toContain('rescue');
  });
});
