import { SupabaseClient, SupabaseClientOptions } from "@supabase/supabase-js";
import { JSONWebKeySet } from "jose";

//#region src/types.d.ts
/**
 * Authentication mode that determines what credentials a request must provide.
 *
 * - `"none"` — No credentials required. Every request is accepted.
 * - `"publishable"` — Requires a valid publishable key in the `apikey` header. Matches only the `default` key.
 * - `"secret"` — Requires a valid secret key in the `apikey` header (timing-safe comparison). Matches only the `default` key.
 * - `"user"` — Requires a valid JWT in the `Authorization: Bearer <token>` header.
 *
 * Bare `"publishable"` / `"secret"` resolve the `default` key from
 * `SUPABASE_PUBLISHABLE_KEYS` / `SUPABASE_SECRET_KEYS`. To target another key or
 * accept any key, see {@link AuthModeWithKey}.
 *
 * @example Single mode
 * ```ts
 * // Single mode
 * withSupabase({ auth: 'user' }, handler)
 *
 * // Multiple modes — the first match wins.
 * // A mode is tried only when its credential is present; a JWT that is
 * // present but fails verification rejects immediately rather than falling
 * // through to the next mode.
 * withSupabase({ auth: ['user', 'publishable'] }, handler)
 * ```
 *
 * @category Types
 */
type AuthMode = 'none' | 'publishable' | 'secret' | 'user';
/**
 * @deprecated Use {@link AuthMode} instead. Will be removed in a future major release.
 * @category Types
 */
type Allow = AuthMode;
/**
 * Extended auth mode that supports targeting a specific named key.
 *
 * Use the colon syntax (`"publishable:web_app"`) to require a specific named key
 * from the `SUPABASE_PUBLISHABLE_KEYS` or `SUPABASE_SECRET_KEYS` JSON object.
 * Use `"publishable:*"` or `"secret:*"` to accept any key in the set. The bare
 * form without a colon (`"publishable"` / `"secret"`) matches only the `default` key.
 *
 * @example Named key
 * ```ts
 * // Accept only the "mobile" publishable key
 * withSupabase({ auth: 'publishable:mobile' }, handler)
 *
 * // Accept any secret key
 * withSupabase({ auth: 'secret:*' }, handler)
 *
 * // Mix named keys with other modes
 * withSupabase({ auth: ['user', 'publishable:web_app'] }, handler)
 * ```
 *
 * @category Types
 */
type AuthModeWithKey = AuthMode | `publishable:${string}` | `secret:${string}`;
/**
 * @deprecated Use {@link AuthModeWithKey} instead. Will be removed in a future major release.
 * @category Types
 */
type AllowWithKey = AuthModeWithKey;
/**
 * Resolved Supabase environment configuration.
 *
 * Holds the project URL, API keys, and JWKS needed by every other primitive.
 * Typically resolved automatically from environment variables by {@link core.resolveEnv},
 * but can be passed explicitly via the `env` option.
 *
 * @see {@link core.resolveEnv} for how each field maps to environment variables.
 * @category Types
 */
interface SupabaseEnv {
  /** Supabase project URL (e.g. `"https://<ref>.supabase.co"`). Sourced from `SUPABASE_URL`. */
  url: string;
  /**
   * Named publishable keys. Sourced from `SUPABASE_PUBLISHABLE_KEYS` (JSON object)
   * or `SUPABASE_PUBLISHABLE_KEY` (single key, stored as `{ default: "<value>" }`).
   */
  publishableKeys: Record<string, string>;
  /**
   * Named secret keys. Sourced from `SUPABASE_SECRET_KEYS` (JSON object)
   * or `SUPABASE_SECRET_KEY` (single key, stored as `{ default: "<value>" }`).
   */
  secretKeys: Record<string, string>;
  /**
   * JWKS source used for JWT verification.
   *
   * Sourced from one of (in priority order):
   * - `SUPABASE_JWKS` — inline JSON. Resolves to a `JSONWebKeySet`.
   * - `SUPABASE_JWKS_URL` — remote endpoint. Resolves to a `URL`; keys
   *   are fetched lazily and cached in memory (cooldown / max-age handled by
   *   `jose`). `https://` is always accepted; plain `http://` is accepted
   *   only for loopback hosts (`localhost`, `127.0.0.0/8`, `::1`) to support
   *   the Supabase CLI. Any other `http://` URL is rejected to prevent MITM
   *   swap-in of a forged signing key.
   *
   * `null` when no JWKS is configured (JWT verification will be unavailable).
   * Each env var is authoritative when set: a malformed value resolves to
   * `null` rather than falling through to the other variable.
   */
  jwks: JSONWebKeySet | URL | null;
}
/**
 * Raw credentials extracted from an incoming HTTP request.
 *
 * Produced by {@link core.extractCredentials} from the `Authorization` and `apikey` headers.
 *
 * @see {@link core.extractCredentials}
 * @category Types
 */
