/**
 * credential 治理端點測試。
 *
 * 範圍限制（誠實記錄，非本檔缺陷）：`putWorkerSecret` / `deleteWorkerSecret` 呼叫真實
 * Cloudflare API（`fetch` 到 api.cloudflare.com）。測試環境（wrangler.test.toml）刻意不設
 * CF_SECRETS_API_TOKEN/CF_ACCOUNT_ID，所以本檔只覆蓋「不需要真的打 CF API」的路徑：
 *   - D1-only 的 GET /credentials、/credentials/catalog
 *   - DELETE 在 D1 無 row 時 fallback 刪舊 KV（不會走到 deleteWorkerSecret）
 * 真正打 CF Workers Secrets API 成功寫入/刪除的路徑，由部署到 leo21c 帳號後的端到端
 * curl 驗證覆蓋（見 credential-store-migration.md T8/T9 完成記錄）。
 */
import { describe, it, expect, beforeEach } from 'vitest';
import { env, SELF } from 'cloudflare:test';

const API_KEY = 'test-tenant-t89';

async function insertCredentialRow(
  name: string,
  secretRef: string,
  extra: Partial<{ service: string | null; sensitivity: string; last_used_at: number | null }> = {},
): Promise<void> {
  await env.CREDENTIALS_DB
    .prepare(
      `INSERT INTO credentials (api_key, name, service, sensitivity, secret_ref, created_at, last_used_at)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
    )
    .bind(
      API_KEY,
      name,
      extra.service ?? null,
      extra.sensitivity ?? 'standard',
      secretRef,
      Math.floor(Date.now() / 1000),
      extra.last_used_at ?? null,
    )
    .run();
}

async function clearTenantRows(): Promise<void> {
  await env.CREDENTIALS_DB.prepare(`DELETE FROM credentials WHERE api_key = ?`).bind(API_KEY).run();
}

describe('GET /credentials (D1, T9)', () => {
  beforeEach(clearTenantRows);

  it('缺 X-Arcrun-API-Key → 401', async () => {
    const res = await SELF.fetch('https://cypher.test/credentials');
    expect(res.status).toBe(401);
  });

  it('無資料 → 空陣列（非拋錯）', async () => {
    const res = await SELF.fetch('https://cypher.test/credentials', {
      headers: { 'X-Arcrun-API-Key': API_KEY },
    });
    expect(res.status).toBe(200);
    const body = await res.json() as { success: boolean; credentials: unknown[]; total: number };
    expect(body.success).toBe(true);
    expect(body.credentials).toEqual([]);
    expect(body.total).toBe(0);
  });

  it('回傳 metadata，絕不含 secret_ref 或值', async () => {
    await insertCredentialRow('telegram_bot_token', 'CRED_TELEGRAM_BOT_TOKEN_ABCDEF01', { service: 'telegram' });
    const res = await SELF.fetch('https://cypher.test/credentials', {
      headers: { 'X-Arcrun-API-Key': API_KEY },
    });
    const body = await res.json() as { success: boolean; credentials: Array<Record<string, unknown>> };
    expect(body.success).toBe(true);
    expect(body.credentials).toHaveLength(1);
    const row = body.credentials[0];
    expect(row.name).toBe('telegram_bot_token');
    expect(row.service).toBe('telegram');
    expect(row).not.toHaveProperty('secret_ref');
    expect(row).not.toHaveProperty('value');
    expect(JSON.stringify(row)).not.toMatch(/CRED_/);
  });

  it('/credentials/catalog 回同一份資料（Console 相容別名）', async () => {
    await insertCredentialRow('notion_token', 'CRED_NOTION_TOKEN_ABCDEF01');
    const [listRes, catalogRes] = await Promise.all([
      SELF.fetch('https://cypher.test/credentials', { headers: { 'X-Arcrun-API-Key': API_KEY } }),
      SELF.fetch('https://cypher.test/credentials/catalog', { headers: { 'X-Arcrun-API-Key': API_KEY } }),
    ]);
    const [listBody, catalogBody] = await Promise.all([listRes.json(), catalogRes.json()]) as Array<{
      credentials: Array<{ name: string }>;
    }>;
    expect(listBody.credentials.map(r => r.name)).toEqual(catalogBody.credentials.map(r => r.name));
  });
});

describe('DELETE /credentials/:name (T9)', () => {
  beforeEach(clearTenantRows);

  it('D1 無 row（從未回填）→ fallback 刪舊 KV，不誤報找不到', async () => {
    await env.CREDENTIALS_KV.put(
      `${API_KEY}:cred:legacy_only`,
      JSON.stringify({ encrypted: 'x', iv: 'y' }),
    );
    const res = await SELF.fetch('https://cypher.test/credentials/legacy_only', {
      method: 'DELETE',
      headers: { 'X-Arcrun-API-Key': API_KEY },
    });
    const body = await res.json() as { success: boolean; source: string };
    expect(res.status).toBe(200);
    expect(body.success).toBe(true);
    expect(body.source).toBe('legacy-kv');
    const raw = await env.CREDENTIALS_KV.get(`${API_KEY}:cred:legacy_only`);
    expect(raw).toBeNull();
  });
});
