/**
 * GET /kbdb/map ＋ /kbdb/map/:library proxy 測試（library-map SDD M5/R4，console 首頁藏書地圖資料源）
 *
 * 驗證 IO 接線（聚合真身在 KBDB 基本盤 kbdb/src/routes/map.ts，M2 已測；這裡只測轉發）：
 *   1. 租戶閘：無 X-Arcrun-API-Key → 401 不碰 KBDB（與本 proxy 其他端點同閘）
 *   2. 轉發：/kbdb/map → base /map；/kbdb/map/:library → base /map/:library（庫名 URL-encode）
 *   3. owner_id **不強制注入、只選擇性透傳**（與 MCP kbdb_get_map 同義）——現行 backfill 的
 *      map block owner_id=NULL，強制注入租戶會讓首頁永遠假空狀態
 *   4. 空陣列原樣透傳（前端誠實空狀態的資料依據）；404／KBDB 不可達 → 誠實回報不假裝
 *
 * KBDB 打 fetchMock 假 host（wrangler.test.toml KBDB_BASE_URL=https://kbdb.test）＋
 * disableNetConnect——測試絕不外連。
 */
import { SELF, fetchMock } from 'cloudflare:test';
import { beforeAll, afterEach, describe, it, expect } from 'vitest';

const KEY = { 'X-Arcrun-API-Key': 'leo' };

beforeAll(() => {
  fetchMock.activate();
  fetchMock.disableNetConnect();
});
afterEach(() => fetchMock.assertNoPendingInterceptors());

describe('GET /kbdb/map — 租戶閘', () => {
  it('無 X-Arcrun-API-Key → 401，不碰 KBDB', async () => {
    const res = await SELF.fetch('http://localhost/kbdb/map');
    expect(res.status).toBe(401);
  });
  it('/kbdb/map/:library 同閘 → 401', async () => {
    const res = await SELF.fetch('http://localhost/kbdb/map/kb');
    expect(res.status).toBe(401);
  });
});

describe('GET /kbdb/map — 全館地圖轉發', () => {
  it('轉發 base /map、回應原樣透傳（不注入 owner_id）', async () => {
    const payload = {
      success: true,
      libraries: [
        { library: 'kb', narrative: 'leo 的知識庫主庫', top_entities: ['00-INDEX'], triplet_count: 111, updated_at: 1784451880 },
      ],
      count: 1,
    };
    fetchMock
      .get('https://kbdb.test')
      .intercept({ path: '/map', method: 'GET' })
      .reply(200, payload);
    const res = await SELF.fetch('http://localhost/kbdb/map', { headers: KEY });
    expect(res.status).toBe(200);
    const data = (await res.json()) as typeof payload;
    expect(data.count).toBe(1);
    expect(data.libraries[0].library).toBe('kb');
    expect(data.libraries[0].triplet_count).toBe(111);
  });

  it('空陣列原樣透傳（前端據此顯示誠實空狀態，指引 recompute backfill）', async () => {
    fetchMock
      .get('https://kbdb.test')
      .intercept({ path: '/map', method: 'GET' })
      .reply(200, { success: true, libraries: [], count: 0 });
    const res = await SELF.fetch('http://localhost/kbdb/map', { headers: KEY });
    expect(res.status).toBe(200);
    const data = (await res.json()) as { libraries: unknown[]; count: number };
    expect(data.libraries).toEqual([]);
    expect(data.count).toBe(0);
  });

  it('caller 帶 owner_id → 透傳給 base（選擇性，非強制注入）', async () => {
    fetchMock
      .get('https://kbdb.test')
      .intercept({ path: '/map', query: { owner_id: 'someone' }, method: 'GET' })
      .reply(200, { success: true, libraries: [], count: 0 });
    const res = await SELF.fetch('http://localhost/kbdb/map?owner_id=someone', { headers: KEY });
    expect(res.status).toBe(200);
  });
});

describe('GET /kbdb/map/:library — 單庫詳圖轉發', () => {
  it('轉發 base /map/:library、詳圖（degree/bridges/commit_hash）原樣透傳', async () => {
    const map = {
      record_id: 'e_1',
      library: 'kb',
      narrative: 'leo 的知識庫主庫',
      top_entities: [{ name: '00-INDEX', degree: 29 }],
      relation_profile: [{ predicate: '連結至', count: 48 }],
      bridges: [{ entity: 'Gitea', libraries: ['kb', 'notes'] }],
      triplet_count: 111,
      commit_hash: 'abc1234def',
      status: 'active',
      updated_at: 1784451880,
    };
    fetchMock
      .get('https://kbdb.test')
      .intercept({ path: '/map/kb', method: 'GET' })
      .reply(200, { success: true, map });
    const res = await SELF.fetch('http://localhost/kbdb/map/kb', { headers: KEY });
    expect(res.status).toBe(200);
    const data = (await res.json()) as { map: typeof map };
    expect(data.map.top_entities[0].degree).toBe(29);
    expect(data.map.bridges[0].libraries).toEqual(['kb', 'notes']);
  });

  it('庫名 URL-encode 轉發（中文庫名不炸）', async () => {
    fetchMock
      .get('https://kbdb.test')
      .intercept({ path: `/map/${encodeURIComponent('筆記庫')}`, method: 'GET' })
      .reply(200, { success: true, map: { library: '筆記庫' } });
    const res = await SELF.fetch(`http://localhost/kbdb/map/${encodeURIComponent('筆記庫')}`, { headers: KEY });
    expect(res.status).toBe(200);
  });

  it('base 404（庫沒地圖）→ 原樣透傳 404，不假裝有資料', async () => {
    fetchMock
      .get('https://kbdb.test')
      .intercept({ path: '/map/nope', method: 'GET' })
      .reply(404, { success: false, error: 'not found' });
    const res = await SELF.fetch('http://localhost/kbdb/map/nope', { headers: KEY });
    expect(res.status).toBe(404);
    const data = (await res.json()) as { success: boolean };
    expect(data.success).toBe(false);
  });
});

describe('KBDB 不可達 → 誠實 502（前端顯示地圖不可達，不擋搜尋）', () => {
  it('/kbdb/map fetch 炸 → 502 + success:false', async () => {
    // 不掛 interceptor：disableNetConnect 下 fetch 直接 throw → route catch → 502
    const res = await SELF.fetch('http://localhost/kbdb/map', { headers: KEY });
    expect(res.status).toBe(502);
    const data = (await res.json()) as { success: boolean; error: string };
    expect(data.success).toBe(false);
    expect(data.error).toContain('KBDB 不可達');
  });
});
