import { request } from '../request.js';
import { AgentIdPError } from '../errors.js';
import type { IntrospectResponse } from '../types.js';

/**
 * Client for OAuth 2.0 token operations (introspect and revoke).
 * Token issuance is handled separately by TokenManager.
 */
export class TokenClient {
  constructor(
    private readonly baseUrl: string,
    private readonly getToken: () => Promise<string>,
  ) {}

  /**
   * Introspect a token to check whether it is currently active.
   * Always returns 200 — check the `active` field to determine validity.
   * Requires a Bearer token with `tokens:read` scope.
   */
  async introspectToken(tokenToCheck: string): Promise<IntrospectResponse> {
    const token = await this.getToken();
    const body = new URLSearchParams({ token: tokenToCheck });

    let response: Response;
    try {
      response = await fetch(new URL('/api/v1/token/introspect', this.baseUrl).toString(), {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: body.toString(),
      });
    } catch (err) {
      throw new AgentIdPError(
        'NETWORK_ERROR',
        `Network error: ${err instanceof Error ? err.message : String(err)}`,
        0,
      );
    }

    const data: unknown = await response.json();
    if (!response.ok) {
      throw AgentIdPError.fromApiError(data, response.status);
    }
    return data as IntrospectResponse;
  }

  /**
   * Revoke a token immediately. Idempotent — revoking an already-revoked
   * or expired token is not an error (RFC 7009).
   */
  async revokeToken(tokenToRevoke: string): Promise<void> {
    const token = await this.getToken();
    const body = new URLSearchParams({ token: tokenToRevoke });

    let response: Response;
    try {
      response = await fetch(new URL('/api/v1/token/revoke', this.baseUrl).toString(), {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: body.toString(),
      });
    } catch (err) {
      throw new AgentIdPError(
        'NETWORK_ERROR',
        `Network error: ${err instanceof Error ? err.message : String(err)}`,
        0,
      );
    }

    if (!response.ok) {
      const data: unknown = await response.json();
      throw AgentIdPError.fromApiError(data, response.status);
    }
  }
}
