/**
 * A2A OIDC e2e 共有ヘルパ。
 *
 * 実 oidc-provider を相手にした e2e（oidc-e2e.test.ts / a2a-card-e2e.test.ts）で
 * 共通して必要になる「cookie を保持する最小 HTTP クライアント」と base64url ヘルパ。
 * テスト専用ユーティリティ（本番コードからは import しない）。
 */

export function b64url(b: Buffer): string {
  return b.toString('base64url');
}

/**
 * fetch は cookie を保持しないので、最小限の cookie jar を持つ HTTP クライアントを作る。
 * oidc-provider は `_interaction` / `_session` / `_interaction_resume`（+ `.legacy` / `.sig`）等を
 * set-cookie で返すので、name=value を蓄積して後続リクエストに Cookie ヘッダで返送する。
 */
export class Client {
  private jar = new Map<string, string>();

  private storeCookies(res: Response): void {
    const setCookies = res.headers.getSetCookie?.() ?? [];
    for (const sc of setCookies) {
      const first = sc.split(';')[0];
      const eq = first.indexOf('=');
      if (eq < 0) continue;
      const name = first.slice(0, eq).trim();
      const value = first.slice(eq + 1).trim();
      // 値が空 = サーバが cookie を消去している → jar からも削除
      if (value === '') this.jar.delete(name);
      else this.jar.set(name, value);
    }
  }

  private cookieHeader(): string {
    return [...this.jar.entries()].map(([k, v]) => `${k}=${v}`).join('; ');
  }

  async get(url: string, extraHeaders: Record<string, string> = {}): Promise<Response> {
    const headers: Record<string, string> = { ...extraHeaders };
    if (this.jar.size) headers.cookie = this.cookieHeader();
    const res = await fetch(url, {
      redirect: 'manual',
      headers,
    });
    this.storeCookies(res);
    return res;
  }

  async postForm(url: string, body: Record<string, string>): Promise<Response> {
    const headers: Record<string, string> = {
      'content-type': 'application/x-www-form-urlencoded',
    };
    if (this.jar.size) headers.cookie = this.cookieHeader();
    const res = await fetch(url, {
      method: 'POST',
      redirect: 'manual',
      headers,
      body: new URLSearchParams(body).toString(),
    });
    this.storeCookies(res);
    return res;
  }
}
