import { IntegrationFn, IntegrationClass, Integration, Options as Options$1 } from '@sentry/types';
import { browserTracingIntegration, vueRouterInstrumentation } from '@sentry/vue';
import { Options, TracingOptions } from '@sentry/vue/types/types';
import { SentryWebpackPluginOptions } from '@sentry/webpack-plugin';
import * as SentryNode from '@sentry/node';
import { Integrations, NodeOptions, Handlers } from '@sentry/node';
import { Configuration } from 'webpack';
import { breadcrumbsIntegration, globalHandlersIntegration, httpContextIntegration, replayIntegration, browserApiErrorsIntegration } from '@sentry/browser';
import * as SentryTypes from '@sentry/core';
import { functionToStringIntegration, inboundFiltersIntegration, linkedErrorsIntegration, requestDataIntegration } from '@sentry/core';
import { captureConsoleIntegration, contextLinesIntegration, debugIntegration, dedupeIntegration, extraErrorDataIntegration, httpClientIntegration, reportingObserverIntegration, rewriteFramesIntegration, sessionTimingIntegration } from '@sentry/integrations';

type IntegrationConfig<T extends IntegrationFn> = Parameters<T>[0] | Record<string, never> | false
type ClassIntegrationConfig<T extends IntegrationClass<Integration>> = ConstructorParameters<T>[0] | Record<string, never> | false

type BrowserIntegrations = {
    Breadcrumbs?: IntegrationConfig<typeof breadcrumbsIntegration>
    GlobalHandlers?: IntegrationConfig<typeof globalHandlersIntegration>
    HttpContext?: IntegrationConfig<typeof httpContextIntegration>
    Replay?: IntegrationConfig<typeof replayIntegration>
    TryCatch?: IntegrationConfig<typeof browserApiErrorsIntegration>
}

type CoreIntegrations = {
    FunctionToString?: IntegrationConfig<typeof functionToStringIntegration>
    InboundFilters?: IntegrationConfig<typeof inboundFiltersIntegration>
    LinkedErrors?: IntegrationConfig<typeof linkedErrorsIntegration>
    RequestData?: IntegrationConfig<typeof requestDataIntegration>
}

type PluggableIntegrations = {
    CaptureConsole?: IntegrationConfig<typeof captureConsoleIntegration>
    ContextLines?: IntegrationConfig<typeof contextLinesIntegration>
    Debug?: IntegrationConfig<typeof debugIntegration>
    Dedupe?: IntegrationConfig<typeof dedupeIntegration>
    ExtraErrorData?: IntegrationConfig<typeof extraErrorDataIntegration>
    HttpClient?: IntegrationConfig<typeof httpClientIntegration>
    ReportingObserver?: IntegrationConfig<typeof reportingObserverIntegration>
    RewriteFrames?: IntegrationConfig<typeof rewriteFramesIntegration>
    SessionTiming?: IntegrationConfig<typeof sessionTimingIntegration>
}

type NodeProfilingIntegrations = {
    ProfilingIntegration?: IntegrationConfig<IntegrationFn> // Dummy type since we don't want to depend on `@sentry/profiling-node`
}

type NodeIntegrations = {
    Anr?: ClassIntegrationConfig<typeof Integrations.Anr>
    Apollo?: ClassIntegrationConfig<typeof Integrations.Apollo>
    Console?: ClassIntegrationConfig<typeof Integrations.Console>
    Context?: ClassIntegrationConfig<typeof Integrations.Context>
    ContextLines?: ClassIntegrationConfig<typeof Integrations.ContextLines>
    Express?: ClassIntegrationConfig<typeof Integrations.Express>
    GraphQL?: ClassIntegrationConfig<typeof Integrations.GraphQL>
    Hapi?: ClassIntegrationConfig<typeof Integrations.Hapi>
    Http?: ClassIntegrationConfig<typeof Integrations.Http>
    LocalVariables?: ClassIntegrationConfig<typeof Integrations.LocalVariables>
    Modules?: ClassIntegrationConfig<typeof Integrations.Modules>
    Mongo?: ClassIntegrationConfig<typeof Integrations.Mongo>
    Mysql?: ClassIntegrationConfig<typeof Integrations.Mysql>
    OnUncaughtException?: ClassIntegrationConfig<typeof Integrations.OnUncaughtException>
    OnUnhandledRejection?: ClassIntegrationConfig<typeof Integrations.OnUnhandledRejection>
    Postgres?: ClassIntegrationConfig<typeof Integrations.Postgres>
    Prisma?: ClassIntegrationConfig<typeof Integrations.Prisma>
    Spotlight?: ClassIntegrationConfig<typeof Integrations.Spotlight>
    Undici?: ClassIntegrationConfig<typeof Integrations.Undici>
}

