/**
 * 同步查詢 trigger（sync query）測試 — webhooks-named.ts 的 /query 與 /q/* 端點。
 *
 * 驗證重點（對應交辦 Part 1）：
 *   1. 同步回「最終節點輸出」本身（非 202、非 {success,data,...} 信封）— GET(query string) 與 POST(body) 皆是。
 *   2. namespace 走 path 的公開形態（/q/:ns/:name、POST /webhooks/named/:ns/:name/query）。
 *   3. 節點失敗 → 誠實回錯誤 + trace（500），非假綠。
 *   4. 認證：缺 X-Arcrun-API-Key → 401；workflow 不存在 → 404。
 *
 * 用內建零件（comp_uppercase / comp_passthrough，純記憶體、無外部 fetch）當「極簡 workflow」，
 * 因此本測試就是「Part 1 同步 trigger 機制本身可用」的證據（確實同步回值而非 202）。
 */
import { describe, it, expect, beforeAll } from 'vitest';
import { env, SELF } from 'cloudflare:test';

const API_KEY = 'test-tenant-query';

function kvKey(name: string, apiKey = API_KEY): string {
  return `${apiKey}:wf:${name}`;
}

// 極簡 workflow：單一 comp_uppercase 節點。caller input（text）→ 大寫 → 當最終輸出回。
// 無 Input/Output 節點：最終節點輸出即 comp_uppercase 的回傳，乾淨可斷言。
const UPPER_WF = {
  name: 'q_upper',
  graph: {
    id: 'q_upper',
    name: 'sync query upper',
    nodes: [{ id: 'upper', type: 'Component', componentId: 'comp_uppercase' }],
    edges: [],
  },
  description: '同步查詢：把 text 轉大寫回傳（測試用）',
  created_at: new Date().toISOString(),
};

// 會失敗的 workflow：引用不存在的零件 → 節點執行失敗。
const FAIL_WF = {
  name: 'q_fail',
  graph: {
    id: 'q_fail',
    name: 'sync query fail',
    nodes: [{ id: 'boom', type: 'Component', componentId: 'comp_does_not_exist' }],
    edges: [],
  },
  description: '同步查詢：故意引用不存在零件（測試失敗路徑）',
  created_at: new Date().toISOString(),
};

beforeAll(async () => {
  await env.WEBHOOKS.put(kvKey(UPPER_WF.name), JSON.stringify(UPPER_WF));
  await env.WEBHOOKS.put(kvKey(FAIL_WF.name), JSON.stringify(FAIL_WF));
});

describe('同步查詢 trigger — 成功回最終節點輸出（非 202、非信封）', () => {
  it('POST /webhooks/named/:name/query（header 認證，body input）同步回輸出', async () => {
    const res = await SELF.fetch('http://localhost/webhooks/named/q_upper/query', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'X-Arcrun-API-Key': API_KEY },
      body: JSON.stringify({ text: 'hello' }),
    });
    expect(res.status).toBe(200); // 關鍵：非 202
    const data = await res.json() as Record<string, unknown>;
    // 回的是「最終節點輸出本身」：頂層直接有 text=HELLO，而非包在 { data: ... } 信封裡
    expect(data.text).toBe('HELLO');
    expect(data).not.toHaveProperty('duration_ms'); // 信封欄位不該出現在 body
    // duration 走 header，不污染輸出
    expect(res.headers.get('X-Arcrun-Duration-Ms')).not.toBeNull();
  });

  it('GET /webhooks/named/:name/query（header 認證，query string input）同步回輸出', async () => {
    const res = await SELF.fetch('http://localhost/webhooks/named/q_upper/query?text=world', {
      headers: { 'X-Arcrun-API-Key': API_KEY },
    });
    expect(res.status).toBe(200);
    const data = await res.json() as Record<string, unknown>;
    expect(data.text).toBe('WORLD');
  });

  it('GET /q/:ns/:name（namespace 走 path，query string input）同步回輸出', async () => {
    const res = await SELF.fetch(`http://localhost/q/${API_KEY}/q_upper?text=abc`);
    expect(res.status).toBe(200);
    const data = await res.json() as Record<string, unknown>;
    expect(data.text).toBe('ABC');
  });

  it('POST /webhooks/named/:ns/:name/query（namespace 走 path，body input）同步回輸出', async () => {
    const res = await SELF.fetch(`http://localhost/webhooks/named/${API_KEY}/q_upper/query`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ text: 'path' }),
    });
    expect(res.status).toBe(200);
    const data = await res.json() as Record<string, unknown>;
    expect(data.text).toBe('PATH');
  });
});

describe('同步查詢 trigger — 誠實錯誤（不假綠）', () => {
  it('節點失敗 → 500 + error + trace（非把錯誤當輸出）', async () => {
    const res = await SELF.fetch('http://localhost/webhooks/named/q_fail/query', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'X-Arcrun-API-Key': API_KEY },
      body: JSON.stringify({}),
    });
    expect(res.status).toBe(500);
    const data = await res.json() as { success: boolean; error: string; trace: unknown };
    expect(data.success).toBe(false);
    expect(typeof data.error).toBe('string');
    expect(data.error.length).toBeGreaterThan(0);
    expect(data.trace).toBeDefined();
  });
});

describe('同步查詢 trigger — 認證與存在性', () => {
  it('缺 X-Arcrun-API-Key（header 形態）→ 401', async () => {
    const res = await SELF.fetch('http://localhost/webhooks/named/q_upper/query', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ text: 'x' }),
    });
    expect(res.status).toBe(401);
  });

  it('workflow 不存在 → 404', async () => {
    const res = await SELF.fetch('http://localhost/webhooks/named/no_such_wf/query', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'X-Arcrun-API-Key': API_KEY },
      body: JSON.stringify({}),
    });
    expect(res.status).toBe(404);
  });
});
