import { GoTrueClientOptions } from '@supabase/auth-js'
import { RealtimeClientOptions } from '@supabase/realtime-js'
import { PostgrestError } from '@supabase/postgrest-js'
import type { StorageClientOptions } from '@supabase/storage-js'
import type {
  GenericSchema,
  GenericRelationship,
  GenericTable,
  GenericUpdatableView,
  GenericNonUpdatableView,
  GenericView,
  GenericFunction,
} from './rest/types/common/common'
export type {
  GenericSchema,
  GenericRelationship,
  GenericTable,
  GenericUpdatableView,
  GenericNonUpdatableView,
  GenericView,
  GenericFunction,
}

export interface SupabaseAuthClientOptions extends GoTrueClientOptions {}

export type Fetch = typeof fetch

/**
 * Configuration options for trace context propagation.
 *
 * Enables distributed tracing across Supabase services using W3C Trace Context
 * and OpenTelemetry standards. When enabled, the SDK automatically attaches
 * trace context headers (traceparent, tracestate, baggage) to outgoing requests
 * to Supabase domains.
 *
 * @see https://www.w3.org/TR/trace-context/
 * @see https://opentelemetry.io/docs/concepts/context-propagation/
 */
export interface TracePropagationOptions {
  /**
   * Enable trace propagation. Disabled by default.
   *
   * When enabled, automatically detects and propagates active trace context
   * from the OpenTelemetry API to outgoing Supabase requests. Trace context
   * is only propagated to Supabase domains (*.supabase.co, *.supabase.in,
   * localhost) for security.
   *
   * @default false
   */
  enabled?: boolean

  /**
   * Respect upstream sampling decisions.
   *
   * When true, trace context will not be propagated if the upstream trace
   * indicates non-sampling (sampled flag = 0 in traceparent header).
   * This helps reduce overhead when traces are not being collected.
   *
   * @default true
   */
  respectSamplingDecision?: boolean
}

