/**
 * Copyright © 2022 Anagog Ltd. All rights reserved.
 */

import { FlatList, NativeModules, Platform } from 'react-native';
import { eventEmitter } from './Emitter';
import { AnagogEventType } from './types/AnagogEventType';
import { JedAIStatus } from './types/JedAIStatus';
import type { JEMAUserInteractionEvent } from './models/JEMAUserInteractionEvent';
import type { ApplicationEvent } from './models/ApplicationEvent';
import { Onboarding } from './Onboarding';
import { PageTracker } from './PageTracker';
import { AnagogLogger } from './AnagogLogger';
import { ANAGOG_FCM_INDICATION } from './constants/Constants';
import type  {TimeFrame}  from './types/TimeFrame';

const { JedAIModule } = NativeModules;

const packageInfo = require('../package.json');
const PACKAGE_VERSION = packageInfo['version'] + (packageInfo["isDev"] === true ? ".dev" : "");

sendInfoToSDK();

export class AnagogSDK {

	static packageVersion = PACKAGE_VERSION;

	static onboarding = new Onboarding();
	static pageTracker = new PageTracker();

	/**
	 * Create an EventStream from JedAI to your ReactNative app.
	 * Use this API to listen for SDK events such as onCampaignTriggered, onNotificationClick, onSnapshotReport.
	 * @param listener callback with 2 parameters: `AnagogEventType` and payload that different for each type of event.
	 * @see {@link https://www.npmjs.com/package/@anagog/jedai#SDK-Notifications example}
	 */
	static obtainEventStream(listener: (action: AnagogEventType, payload: any) => void) {
		AnagogLogger.info('obtainEventStream called');

		// Remove previous listeners
		Object.keys(AnagogEventType).filter((item) => {
			return isNaN(Number(item));
		}).forEach(
			eventType => eventEmitter?.removeAllListeners(eventType)
		);

		// Add new listeners
		eventEmitter?.addListener(AnagogEventType.onCampaignTriggered, (event) => {
			AnagogLogger.info('Event received: ' + AnagogEventType.onCampaignTriggered + (event ? ' ' + JSON.stringify(event ?? {}) : ''));
			listener(AnagogEventType.onCampaignTriggered, event);
		});
		eventEmitter?.addListener(AnagogEventType.onNotificationClick, (event) => {
			AnagogLogger.info('Event received: ' + AnagogEventType.onNotificationClick + (event ? ' ' + JSON.stringify(event ?? {}) : ''));
			listener(AnagogEventType.onNotificationClick, event);
		});
		eventEmitter?.addListener(AnagogEventType.onSnapshotReport, (event) => {
			AnagogLogger.info('Event received: ' + AnagogEventType.onSnapshotReport + (event ? ' ' + JSON.stringify(event ?? {}) : ''));
			listener(AnagogEventType.onSnapshotReport, event);
		});
		eventEmitter?.addListener(AnagogEventType.onEncodedEnrichmentReport, (event) => {
			AnagogLogger.info('Event received: ' + AnagogEventType.onEncodedEnrichmentReport + (event ? ' ' + JSON.stringify(event ?? {}) : ''));
			listener(AnagogEventType.onEncodedEnrichmentReport, event);
		});
		eventEmitter?.addListener(AnagogEventType.onStreamConnected, (event) => {
			AnagogLogger.info('Event received: ' + AnagogEventType.onStreamConnected + (event ? ' ' + JSON.stringify(event ?? {}) : ''));
			listener(AnagogEventType.onStreamConnected, event);
		});
		eventEmitter?.addListener(AnagogEventType.onJedAIStatusChange, (event) => {
			const status = event["status"];
			AnagogLogger.info('Event received: ' + AnagogEventType.onJedAIStatusChange + (event ? ' ' + JSON.stringify(event ?? {}) : ''));
			if (status === true) {
				listener(AnagogEventType.onJedAIStatusChange, JedAIStatus.active);
			}
			else if (status === false) {
				listener(AnagogEventType.onJedAIStatusChange, JedAIStatus.passive);
			}
			else {
				listener(AnagogEventType.onJedAIStatusChange, JedAIStatus.unknown);
			}
		});
		eventEmitter?.addListener(AnagogEventType.onBestMomentEvent, (event) => {
			AnagogLogger.info('Event received: ' + AnagogEventType.onBestMomentEvent);
			listener(AnagogEventType.onBestMomentEvent, event);
		});

		// Notify to native side that there is a listener
		JedAIModule.streamIsReady();
	}

