<?php
/**
 * OAuth backend contract.
 *
 * @package NimblyMail\SMTP
 */

namespace NimblyMail\SMTP\OAuth\Contracts;

defined( 'ABSPATH' ) || exit;

/**
 * Interface OAuthBackend
 *
 * Shared contract for OAuth refresh and revoke implementations. Hosted-proxy
 * (ProxyClient) and direct-to-provider (DirectClient) backends both implement
 * it so mailers and the disconnect path can dispatch by configuration without
 * knowing which transport is in use.
 *
 * Every method returns the same structured response shape so callers can
 * treat both backends identically:
 *
 *     array{ok: bool, status: int, data: array<string, mixed>, error?: string}
 *
 * Where:
 *   - ok      — true on 2xx success (or local-only success for backends without an upstream endpoint).
 *   - status  — HTTP status code (0 on transport error or when no upstream call was made).
 *   - data    — Decoded JSON body or an empty array.
 *   - error   — Optional short machine-readable error tag.
 *
 * @since 1.0.0
 */
interface OAuthBackend {

    /**
     * Whether this backend has the credentials it needs to make signed calls.
     *
     * @since 1.0.0
     *
     * @return bool
     */
    public function is_provisioned(): bool;

    /**
     * Exchange a refresh_token for a fresh access_token.
     *
     * @since 1.0.0
     *
     * @param string $refresh_token The refresh token to exchange.
     *
     * @return array{ok: bool, status: int, data: array<string, mixed>, error?: string}
     */
    public function refresh( string $refresh_token ): array;

    /**
     * Revoke the current authorization.
     *
     * Best-effort: implementations may degrade to a local no-op when the
     * upstream provider has no revocation endpoint (Microsoft v2.0). Callers
     * always clear local tokens after this call regardless of the result.
     *
     * @since 1.0.0
     *
     * @return array{ok: bool, status: int, data: array<string, mixed>, error?: string}
     */
    public function revoke(): array;
}