export type SupabaseClientOptions<SchemaName> = {
  /**
   * The Postgres schema which your tables belong to. Must be on the list of exposed schemas in Supabase. Defaults to `public`.
   */
  db?: {
    schema?: SchemaName
    /**
     * Optional timeout in milliseconds for PostgREST requests.
     * When set, requests will automatically abort after this duration to prevent indefinite hangs.
     *
     * @example With timeout
     * ```ts
     * const supabase = createClient(url, key, {
     *   db: { timeout: 30000 } // 30 second timeout
     * })
     * ```
     */
    timeout?: number
    /**
     * Maximum URL length in characters before warnings/errors are triggered.
     * Defaults to 8000 characters. Used to provide helpful hints when URLs
     * exceed server limits.
     *
     * @example With custom URL length limit
     * ```ts
     * const supabase = createClient(url, key, {
     *   db: { urlLengthLimit: 10000 } // Custom limit
     * })
     * ```
     */
    urlLengthLimit?: number
  }

  auth?: {
    /**
     * Automatically refreshes the token for logged-in users. Defaults to true.
     */
    autoRefreshToken?: boolean
    /**
     * Optional key name used for storing tokens in local storage.
     */
    storageKey?: string
    /**
     * Whether to persist a logged-in session to storage. Defaults to true.
     */
    persistSession?: boolean
    /**
     * Detect a session from the URL. Used for OAuth login callbacks. Defaults to true.
     *
     * Can be set to a function to provide custom logic for determining if a URL contains
     * a Supabase auth callback. The function receives the current URL and parsed parameters,
     * and should return true if the URL should be processed as a Supabase auth callback.
     *
     * This is useful when your app uses other OAuth providers (e.g., Facebook Login) that
     * also return access_token in the URL fragment, which would otherwise be incorrectly
     * intercepted by Supabase Auth.
     *
     * @example With custom detection logic
     * ```ts
     * detectSessionInUrl: (url, params) => {
     *   // Ignore Facebook OAuth redirects
     *   if (url.pathname === '/facebook/redirect') return false
     *   // Use default detection for other URLs
     *   return Boolean(params.access_token || params.error_description)
     * }
     * ```
     */
    detectSessionInUrl?: boolean | ((url: URL, params: { [parameter: string]: string }) => boolean)
    /**
     * A storage provider. Used to store the logged-in session.
     */
    storage?: SupabaseAuthClientOptions['storage']
    /**
     * A storage provider to store the user profile separately from the session.
     * Useful when you need to store the session information in cookies,
     * without bloating the data with the redundant user object.
     *
     * @experimental
     */
    userStorage?: SupabaseAuthClientOptions['userStorage']
    /**
     * OAuth flow to use - defaults to implicit flow. PKCE is recommended for mobile and server-side applications.
     */
    flowType?: SupabaseAuthClientOptions['flowType']
    /**
     * If debug messages for authentication client are emitted. Can be used to inspect the behavior of the library.
     */
    debug?: SupabaseAuthClientOptions['debug']
    /**
     * Provide your own locking mechanism based on the environment. By default no locking is done at this time.
     *
     * @experimental
     */
    lock?: SupabaseAuthClientOptions['lock']
    /**
     * If there is an error with the query, throwOnError will reject the promise by
     * throwing the error instead of returning it as part of a successful response.
     */
    throwOnError?: SupabaseAuthClientOptions['throwOnError']
    /**
     * Opt-in flags for experimental features. These APIs may change without
     * notice and are disabled by default.
     *
     * @experimental
     */
    experimental?: SupabaseAuthClientOptions['experimental']
    /**
     * Maximum time in milliseconds to wait when acquiring the auth lock before
     * stealing it from the previous holder. See `GoTrueClientOptions.lockAcquireTimeout`
     * for full semantics (zero fails immediately, negative waits indefinitely).
     *
     * @default 5000
     */
    lockAcquireTimeout?: SupabaseAuthClientOptions['lockAcquireTimeout']
    /**
     * If true, skips automatic initialization in the auth client constructor.
     * Useful for SSR contexts where initialization timing must be controlled to
     * prevent race conditions with HTTP response generation.
     *
     * @default false
     */
    skipAutoInitialize?: SupabaseAuthClientOptions['skipAutoInitialize']
  }
  /**
   * Options passed to the realtime-js instance
   */
  realtime?: RealtimeClientOptions
  storage?: StorageClientOptions
  global?: {
    /**
     * A custom `fetch` implementation.
     */
    fetch?: Fetch
    /**
     * Optional headers for initializing the client.
     */
    headers?: Record<string, string>
  }
  /**
   * Optional function for using a third-party authentication system with
   * Supabase. The function should return an access token or ID token (JWT) by
   * obtaining it from the third-party auth SDK. Note that this
   * function may be called concurrently and many times. Use memoization and
   * locking techniques if this is not supported by the SDKs.
   *
   * When set, the `auth` namespace of the Supabase client cannot be used.
   * Create another client if you wish to use Supabase Auth and third-party
   * authentications concurrently in the same application.
   */
  accessToken?: () => Promise<string | null>
  /**
   * Enable OpenTelemetry / W3C trace context propagation to Supabase services.
   *
   * Disabled by default. Pass `true` for the common case (auto-detect an
   * active OTel context and inject `traceparent` / `tracestate` / `baggage`
   * headers) or an object for fine-grained control.
   *
   * Requires `@opentelemetry/api` to be installed in your application; if
   * not present, the SDK silently no-ops.
   *
   * @example
   * ```ts
   * // Shorthand — opt in with defaults.
   * createClient(url, key, { tracePropagation: true })
   *
   * // Advanced — always propagate, even for non-sampled traces.
   * createClient(url, key, {
   *   tracePropagation: { enabled: true, respectSamplingDecision: false },
   * })
   * ```
   */
  tracePropagation?: TracePropagationOptions | boolean
}

/**
 * Helper types for query results.
 */
export type QueryResult<T> = T extends PromiseLike<infer U> ? U : never
export type QueryData<T> = T extends PromiseLike<{ data: infer U }> ? Exclude<U, null> : never
export type QueryError = PostgrestError

/**
 * Strips internal Supabase metadata from Database types.
 * Useful for libraries defining generic constraints on Database types.
 *
 * @example Stripping internal Supabase metadata
 * ```typescript
 * type CleanDB = DatabaseWithoutInternals<Database>
 * ```
 */
export type DatabaseWithoutInternals<DB> = Omit<DB, '__InternalSupabase'>
