import { IAuthStrategy, AuthResolveOptions, AuthCredentials } from '../protocols/auth-strategy.js';
import { IConnectionReader, IConnectionTokenWriter, DecryptedConnection } from '../protocols/connection-store.js';

/**
 * Abstract base class for OAuth2 refresh-token strategies.
 *
 * Template-method pattern: `resolve()` is concrete; four small hooks inject
 * provider specifics. Validated across two providers (Salesforce, HubSpot)
 * in the extraction-source app before being extracted here — see
 * `docs/gate-1-auth-extraction-findings.md` for the "build first, extract
 * later" evidence.
 *
 * Subclass contract:
 *   - `provider`                — slug matched against `connections.provider`
 *   - `defaultExpiresInSec`     — fallback when refresh response omits `expires_in`
 *   - `tokenEndpoint()`         — URL to POST the refresh grant
 *   - `refreshBodyExtras()`     — provider-specific body params
 *   - `parseRefreshResponse()`  — raw JSON → ParsedRefreshResponse
 *   - `buildCredentials()`      — stored or freshly-refreshed access token +
 *                                 connection + optional raw refresh response
 *                                 → provider credentials
 *
 * Base handles: expiry check w/ 5-min safety window, `forceRefresh` escape
 * hatch, POST form-urlencoded body, OAuth2 error mapping to
 * `ConnectionBrokenError`, refresh-token rotation persistence, fetch +
 * clock injection for tests.
 */

type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
interface OAuth2RefreshStrategyOptions {
    connectionReader: IConnectionReader;
    tokenWriter: IConnectionTokenWriter;
    /** Injectable fetch for tests. Defaults to the global `fetch`. */
    fetch?: FetchLike;
    /** Injectable clock for tests. Defaults to `Date.now`. */
    now?: () => number;
}
interface ParsedRefreshResponse {
    accessToken: string;
    /**
     * New refresh token if the provider rotated it (HubSpot: always, Salesforce:
     * sometimes). Omit when the provider reused the old refresh token.
     */
    refreshToken?: string;
    /** Seconds from now. If omitted, subclass `defaultExpiresInSec` applies. */
    expiresInSec?: number;
}
declare abstract class OAuth2RefreshStrategy implements IAuthStrategy {
    protected abstract readonly provider: string;
    protected abstract readonly defaultExpiresInSec: number;
    protected readonly connectionReader: IConnectionReader;
    protected readonly tokenWriter: IConnectionTokenWriter;
    protected readonly fetchImpl: FetchLike;
    protected readonly now: () => number;
    constructor(opts: OAuth2RefreshStrategyOptions);
    resolve(connectionId: string, opts?: AuthResolveOptions): Promise<AuthCredentials>;
    protected abstract tokenEndpoint(): string;
    protected abstract refreshBodyExtras(): Record<string, string>;
    protected abstract parseRefreshResponse(raw: unknown): ParsedRefreshResponse;
    protected abstract buildCredentials(accessToken: string, connection: DecryptedConnection, refreshRaw?: unknown): AuthCredentials;
    private executeRefresh;
    private isExpiring;
}

export { type FetchLike, OAuth2RefreshStrategy, type OAuth2RefreshStrategyOptions, type ParsedRefreshResponse };
