export type ESignProvider = "docusign" | "dropbox_sign"

export type ESignStatus = "signed" | "declined" | "voided"

/** Result of connecting an account (OAuth exchange or API-key validation). */
export interface ESignTokens {
  accessToken: string
  refreshToken: string | null
  /** ISO expiry of the access token, or null (API keys don't expire). */
  expiresAt: string | null
  accountId: string | null
  baseUri: string | null
  accountName: string | null
}

/** Decrypted, ready-to-use credentials for a single connected account. */
export interface ESignCredentials {
  provider: ESignProvider
  accessToken: string
  refreshToken?: string | null
  accountId?: string | null
  baseUri?: string | null
}

export interface SendParams {
  document: Buffer
  documentName: string
  signerEmail: string
  signerName: string
  subject: string
  message: string
  /** Our callback the provider should ping on status changes (DocuSign envelope-level Connect). */
  webhookUrl: string
}

export interface ESignAdapter {
  id: ESignProvider
  label: string
  /** "oauth" → connect via redirect; "apikey" → connect by pasting a key. */
  kind: "oauth" | "apikey"
  /**
   * True when the platform can offer this provider. OAuth providers need the
   * operator's app credentials (client id/secret); API-key providers are always
   * available because the landlord brings their own key.
   */
  available(): boolean

  // ── OAuth providers (DocuSign) ────────────────────────────────────────────
  getAuthUrl(state: string): string
  exchangeCode(code: string): Promise<ESignTokens>
  refresh(refreshToken: string): Promise<ESignTokens>

  // ── API-key providers (Dropbox Sign) ──────────────────────────────────────
  /** Validate a pasted API key and return a token set to store. */
  connectApiKey(apiKey: string): Promise<ESignTokens>

  // ── Common ────────────────────────────────────────────────────────────────
  /** Send a document for signature; returns the provider's envelope/request id. */
  send(creds: ESignCredentials, params: SendParams): Promise<{ externalId: string }>
  /** Extract the external id from an inbound (still UNVERIFIED) webhook body, for owner lookup. */
  peekExternalId(body: string): string | null
  /**
   * Authenticate an inbound webhook and return the authoritative status.
   * DocuSign pull-verifies by fetching the envelope with the owner's token;
   * Dropbox Sign HMAC-verifies the body with the account API key. Returns null
   * if the event isn't authentic or isn't a terminal status we track.
   */
  verifyAndGetStatus(
    creds: ESignCredentials,
    externalId: string,
    body: string,
    headers: Headers
  ): Promise<ESignStatus | null>
  /** Download the completed/executed document, or null if unavailable. */
  getSignedDocument(creds: ESignCredentials, externalId: string): Promise<Buffer | null>
}

/** The OAuth callback URL for a provider (must match what's registered in the provider app). */
export function esignRedirectUri(provider: ESignProvider): string {
  const base = (process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000").replace(/\/+$/, "")
  return `${base}/api/esign/${provider}/callback`
}
