import type { VaultAuthResponse, VaultSecretResponse, VaultRenewResponse } from "./vault.types.js";

const DEFAULT_TIMEOUT_MS = 5000;

export class VaultClient {
  constructor(
    private readonly address: string,
    private readonly timeoutMs = DEFAULT_TIMEOUT_MS
  ) {}

  async login(roleId: string, secretId: string): Promise<VaultAuthResponse> {
    return this.request<VaultAuthResponse>("/v1/auth/approle/login", {
      method: "POST",
      body: JSON.stringify({ role_id: roleId, secret_id: secretId }),
    });
  }

  async readSecret(path: string, token: string): Promise<VaultSecretResponse> {
    return this.request<VaultSecretResponse>(`/v1/${path}`, {
      method: "GET",
      headers: { "X-Vault-Token": token },
    });
  }

  async renewToken(token: string): Promise<VaultRenewResponse> {
    return this.request<VaultRenewResponse>("/v1/auth/token/renew-self", {
      method: "POST",
      headers: { "X-Vault-Token": token },
    });
  }

  private async request<T>(path: string, init: RequestInit): Promise<T> {
    const url = `${this.address}${path}`;
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), this.timeoutMs);

    try {
      const response = await fetch(url, {
        ...init,
        signal: controller.signal,
        headers: {
          "Content-Type": "application/json",
          ...init.headers,
        },
      });

      if (!response.ok) {
        const body = await response.text().catch(() => "");
        throw new Error(`Vault ${init.method} ${path} failed: ${response.status} ${body}`);
      }

      return (await response.json()) as T;
    } finally {
      clearTimeout(timeout);
    }
  }
}