interface Credentials {
  /** Bearer token from the `Authorization: Bearer <token>` header, or `null` if absent. */
  token: string | null;
  /** API key from the `apikey` header, or `null` if absent. */
  apikey: string | null;
}
/**
 * Result of credential verification.
 *
 * Contains the resolved auth mode, the verified token (for `"user"` mode),
 * decoded JWT claims, and the matched key name (for `"publishable"` / `"secret"` modes).
 *
 * @see {@link core.verifyCredentials}
 * @see {@link core.verifyAuth}
 * @category Types
 */
interface AuthResult {
  /** The auth mode that was successfully matched. */
  authMode: AuthMode;
  /** The verified JWT, or `null` for non-user auth modes. */
  token: string | null;
  /** Normalized user identity derived from the JWT, or `null` when no JWT is present. */
  userClaims: UserClaims | null;
  /** Raw JWT payload, or `null` when no JWT is present. */
  jwtClaims: JWTClaims | null;
  /** Name of the matched key (e.g. `"default"`, `"mobile"`), or `null` for `"user"` / `"none"` modes. */
  keyName?: string | null;
}
/**
 * Standard JWT claims as defined by RFC 7519, extended with Supabase-specific fields.
 *
 * This is the raw JWT payload — use {@link UserClaims} for a normalized, camelCase view.
 *
 * @see https://datatracker.ietf.org/doc/html/rfc7519#section-4.1
 * @category Types
 */
interface JWTClaims {
  /** Subject — the user's unique ID. */
  sub: string;
  /** Issuer — typically your Supabase project URL. */
  iss?: string;
  /** Audience — who the token is intended for. */
  aud?: string | string[];
  /** Expiration time (seconds since epoch). */
  exp?: number;
  /** Issued at (seconds since epoch). */
  iat?: number;
  /** Supabase role (e.g. `"authenticated"`, `"anon"`). */
  role?: string;
  /** User's email address from Supabase Auth. */
  email?: string;
  /** Application-level metadata set via Supabase Auth admin APIs. */
  app_metadata?: Record<string, unknown>;
  /** User-editable metadata set via Supabase Auth. */
  user_metadata?: Record<string, unknown>;
  /** Additional custom claims. */
  [key: string]: unknown;
}
/**
 * Normalized, camelCase view of the authenticated user's identity.
 *
 * Derived from {@link JWTClaims}. For the full Supabase `User` object
 * (including email confirmation status, providers, etc.), call
 * `supabase.auth.getUser()` using the context client.
 * @category Types
 */
interface UserClaims {
  /** User's unique ID (same as `JWTClaims.sub`). */
  id: string;
  /** Supabase role (e.g. `"authenticated"`). */
  role?: string;
  /** User's email address. */
  email?: string;
  /** Application-level metadata (e.g. roles, permissions). */
  appMetadata?: Record<string, unknown>;
  /** User-editable profile metadata (e.g. display name, avatar). */
  userMetadata?: Record<string, unknown>;
}
/**
 * Configuration for {@link withSupabase} and {@link createSupabaseContext}.
 *
 * Controls which auth modes are accepted, environment overrides, and CORS behavior.
 *
 * @example Basic usage
 * ```ts
 * // Require authenticated users, auto-CORS enabled (default)
 * const config: WithSupabaseConfig = { auth: 'user' }
 *
 * // Accept users or service-to-service calls, custom CORS headers
 * const config: WithSupabaseConfig = {
 *   auth: ['user', 'secret'],
 *   cors: { 'Access-Control-Allow-Origin': 'https://myapp.com' },
 * }
 *
 * // No auth required, CORS disabled
 * const config: WithSupabaseConfig = { auth: 'none', cors: 'disabled' }
 * ```
 *
 * @category Types
 */
