import type {
  GatewayFiatEnvelope,
  GatewayJsonObject,
  GatewayStripePayeeIdentity,
  SignedPermitCustomerSidePaymentProvider,
} from "./gateway.js";

export const STRIPE_PAYMENT_INTENTS_ADAPTER_VERSION: "2.0.0";
export const STRIPE_PAYEE_IDENTITY_PROFILE: "MANDATESHIELD_PAYEE_IDENTITY_V1";
export const STRIPE_PAYMENT_INTENTS_AUDIENCE:
  "https://api.stripe.com/v1/payment_intents";
export const STRIPE_PAYMENT_INTENTS_PERMIT_PROFILE:
  "STRIPE_PAYMENT_INTENTS_V1";
export const STRIPE_PAYMENT_INTENTS_EXECUTION_MODE:
  "SIGNED_EXECUTION_PERMIT_V1";

export type StripeAccountId = `acct_${string}`;
export type StripePaymentMethodId = `pm_${string}`;

export interface StripePaymentIntentProviderInput
  extends GatewayJsonObject {
  payment_method_id: StripePaymentMethodId;
}

export interface StripePaymentIntentEnvelope
  extends GatewayFiatEnvelope {
  payee_identity: GatewayStripePayeeIdentity;
}

export type StripeAdapterFetch = (
  input: URL,
  init: RequestInit,
) => Promise<Response>;

export type StripeLocalTestBaseUrl =
  | `http://localhost${string}`
  | `https://localhost${string}`
  | `http://127.0.0.1${string}`
  | `https://127.0.0.1${string}`
  | `http://[::1]${string}`
  | `https://[::1]${string}`;

interface StripePaymentIntentsAdapterCommonOptions {
  /** Keep this credential only in the customer-controlled execution service. */
  secretKey: string;
  stripeAccountId: StripeAccountId;
  merchantId: string;
  processorAudience?: typeof STRIPE_PAYMENT_INTENTS_AUDIENCE;
  apiVersion?: string;
  timeoutMs?: number;
  /**
   * Maximum reference-free create recovery window. The runtime caps this at
   * 20 hours so Stripe cannot prune the original idempotency key first.
   */
  createRecoveryHorizonMs?: number;
  clock?: () => number | Date | string;
}

export type StripePaymentIntentsAdapterOptions =
  StripePaymentIntentsAdapterCommonOptions &
    (
      | {
          fetch?: StripeAdapterFetch;
          baseUrl?: never;
          testOnlyAllowCustomBaseUrl?: never;
        }
      | {
          /**
           * Explicit localhost-only transport for tests. Non-local endpoints
           * and live keys are rejected by the runtime.
           */
          fetch: StripeAdapterFetch;
          baseUrl: StripeLocalTestBaseUrl;
          testOnlyAllowCustomBaseUrl: true;
        }
    );

export interface StripePaymentIntentsAdapter
  extends SignedPermitCustomerSidePaymentProvider<
    StripePaymentIntentProviderInput,
    StripePaymentIntentEnvelope
  > {
  readonly name: "STRIPE_PAYMENT_INTENTS";
  readonly payeeIdentityProvider: "STRIPE";
  readonly executionMode: typeof STRIPE_PAYMENT_INTENTS_EXECUTION_MODE;
  readonly version: typeof STRIPE_PAYMENT_INTENTS_ADAPTER_VERSION;
  readonly processorAudience: typeof STRIPE_PAYMENT_INTENTS_AUDIENCE;
  readonly merchantId: string;
  readonly stripeAccountId: StripeAccountId;
  readonly createRecoveryHorizonMs: number;
}

/**
 * Creates the server-only Stripe PaymentIntents provider for the
 * MandateShield Gateway.
 *
 * It permits only the official Stripe API in normal operation. A payment
 * attempt requires an exact provider-bound MandateShield permit plus a fresh
 * online single-winner claim. The Stripe credential and PaymentMethod stay in
 * the customer-controlled executor. Ambiguous outcomes remain UNKNOWN.
 */
export function createStripePaymentIntentsAdapter(
  options: StripePaymentIntentsAdapterOptions,
): StripePaymentIntentsAdapter;
