import { BlazeAsyncBridge, BlazeContentExtraInfo, BlazeGlobalEvents } from "@wscsports/blaze-rtn-sdk";

export type BlazeIMAOnAdEventEventType =
    | 'adStarted' // Ad has started.
    | 'allAdsCompleted' // All valid ads managed by the ads manager have completed.
    | 'adClicked' // Ad clicked.
    | 'adCompleted' // Single ad has finished.
    | 'adLoaded' // An ad was loaded.
    | 'adPaused' // Ad paused.
    | 'adResumed' // Ad resumed.
    | 'adSkipped' // Ad has skipped.
    | 'adTapped' // Ad tapped.
    | 'adFirstQuartile' // First quartile of a linear ad was reached.
    | 'adMidpoint' // Midpoint of a linear ad was reached.
    | 'adThirdQuartile' // Third quartile of a linear ad was reached.
    | 'adRequested' // Ad Requested.
    ;

export interface BlazeIMASettings {
    language?: string
    ppid?: string
    sessionId?: string
}

interface BlazeIMADelegateOnAdEventParams {
    eventType: BlazeIMAOnAdEventEventType;
}

interface BlazeIMAAdRequestInfo {
    extraInfo: BlazeContentExtraInfo;
}

export interface BlazeIMAAdRequestParams {
    requestDataInfo: BlazeIMAAdRequestInfo;
}

export interface BlazeIMADelegate {

    /**
     * This function will be triggered every time an event on an ad will happen.
     * 
     * @param params The data associated with the ad involved in the event.
     */
    onIMAAdEvent?: (params: BlazeIMADelegateOnAdEventParams) => void;

    /**
      * Called when an error occurs during ad loading or playback.
      * 
      * @param errorMessage The error message associated with the error.
      */
    onIMAAdError?: (errorMessage: string) => void;

    /**
     * 
     * @param params The request data information provides additional info regarding the current ad request.
     * @returns Additional query parameters to be included in the ad tag.
     */
    additionalIMATagQueryParams?: (params: BlazeIMAAdRequestParams) => Record<string, string>;

    /**
     * 
     * @param params The request data information provides additional info regarding the current ad request.
     * @returns Custom settings for the IMA SDK.
     */
    customIMASettings?: (params: BlazeIMAAdRequestParams) => BlazeIMASettings | undefined;

    /**
     * Overrides the default ad tag URL with a custom one. This URL will be used for the ad request.
     * 
     * @param params The request data information provides additional info regarding the current ad request.
     * @returns the override ad tag URL to be used for the ad request.
     */
    overrideAdTagUrl?: (params: BlazeIMAAdRequestParams) => string | undefined;

}

export class BlazeGlobalDelegateHelper {

    static registerDelegate(delegate?: BlazeIMADelegate | null) {
        BlazeGlobalDelegateHelper.onIMAAdEvent(delegate?.onIMAAdEvent)
        BlazeGlobalDelegateHelper.onIMAAdError(delegate?.onIMAAdError)
        BlazeGlobalDelegateHelper.additionalIMATagQueryParams(delegate?.additionalIMATagQueryParams)
        BlazeGlobalDelegateHelper.customIMASettings(delegate?.customIMASettings)
        BlazeGlobalDelegateHelper.overrideAdTagUrl(delegate?.overrideAdTagUrl)
    }

    private static onIMAAdEvent(
        callback?: (params: BlazeIMADelegateOnAdEventParams) => void,
    ) {
        const eventName = 'BlazeIMA.onAdEvent'
        if (callback) {
            BlazeGlobalEvents.createEventSubscription(
                eventName,
                (data: any) => {
                    try {
                        const eventType = data['eventType'];
                        callback({
                            eventType
                        });
                    } catch (e) {
                        console.error('onIMAAdEvent', e);
                    }
                },
            );
        } else {
            BlazeGlobalEvents.cancelEventSubscription(eventName)
        }
    };

    private static onIMAAdError(
        callback?: (errorMessage: string) => void,
    ) {
        const eventName = 'BlazeIMA.onAdError'
        if (callback) {
            BlazeGlobalEvents.createEventSubscription(
                eventName,
                (data: any) => {
                    try {
                        const errorMessage = data['errorMessage'];
                        callback(errorMessage);
                    } catch (e) {
                        console.error('onIMAAdError', e);
                    }
                },
            );
        } else {
            BlazeGlobalEvents.cancelEventSubscription(eventName)
        }
    };

    private static additionalIMATagQueryParams(
        callback?: (params: BlazeIMAAdRequestParams) => Promise<Record<string, string>> | Record<string, string>
    ) {
        const eventName = 'BlazeIMA.additionalIMATagQueryParams'
        // Register async method handler
        if (callback) {
            BlazeAsyncBridge.registerJSMethod(
                eventName,
                async (params) => {
                    try {
                        const result = await callback(params as BlazeIMAAdRequestParams);
                        return result;
                    } catch (error) {
                        console.error(`Error in ${eventName}:`, error);
                        return {};
                    }
                }
            );
        } else {
            // Unregister the handler if no delegate is provided
            BlazeAsyncBridge.unregisterJSMethod(eventName);
        }
    }

    private static customIMASettings(
        callback?: (params: BlazeIMAAdRequestParams) => Promise<BlazeIMASettings | undefined> | BlazeIMASettings | undefined
    ) {
        const eventName = 'BlazeIMA.customIMASettings'
        // Register async method handler
        if (callback) {
            BlazeAsyncBridge.registerJSMethod(
                eventName,
                async (params) => {
                    try {
                        const result = await callback(params as BlazeIMAAdRequestParams);
                        return result;
                    } catch (error) {
                        console.error(`Error in ${eventName}:`, error);
                        return undefined;
                    }
                }
            );
        } else {
            // Unregister the handler if no delegate is provided
            BlazeAsyncBridge.unregisterJSMethod(eventName);
        }
    }

    private static overrideAdTagUrl(
        callback?: (params: BlazeIMAAdRequestParams) => Promise<string | undefined> | string | undefined
    ) {
        const eventName = 'BlazeIMA.overrideAdTagUrl'
        // Register async method handler
        if (callback) {
            BlazeAsyncBridge.registerJSMethod(
                eventName,
                async (params) => {
                    try {
                        const result = await callback(params as BlazeIMAAdRequestParams);
                        return result;
                    } catch (error) {
                        console.error(`Error in ${eventName}:`, error);
                        return undefined;
                    }
                }
            );
        } else {
            // Unregister the handler if no delegate is provided
            BlazeAsyncBridge.unregisterJSMethod(eventName);
        }
    }

}