interface WithSupabaseConfig {
  /**
   * Auth mode(s) to accept. Modes are tried in order — the first match wins.
   * A mode falls through only when its credential is absent; a present-but-invalid
   * JWT short-circuits the chain with `InvalidCredentialsError`.
   *
   * @defaultValue `"user"`
   */
  auth?: AuthModeWithKey | AuthModeWithKey[];
  /**
   * @deprecated Use {@link WithSupabaseConfig.auth} instead. The `allow` option
   * is kept for backward compatibility and will be removed in a future major release.
   * When both `auth` and `allow` are provided, `auth` takes precedence.
   */
  allow?: AuthModeWithKey | AuthModeWithKey[];
  /**
   * Override auto-detected environment variables. Useful for testing
   * or when running in environments without standard env var support.
   */
  env?: Partial<SupabaseEnv>;
  /**
   * CORS configuration for the `withSupabase` wrapper.
   *
   * - `'default'` — uses `@supabase/supabase-js` default CORS headers.
   * - `'disabled'` — disables CORS handling entirely.
   * - `{ headers }` — custom CORS headers.
   *
   * The boolean (`true`/`false`) and bare `Record<string, string>` forms are
   * deprecated but still accepted for backward compatibility.
   *
   * @remarks Only applies to the top-level {@link withSupabase} wrapper.
   * The adapters (Hono, H3, Elysia, NestJS) handle CORS separately via each
   * framework's own middleware.
   *
   * @defaultValue `'default'`
   */
  cors?: 'default' | 'disabled' | {
    headers: Record<string, string>;
  } /** @deprecated Use `'default'` | `'disabled'` | `{ headers }` instead. */ | boolean /** @deprecated Use `{ headers }` instead. */ | Record<string, string>;
  /**
   * Options forwarded to both internal `createClient()` calls.
   *
   * `accessToken` is stripped, and auth settings (`persistSession`, `autoRefreshToken`,
   * `detectSessionInUrl`) are force-overwritten to server-safe values.
   *
   * @example Custom Supabase options
   * ```ts
   * withSupabase({
   *   auth: 'user',
   *   supabaseOptions: { db: { schema: 'api' } },
   * }, handler)
   * ```
   */
  supabaseOptions?: SupabaseClientOptions<string>;
}
/**
 * Auth identity for client creation functions.
 *
 * @see {@link core.verifyAuth}, {@link core.verifyCredentials}
 * @category Types
 */
interface ClientAuth {
  /** The caller's JWT, or `null` for anonymous access. */
  token?: string | null;
  /** Name of the API key to use. Falls back to `"default"`, then first available. */
  keyName?: string | null;
}
/**
 * Options for {@link core.createContextClient}.
 * @category Types
 */
interface CreateContextClientOptions {
  /** Auth identity — token and key name from the verified request. */
  auth?: ClientAuth;
  /** Override auto-detected environment variables. */
  env?: Partial<SupabaseEnv>;
  /** Options forwarded to `createClient()`. `accessToken` is stripped; auth settings are force-overwritten. */
  supabaseOptions?: SupabaseClientOptions<string>;
}
/**
 * Options for {@link core.createAdminClient}.
 * @category Types
 */
interface CreateAdminClientOptions {
  /** Auth identity — key name from the verified request. */
  auth?: Pick<ClientAuth, 'keyName'>;
  /** Override auto-detected environment variables. */
  env?: Partial<SupabaseEnv>;
  /** Options forwarded to `createClient()`. `accessToken` is stripped; auth settings are force-overwritten. */
  supabaseOptions?: SupabaseClientOptions<string>;
}
/**
 * The Supabase context created for each authenticated request.
 *
 * Contains pre-configured Supabase clients and the caller's identity.
 * Identical regardless of which layer or adapter produced it.
 * @category Types
 */
interface SupabaseContext<Database = unknown> {
  /** Supabase client scoped to the caller's identity. RLS policies apply. */
  supabase: SupabaseClient<Database>;
  /** Admin Supabase client that bypasses Row-Level Security. */
  supabaseAdmin: SupabaseClient<Database>;
  /** JWT-derived identity. For the full Supabase User object, call `supabase.auth.getUser()`. */
  userClaims: UserClaims | null;
  /** Raw JWT payload. `null` for non-user auth modes. */
  jwtClaims: JWTClaims | null;
  /** The auth mode that was used for this request. */
  authMode: AuthMode;
  /**
   * The auth key name of the API key that was used for this request.
   * Omitted for `'user'` and `'none'` modes, which don't match a named key.
   */
  authKeyName?: string;
}
//#endregion
export { AuthResult as a, CreateContextClientOptions as c, SupabaseContext as d, SupabaseEnv as f, AuthModeWithKey as i, Credentials as l, WithSupabaseConfig as m, AllowWithKey as n, ClientAuth as o, UserClaims as p, AuthMode as r, CreateAdminClientOptions as s, Allow as t, JWTClaims as u };