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

export type BlazeCustomNativeAdEventType =
    | 'openedAd'
    | 'adPageStart'
    | 'adPageFirstQuarter'
    | 'adPageThird'
    | 'adPageMid'
    | 'adPageComplete'
    | 'pausedAdPage'
    | 'resumedAdPage'
    | 'ctaClicked';

interface BlazeGAMCustomNativeAdsDelegateOnAdEventParams {
    eventType: BlazeCustomNativeAdEventType;
}

interface BlazeGAMCustomNativeAdRequestInfo {
    adUnitId: string;
    templateId: string;
    adContext: Record<string, string>;
    extraInfo: BlazeContentExtraInfo;
}

export interface BlazeGAMCustomNativeAdRequestParams {
    requestDataInfo: BlazeGAMCustomNativeAdRequestInfo;
}

export interface BlazeGAMCustomNativeAdsDelegate {

    /**
     * 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.
     */
    onGAMAdEvent?: (params: BlazeGAMCustomNativeAdsDelegateOnAdEventParams) => void;

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

    /**
     * Returns custom targeting properties to be added to the GAM ad request.
     * This is called asynchronously from the native side right before an ad request.
     * 
     * @param params The request data information provides additional  info regarding the current ad request.
     * @returns A dictionary of key-value pairs to be added to the ad request
     */
    customGAMTargetingProperties?: (params: BlazeGAMCustomNativeAdRequestParams) => Record<string, string>;

    /**
     * Returns custom targeting properties to be added to the GAM ad request.
     * This is called asynchronously from the native side right before an ad request.
     * 
     * @param params The request data information provides additional  info regarding the current ad request.
     * @returns A custom publisher-provided identifier (PPID) for more granular targeting.
     */
    publisherProvidedId?: (params: BlazeGAMCustomNativeAdRequestParams) => string | undefined;

    /**
     * Provides additional network extras through GADExtras for customizing ad requests.
     * Use this to set network-specific parameters that can enhance ad targeting or behavior.
     * 
     * @param params The request data information provides additional  info regarding the current ad request.
     * @returns A dictionary of key-value pairs to be added to the ad request
     */
    networkExtras?: (params: BlazeGAMCustomNativeAdRequestParams) => Record<string, BlazePrimitive>;
}

export class BlazeCustomNativeAdsDelegateHelper {

    static registerDelegate(delegate?: BlazeGAMCustomNativeAdsDelegate | null) {
        // Register event listeners for regular events
        BlazeCustomNativeAdsDelegateHelper.onGAMAdEvent(delegate?.onGAMAdEvent)
        BlazeCustomNativeAdsDelegateHelper.onGAMAdError(delegate?.onGAMAdError)
        BlazeCustomNativeAdsDelegateHelper.customGAMTargetingProperties(delegate?.customGAMTargetingProperties)
        BlazeCustomNativeAdsDelegateHelper.publisherProvidedId(delegate?.publisherProvidedId)
        BlazeCustomNativeAdsDelegateHelper.networkExtras(delegate?.networkExtras)
    }

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

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

    private static customGAMTargetingProperties(
        callback?: (params: BlazeGAMCustomNativeAdRequestParams) => Promise<Record<string, string>> | Record<string, string>,
    ) {
        const eventName = 'BlazeGAM.customGAMTargetingProperties'
        // Register async method handler
        if (callback) {
            BlazeAsyncBridge.registerJSMethod(
                eventName,
                async (params) => {
                    try {
                        const result = await callback(params as BlazeGAMCustomNativeAdRequestParams);
                        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 publisherProvidedId(
        callback?: (params: BlazeGAMCustomNativeAdRequestParams) => Promise<string | undefined> | string | undefined,
    ) {
        const eventName = 'BlazeGAM.publisherProvidedId'
        // Register async method handler
        if (callback) {
            BlazeAsyncBridge.registerJSMethod(
                eventName,
                async (params) => {
                    try {
                        const result = await callback(params as BlazeGAMCustomNativeAdRequestParams);
                        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 networkExtras(
        callback?: (params: BlazeGAMCustomNativeAdRequestParams) => Promise<Record<string, BlazePrimitive>> | Record<string, BlazePrimitive>,
    ) {
        const eventName = 'BlazeGAM.networkExtras'
        // Register async method handler
        if (callback) {
            BlazeAsyncBridge.registerJSMethod(
                eventName,
                async (params) => {
                    try {
                        const result = await callback(params as BlazeGAMCustomNativeAdRequestParams);
                        return result;
                    } catch (error) {
                        console.error(`Error in ${eventName}:`, error);
                        return {};
                    }
                }
            );
        } else {
            // Unregister the handler if no delegate is provided
            BlazeAsyncBridge.unregisterJSMethod(eventName);
        }
    }
}