import React, { ComponentProps, ComponentPropsWithRef, ComponentType, ReactNode } from 'react';

export enum TraverseDirection {
    Child = 0,
    Parent,
    Sibling,
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface TraverseOptions {}

export interface PendoOptions {
    onInitComplete?: () => void;
    onInitFailed?: () => void;
}

export interface RNTraverseOptions {
    debouncerTime?: number;
    firstScreenDebouncerTime?: number;
    analyzeScreenNoDebouncerTime?: number;
    analyzeScreenDefaultDebouncerTime?: number;
    analyzeContentScreenDefaultDebouncerTime?: number;
    nativeIDs?: string[] | null;
    clickableElementsNativeIDsRegex?: string | null | undefined;
    android?: Partial<TraverseOptions>;
    ios?: Partial<TraverseOptions>;
}

export interface WithReactNavigationProps extends ComponentPropsWithRef<any> {
    onStateChange?: Function;
    onReady?: Function;
    theme?: any;
    linking?: any;
    fallback?: ReactNode;
    documentTitle?: any;
}

export enum NavigationLibraryType {
    NoPluginDetected = 0,
    ReactNativeNavigation = 1,
    ReactNavigation = 2,
    ExpoRouter = 5,
    Paper = 6,
    Other = 3,
}

export interface NavigationOptions {
    library: NavigationLibraryType;
    navigation?: any;
    clickableElementsNativeIDsRegex?: string;
}

export interface WithExpoRouterProps extends ComponentProps<any> {
    onExpoRouterStateChange: Function;
}

export class PendoSDK {
    /**
     * Set up the Pendo SDK. Call startSession API when you would like to start a session (anonymous or identified).
     * @param appKey The app key for your account
     * @param navigationOptions The navigation §options of your app
     * @param pendoOptions Additional options for internal use
     */
    static setup(appKey: string, navigationOptions: NavigationOptions, pendoOptions?: PendoOptions): void;

    /**
     * Must be called after the SDK was set up.
     * Start a session with a new visitor (anonymous or identified).
     * In case a session was already started, end the session and start a new one.
     * @param visitorId The visitor's ID
     * @param accountId The account's ID
     * @param visitorData The visitor's data
     * @param accountData The account's data
     */
    static startSession(visitorId?: string, accountId?: string, visitorData?: object, accountData?: object): void;

    /**
     * Ends the current session and stops gathering analytics and presenting guides.
     */
    static endSession(): void;

    /**
     * Tracks an event that has happened in your application.
     * @param name The name of the event.
     * @param params Additional parameters for the event (optional).
     */
    static track(name: string, params?: object): void;

    /**
     * Sets a visitor data value.
     * This data is used by Pendo Mobile for creating audiences or reporting analytics.
     * For instance, you might want to provide data on the visitor's age or if the visitor is logged into a service.
     * @param visitorData The visitor's data.
     */
    static setVisitorData(visitorData: object): void;

    /**
     * Sets account data value for a given data name.
     * This data is used by Pendo Mobile for creating audiences or reporting analytics.
     * For instance, you might want to provide data on the account's subscription or if the account is active or not.
     * @param accountData The account's data
     */
    static setAccountData(accountData: object): void;

    /**
     * Stops showing guides.
     * @param dismissGuides Indicates whether to dismiss any guides currently visible.
     */
    static pauseGuides(dismissGuides: boolean): void;

    /**
     * Resumes showing guides.
     */
    static resumeGuides(): void;

    /**
     * Dismisses any visible guides.
     */
    static dismissVisibleGuides(): void;

    /**
     * Returns the current visitor id if available.
     */
    static getVisitorId(): Promise<string | null>;

    /**
     * Returns the current account id if available.
     */
    static getAccountId(): Promise<string | null>;

    /**
     * Returns the Pendo SDK unique device id.
     * Used for anonymous visitor id.
     * This id is unique per application.
     */
    static getDeviceId(): Promise<string | null>;

    /**
     * Sets whether to print debug logs.
     * @param enabled Indicates whether to print debug logs.
     */
    static setDebugMode(enabled: boolean): void;

    /**
     * Call this method in case some content on your screen was changed, and you want to trigger screen scan.
     */
    static screenContentChanged(): void;

    /**
     * Send click analytic for the specific view component
     * @param nativeID of the view component
     */
    static sendClickAnalytic(nativeID: string): void;
}

export function WithPendoReactNavigation<P extends WithReactNavigationProps>(
    WrappedComponent: React.ComponentType<P>,
    options?: RNTraverseOptions,
): React.FunctionComponent<P>;

export function WithPendoModal<P extends object>(WrappedComponent: React.ComponentType<P>): React.ComponentType<P>;

export function WithPendoExpoRouter<P extends ComponentPropsWithRef<any>>(
    WrappedComponent: ComponentType<P>,
    options?: RNTraverseOptions,
): React.FunctionComponent<P & WithExpoRouterProps>;

export function WithPendoPaper<P extends WithPaperProps>(
    WrappedComponent: ComponentType<P>,
    options?: RNTraverseOptions,
): React.FunctionComponent<Omit<P, 'forwardedRef'>>;
