// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { RequestParams } from './DataType';

enum HTML5_MEDIA_EVENT {
	'PLAY' = 'play',
	'PAUSE' = 'pause',
	'ENDED' = 'Ended',
}
enum MEDIA_TYPE {
	'IFRAME' = 'IFRAME',
	'VIDEO' = 'VIDEO',
	'AUDIO' = 'AUDIO',
}
enum EVENT_TYPE {
	'PLAY' = 'Play',
	'ENDED' = 'Ended',
	'PAUSE' = 'Pause',
	'TIME_WATCHED' = 'TimeWatched',
}

export class MediaAutoTrack {
	private _mediaElement;
	private _provider;
	private _params;
	private _started;
	private _iframePlayer;
	private eventActionMapping = {
		[EVENT_TYPE.ENDED]: this.endedEventAction.bind(this),
		[EVENT_TYPE.PLAY]: this.playEventAction.bind(this),
		[EVENT_TYPE.PAUSE]: this.pauseEventAction.bind(this),
	};

	private _youTubeIframeLoader;

	constructor(params: RequestParams, provider) {
		const { eventData } = params;
		this._params = params;
		this._mediaElement = document.getElementById(
			eventData.properties['domElementId']
		);
		this._started = false;
		this._provider = provider;
		const mediaTrackFunMapping = {
			IFRAME: this._iframeMediaTracker,
			VIDEO: this._html5MediaTracker,
			AUDIO: this._html5MediaTracker,
		};

		mediaTrackFunMapping[this._mediaElement.tagName].bind(this)();

		this._initYoutubeFrame();
	}

	private _initYoutubeFrame() {
		this._youTubeIframeLoader = {
			src: 'https://www.youtube.com/iframe_api',
			loading: false,
			loaded: false,
			listeners: [],

			load(callback) {
				const _this = this;
				this.listeners.push(callback);

				if (this.loaded) {
					setTimeout(function() {
						_this.done();
					});
					return;
				}

				if (this.loading) {
					return;
				}

				this.loading = true;

				window['onYouTubeIframeAPIReady'] = function() {
					_this.loaded = true;
					_this.done();
				};

				const script = document.createElement('script');
				script.type = 'text/javascript';
				script.src = this.src;
				document.body.appendChild(script);
			},

			done() {
				delete window['onYouTubeIframeAPIReady'];

				while (this.listeners.length) {
					this.listeners.pop()(window['YT']);
				}
			},
		};
	}

	private _iframeMediaTracker(): void {
		const that = this;
		setInterval(function() {
			if (that._started) {
				that.recordEvent(MEDIA_TYPE.IFRAME, EVENT_TYPE.TIME_WATCHED);
			}
		}, 3 * 1000);
		this._youTubeIframeLoader.load(function(YT) {
			that._iframePlayer = new YT.Player(that._mediaElement.id, {
				events: { onStateChange: that._onPlayerStateChange.bind(that) },
			});
		});
	}

	private _onPlayerStateChange(event): void {
		const iframeEventMapping = {
			0: EVENT_TYPE.ENDED,
			1: EVENT_TYPE.PLAY,
			2: EVENT_TYPE.PAUSE,
		};
		const eventType = iframeEventMapping[event.data];
		if (eventType) {
			this.eventActionMapping[eventType](MEDIA_TYPE.IFRAME);
		}
	}

	private _html5MediaTracker(): void {
		const that = this;
		setInterval(function() {
			if (that._started) {
				that.recordEvent(MEDIA_TYPE.VIDEO, EVENT_TYPE.TIME_WATCHED);
			}
		}, 3 * 1000);
		this._mediaElement.addEventListener(
			HTML5_MEDIA_EVENT.PLAY,
			() => {
				that.eventActionMapping[EVENT_TYPE.PLAY](MEDIA_TYPE.VIDEO);
			},
			false
		);
		this._mediaElement.addEventListener(
			HTML5_MEDIA_EVENT.PAUSE,
			() => {
				that.eventActionMapping[EVENT_TYPE.PAUSE](MEDIA_TYPE.VIDEO);
			},
			false
		);

		this._mediaElement.addEventListener(
			HTML5_MEDIA_EVENT.ENDED,
			() => {
				that.eventActionMapping[EVENT_TYPE.ENDED](MEDIA_TYPE.VIDEO);
			},
			false
		);
	}

	private playEventAction(mediaType) {
		this._started = true;
		this.recordEvent(mediaType, EVENT_TYPE.PLAY);
	}

	private pauseEventAction(mediaType) {
		this._started = false;
		this.recordEvent(mediaType, EVENT_TYPE.PAUSE);
	}

	private endedEventAction(mediaType) {
		this._started = false;
		this.recordEvent(mediaType, EVENT_TYPE.ENDED);
	}

	private recordEvent(mediaType: string, eventType: string): void {
		const newParams = Object.assign({}, this._params);
		const { eventData } = newParams;
		eventData.eventType = eventType;
		let currentPlayTime: string;
		if (mediaType === MEDIA_TYPE.VIDEO) {
			currentPlayTime = this._mediaElement.currentTime;
			eventData.properties.duration = this._mediaElement.duration;
		} else {
			currentPlayTime = this._financial(this._iframePlayer.getCurrentTime());
			eventData.properties.duration = this._financial(
				this._iframePlayer.getDuration()
			);
		}
		const percentage =
			parseFloat(currentPlayTime) / parseFloat(eventData.properties.duration);
		eventData.properties.eventValue = Number(percentage.toFixed(4));
		delete eventData.properties.domElementId;
		this._provider.putToBuffer(newParams);
	}

	private _financial(x) {
		return Number.parseFloat(x).toFixed(4);
	}
}