	/**
	 * Set String custom micro segment value.
	 * @param customName Name of your custom microsegment.
	 * @param value Value that should be saved.
	 * @returns `Promise` with no parameters.
	 */
	static setUserDefinedString(customName: string, value: string): Promise<void> {
		return JedAIModule.setUserDefinedString(customName, value);
	}

	/**
	 * Get String custom micro segment.
	 * @async
	 * @param customName Name of your custom microsegment.
	 * @returns `Promise<string>` with a stored value.
	 */
	static getUserDefinedString(customName: string): Promise<string> {
		return JedAIModule.getUserDefinedString(customName);
	}

	/**
	 * Set Integer custom micro segment value.
	 * @param customName Name of your custom microsegment.
	 * @param value Value that should be saved.
	 * @returns `Promise` with no parameters.
	 */
	static setUserDefinedInteger(customName: string, value: number): Promise<void> {
		return JedAIModule.setUserDefinedInteger(customName, value);
	}

	/**
	 * Get Integer custom micro segment.
	 * @async
	 * @param customName Name of your custom microsegment.
	 * @returns `Promise<number>` with a stored value.
	 */
	static getUserDefinedInteger(customName: string): Promise<number> {
		return JedAIModule.getUserDefinedInteger(customName);
	}

	/**
	 * Set Decimal custom micro segment value.
	 * @param customName Name of your custom microsegment.
	 * @param value Value that should be saved.
	 * @returns `Promise` with no parameters.
	 */
	static setUserDefinedDecimal(customName: string, value: number): Promise<void> {
		return JedAIModule.setUserDefinedDecimal(customName, value);
	}

	/**
	 * Get Decimal custom micro segment.
	 * @async
	 * @param customName Name of your custom microsegment.
	 * @returns `Promise<number>` with a stored value.
	 */
	static getUserDefinedDecimal(customName: string): Promise<number> {
		return JedAIModule.getUserDefinedDecimal(customName);
	}


	/**
	 * Get Stats from Edge SDK.
	 * @async
	 * @param metricName Name of metric.
	 * @param index1 index1 of metric.
	 * @param index2 index2 of metric.
	 * @param timeFrame timeFrame for requested stats such as 'OVERALL', 'LAST_7_DAYS'.
	 * @returns `Promise<string>` with a stored value.
	 */
	static getStats(metricName: string, index1?: string, index2?: string, timeFrame?: TimeFrame): Promise<any> {
		return JedAIModule.getStats(metricName, index1, index2, timeFrame?.toString());
	}

	/**
	 * Use to fire micromoments from your app.
	 * @param micromoment ApplicationEvent object.
	 * @see {@link https://www.npmjs.com/package/@anagog/jedai#Micromoments example}
	 * @returns `Promise` with no parameters.
	 */
	static fireMicromoment(micromoment: ApplicationEvent): Promise<void> {
		return micromoment.fire()
	}

	/**
	 * Report user interaction event to JedAI (e.g. Triggered, Conversion, Clicked etc.).
	 * @param event `JEMAUserInteractionEvent`.
	 * @see {@link https://www.npmjs.com/package/@anagog/jedai#Interaction-events example}
	 * @returns `Promise` with no parameters.
	 */
	static sendUserInteractionEvent(event: JEMAUserInteractionEvent): Promise<void> {
		return event.send();
	}

	/**
	 * Request to generate Microsegments Snapshot report.
	 * @returns `Promise` with a generated report.
	 */
	static requestMicrosegmentsSnapshotReport(): Promise<any> {
		return JedAIModule.requestMicrosegmentsSnapshotReport();
	}

	/**
	 * Request to generate Encoded Enrichment report.
	 * @returns `Promise` with a generated report.
	 */
	static requestEncodedEnrichmentReport(): Promise<any> {
		return JedAIModule.requestEncodedEnrichmentReport();
	}

	/**
	 * Request to export data enrichment
	 * @returns `Promise` with a generated report.
	 */
	static exportDataEnrichment(requestedMetrics?: string[]): Promise<any> {
		return JedAIModule.exportDataEnrichment(requestedMetrics);
	}

