type Nullable<T> = {
  [Property in keyof T]: T[Property] | null;
};

declare let LogRocket: LR.LogRocket;

export = LogRocket;

declare namespace LR {
  interface IRequest {
    reqId: string;
    url: string;
    headers: { [key: string]: string | null | undefined };
    body?: string;
    method: string;
    referrer?: string;
    mode?: string;
    credentials?: string;
  }

  interface IResponse {
    reqId: string;
    status?: number;
    headers: { [key: string]: string | null | undefined };
    body?: string;
    method: string;
    url?: string;
  }

  interface IOptions {
    release?: string;
    console?: {
      isEnabled?:
        | boolean
        | {
            log?: boolean;
            info?: boolean;
            debug?: boolean;
            warn?: boolean;
            error?: boolean;
          };
      shouldAggregateConsoleErrors?: boolean;
    };
    network?: {
      isEnabled?: boolean;
      requestSanitizer?(request: IRequest): null | Nullable<IRequest>;
      responseSanitizer?(response: IResponse): null | Nullable<IResponse>;
    };
    browser?: {
      urlSanitizer?(url: string): null | string;
    };
    dom?: {
      isEnabled?: boolean;
      baseHref?: string;
      textSanitizer?: boolean | string;
      inputSanitizer?: boolean | string;
      imageSanitizer?: boolean | string;
      privateAttributeBlocklist?: string[];
      privateClassNameBlocklist?: string[];
      hiddenAttributes?: string[];
      /**
       * Prevents Web Animation API animations from being captured in a limited capacity.
       * Defaults to false.
       */
      disableWebAnimations?: boolean;

      /** Prevents recording of document.title */
      disablePageTitles?: boolean;

      /** Prevents visibleElement filters from taking the viewport into consideration */
      disableVisibleElement?: boolean;

      /** Logs diagnostics when a stylesheet change cannot be recorded. Defaults to false. */
      shouldLogDroppedStyleDiagnostics?: boolean;
    };

    /** Controls collection of IP addresses and related features, such as GeoIP */
    shouldCaptureIP?: boolean;

    /**
     * Enable sharing sessions across subdomains by setting this to the top-level hostname.
     * */
    rootHostname?: string;

    /**
     * Configure where recording data is published - useful for proxying data and Self-Hosted installations.
     *
     * A full and valid ingestion URL is required (eg. https://ingest.example.com/i)
     */
    serverURL?: string;

    uploadTimeInterval?: number;

    /** a callback which determines whether to send data at a particular moment of time. * */
    shouldSendData?(): boolean;

    shouldDebugLog?: boolean;

    mergeIframes?: boolean;

    /**
     * Controls domains to which a parent window can post messages
     * in order to merge recording with cross-domain iframes
     * */
    childDomains?: string[] | null;

    /**
     * Controls domain to which an iframe window can post messages
     * in order to merge recording with a cross-domain parent window
     * */
    parentDomain?: string | null;

    shouldAugmentNPS?: boolean;

    shouldParseXHRBlob?: boolean;

    /** Controls automatic detection of JS errors using Raven.js
     *  Does not impact captureException or aggregation of console errors
     */
    shouldDetectExceptions?: boolean;

    /** Disables automatic busy frames tracking used for CPU Usage monitoring
     */
    disableBusyFramesTracker?: boolean;

    /**
     * When true, indicates a brand new session should be started on this init call, and no other
     * information, such as user identity, should be carried over from any previous session.
     */
    forceCleanStart?: boolean;

    /**
     * When true, user ID info is persisted to the session info cookie. This is useful for tracking user identities
     * across subdomains (ex. on Shopify checkout pages located on a different subdomain than the storefront)
     */
    persistUserIdInfo?: boolean;
  }

  interface IUserTraits {
    [propName: string]: string | number | boolean;
  }

  type State = { [key: string]: any };
  type Action = { [key: string]: any };

  interface IReduxMiddlewareOptions {
    /** Sanitizer function to scrub redux state */
    stateSanitizer?(state: State): State;
    /** Sanitizer function to scrub or ignore specific redux actions */
    actionSanitizer?(action: Action): null | Action;
  }

  interface ICaptureOptions {
    tags?: {
      [tagName: string]: string | number | boolean;
    };
    extra?: {
      [tagName: string]: string | number | boolean;
    };
  }

  type TrackEventProperties = {
    revenue?: number;
    [key: string]: string | number | boolean | string[] | number[] | boolean[] | undefined | null;
  };

  interface LogRocket {
    /** Configures LogRocket */
    init(
      /** Your LogRocket appID (find it in LogRocket settings) */
      appID: string,
      /** Optional configuration to change what LogRocket records */
      options?: IOptions
    ): void;

    // logging functions
    log(...props: any[]): void;
    info(...props: any[]): void;
    warn(...props: any[]): void;
    error(...props: any[]): void;
    debug(...props: any[]): void;

    /** Identify a user with the current session, with optional user traits */
    identify(uid: string, traits?: IUserTraits): void;
    identify(traits: IUserTraits): void;

    /** Returns a redux middleware which adds redux logs to LogRocket sessions */
    reduxMiddleware(
      /** Optional sanitizer configuration */
      options?: IReduxMiddlewareOptions
    ): any;

    /** Send an event to LogRocket */
    track(eventName: string, eventProperties?: TrackEventProperties): void;

    /** Start a new session and end the current one */
    startNewSession(): void;

    /** Get the current session URL in a callback function */
    getSessionURL(
      /** Callback to get session URL */
      callback: (sessionURL: string) => void
    ): void;

    /** Current SDK version if LogRocket has been loaded, undefined otherwise */
    version: string | undefined;

    /** Current session URL if LogRocket has been loaded, null otherwise */
    sessionURL: string | null;

    /** Manually report string errors to LogRocket */
    captureMessage(
      /** identifier */
      message: string,
      /** error metadata */
      options?: ICaptureOptions
    ): void;

    /** Manually report exceptions to LogRocket */
    captureException(
      /** Error instance */
      exception: Error,
      /** Error metadata */
      options?: ICaptureOptions
    ): void;
  }
}