type ClientCoreIntegrations = Pick<CoreIntegrations, 'FunctionToString' | 'InboundFilters' | 'LinkedErrors'>
type ClientPluggableIntegrations = PluggableIntegrations
type ClientIntegrations = ClientCoreIntegrations & ClientPluggableIntegrations & BrowserIntegrations

type ServerCoreIntegrations = CoreIntegrations
type ServerPluggableIntegrations = Omit<PluggableIntegrations, 'ContextLines'>
type ServerIntegrations = ServerCoreIntegrations & ServerPluggableIntegrations & NodeProfilingIntegrations & NodeIntegrations

interface LazyConfiguration {
    chunkName?: string
    injectLoadHook?: boolean
    injectMock?: boolean
    mockApiMethods?: boolean | string[]
    webpackPrefetch?: boolean
    webpackPreload?: boolean
}

interface TracingConfiguration extends Pick<Options$1, 'tracesSampleRate'> {
    browserTracing?: Parameters<typeof browserTracingIntegration>[0]
    vueOptions?: Partial<TracingOptions>
    vueRouterInstrumentationOptions?: Parameters<typeof vueRouterInstrumentation>[1]
}

interface ModuleConfiguration {
  clientConfig: Partial<Options> | string
  clientIntegrations: ClientIntegrations
  config: Options$1
  customClientIntegrations: string
  customServerIntegrations: string
  disableClientRelease: boolean
  disableClientSide: boolean
  disabled: boolean
  disableServerRelease: boolean
  disableServerSide: boolean
  dsn: string
  tracing: boolean | TracingConfiguration
  initialize: boolean
  lazy: boolean | LazyConfiguration
  logMockCalls: boolean
  /** See available options at https://docs.sentry.io/platforms/node/sourcemaps/uploading/webpack/ */
  publishRelease: boolean | SentryWebpackPluginOptions
  runtimeConfigKey: string
  serverConfig: NodeOptions | string
  serverIntegrations: ServerIntegrations
  sourceMapStyle: Configuration['devtool']
  requestHandlerConfig: Handlers.RequestHandlerOptions
}

type PartialModuleConfiguration = Partial<ModuleConfiguration>

type ModulePublicRuntimeConfig = Pick<PartialModuleConfiguration, 'config' | 'clientConfig' | 'serverConfig'>

type Sentry = typeof SentryTypes
type NodeSentry = typeof SentryNode

// add type to Vue context
declare module 'vue/types/vue' {
  interface Vue {
    readonly $sentry: Sentry
    $sentryLoad(): Promise<void>
    $sentryReady(): Promise<Sentry>
  }
}

// App Context and NuxtAppOptions
declare module '@nuxt/types' {
  interface Context {
    readonly $sentry: Sentry
    $sentryLoad(): Promise<void>
    $sentryReady(): Promise<Sentry>
  }

  interface NuxtOptions {
    sentry?: PartialModuleConfiguration
  }

  interface NuxtAppOptions {
    readonly $sentry: Sentry
    $sentryLoad(): Promise<void>
    $sentryReady(): Promise<Sentry>
  }
}

declare module '@nuxt/types/config/runtime' {
  interface NuxtRuntimeConfig {
    sentry?: ModulePublicRuntimeConfig
  }
}

// add types for Vuex Store
declare module 'vuex/types' {
  interface Store<S> {
    readonly $sentry: Sentry
    $sentryLoad(): Promise<void>
    $sentryReady(): Promise<Sentry>
  }
}

declare global {
  namespace NodeJS {
    interface Process {
      sentry: NodeSentry
    }
  }
}

type ModuleOptions = PartialModuleConfiguration

declare const _default: unknown;

export { type ModuleOptions, type ModulePublicRuntimeConfig, _default as default };