	/**
	 * @deprecated This method is deprecated and will be removed in the future releases.
	 * Use `AnagogSDK.shareFeedback` instead.
	 */
	static share(): Promise<void> {
		return this.shareFeedback();
	}

	/**
	 * Create and share SDK feedback report.
	 * Use this in case you want to share with Anagog SDK operation and debugging report for analyze.
	 * @returns `Promise` with no parameters. Returned when report is generated and share window closed.
	 */
	static shareFeedback(): Promise<void> {
		return JedAIModule.shareFeedback();
	}

	/**
	 * Create SDK feedback report.
	 * Use this in case you want to create a feedback report zip file and share it by your self.
	 * @returns `Promise` with a string parameter that represents a URL with the saved zip file. Returned when report is generated and ready for send.
	 */
	static generateFeedback(): Promise<string> {
		return JedAIModule.generateFeedback();
	}

	/**
	 * Enable and start JedAI.
	 * @returns `Promise` with no parameters. Returned when JedAI is ready.
	 */
	static enableSDK(): Promise<void> {
		AnagogLogger.info('Enable SDK');
		return JedAIModule.enableJedAI();
	}

	/**
	 * Disable and stop JedAI.
	 * @returns `Promise` with no parameters. Returned when JedAI is completely disabled.
	 */
	static disableSDK(): Promise<void> {
		AnagogLogger.info('Disable SDK');
		return JedAIModule.disableJedAI();
	}

	/**
	 * Disable and stop JedAI. Also, all stored data by JedAI will be removed.
	 * @returns `Promise` with no parameters. Returned when JedAI is completely disabled.
	 */
	static disableAndPurgeSDK(): Promise<void> {
		AnagogLogger.info('Disable and purge SDK');
		return JedAIModule.disableAndPurgeJedAI();
	}

	/**
	 * Indicates if JedAI srtarted or not.
	 * @returns `Promise<JedAIStatus>` with JedAI status parameter.
	 */
	static getSDKStatus(): Promise<JedAIStatus> {
		return JedAIModule.getJedAIStatus()
			.then((status: boolean) => {
				if (status === true)
					return JedAIStatus.active;
				else if (status === false)
					return JedAIStatus.passive;
				return JedAIStatus.unknown;
			});
	}

	/**
	 * Get JedAI Version.
	 * @returns `Promise<string>` with JedAI version.
	 */
	static getSDKVersion(): Promise<string> {
		return JedAIModule.getVersion();
	}

	/**
	 * Deliver Anagog FCM message to Anagog SDK (Android only).
	 * @returns `Promise<boolean>` true if its an Anagog FCM message, otherwize false
	 */
	// static handleFcmMessageIfRequired (remoteMessage : Object) : Promise<boolean> {
	// 	console.log("handleFcmMessageIfRequired: " + JSON.parse(JSON.stringify(remoteMessage)) + ",remoteMessage: " + JSON.stringify(remoteMessage));
	// 	let data = (new Map(Object.entries(remoteMessage))).get('data');
	// 	let dataMap = new Map(Object.entries(data));
	// 	if(Platform.OS === 'android' && dataMap.has(ANAGOG_FCM_INDICATION)) {
	// 		//Return true no matter if SDK succeed to handler
	// 	  return JedAIModule.onPushNotificationReceived(data).then(() => true).catch(() => true);
	// 	} else {
	// 	  return Promise.resolve(false);
	// 	}
	// }

	/**
	 * Deliver Anagog FCM message to Anagog SDK (Android only).
	 * @returns `Promise<boolean>` result from native api of message process
	 */
	static onPushNotificationReceived(remoteMessage: Object) : Promise<boolean>{
		AnagogLogger.info('onPushNotificationReceived called');
		if(Platform.OS === 'android'){ 
			return JedAIModule.onPushNotificationReceived(remoteMessage);
		}
		return Promise.reject("Not supported in IOS");
	}

}

function sendInfoToSDK() {
	if (Platform.OS === 'ios') {
		try {
			let json = {
				version: PACKAGE_VERSION
			};
			let string = JSON.stringify(json);
			JedAIModule.information(string);
		} catch(error) {
			console.log("information error", error);
		}
	}
}