/** @file
 * @author Edouard DUPIN
 * @copyright 2018, Edouard DUPIN, all right reserved
 * @license PROPRIETARY (see license file)
 */

import { Component, OnInit } from '@angular/core';
import { PopInService, UploadProgress } from '@kangaroo-and-rabbit/kar-cw';
import { Series } from 'app/back-api';
import { RESTAbort } from 'app/back-api/rest-tools';

import { TypeService, SeriesService, MediaService, SeasonService } from 'app/service';

export class ElementList {
	constructor(
		public value: number,
		public label: string) {
		// nothing to do.
	}
}
export class FileParsedElement {
	public isSended: boolean = false;
	public nameDetected: boolean = false;
	public episodeDetected: boolean = false;
	constructor(
		public id: number,
		public file: File,
		public series: string,
		public season: number,
		public episode: number,
		public title: string) {
		// nothiing to do.
	}
}
export class FileFailParsedElement {
	constructor(
		public file: File,
		public reason: string) {
		// nothiing to do.
	}
}

@Component({
	selector: 'app-video-edit',
	templateUrl: './upload.html',
	styleUrls: ['./upload.less']
})

export class UploadScene implements OnInit {
	parsedElement: FileParsedElement[] = [];
	parsedFailedElement: FileFailParsedElement[] = [];
	uploadFileValue: string = '';
	selectedFiles: FileList;
	typeId: number = null;
	seriesId: number = null;
	seasonId: number = null;
	needSend: boolean = false;

	// list of all files already registered in the bdd to compare with the current list of files.
	listFileInBdd: any = null;

	// section tha define the upload value to display in the pop-in of upload
	public upload: UploadProgress = new UploadProgress();

	listType: ElementList[] = [
		{ value: null, label: '---' },
	];
	listSeries: ElementList[] = [
		{ value: null, label: '---' },
	];
	listSeries2 = [{ id: null, description: '---' }];

	/*
	  config = {
				displayKey: "label", // if objects array passed which key to be displayed defaults to description
				search: true,
				limitTo: 3,
			  };
	  */
	config = {
		displayKey: 'description', // if objects array passed which key to be displayed defaults to description
		search: true, // true/false for the search functionality defaults to false,
		height: 'auto', // height of the list so that if there are more no of items it can show a scroll defaults to auto. With auto height scroll will never appear
		placeholder: 'Select', // text to be displayed when no item is selected defaults to Select,
		customComparator: () => { }, // a custom function using which user wants to sort the items. default is undefined and Array.sort() will be used in that case,
		limitTo: 10, // number thats limits the no of options displayed in the UI (if zero, options will not be limited)
		moreText: 'more', // text to be displayed whenmore than one items are selected like Option 1 + 5 more
		noResultsFound: 'No results found!', // text to be displayed when no items are found while searching
		searchPlaceholder: 'Search', // label thats displayed in search input,
		searchOnKey: 'description', // key on which search should be performed this will be selective search. if undefined this will be extensive search on all keys
	};
	listSeason: ElementList[] = [
		{ value: null, label: '---' },
	];
	globalSeries: string = '';
	globalSeason: number = null;
	cancelHandle: RESTAbort = {};
	dataUniqueId: number = 0;
	constructor(
		private MediaService: MediaService,
		private seasonService: SeasonService,
		private seriesService: SeriesService,
		private typeService: TypeService,
		private popInService: PopInService,
	) {
		// nothing to do.
	}

	updateNeedSend(): boolean {
		if (this.parsedElement.length === 0) {
			this.needSend = false;
			return;
		}
		this.needSend = true;
		for (let iii = 0; iii < this.parsedElement.length; iii++) {
			if (this.parsedElement[iii].title === undefined || this.parsedElement[iii].title === null || this.parsedElement[iii].title === '') {
				this.needSend = false;
			}
		}
		if (this.typeId === undefined || this.typeId === null) {
			this.needSend = false;
		}
		return this.needSend;
	}

	ngOnInit() {
		let self = this;
		this.listType = [{ value: null, label: '---' }];
		this.listSeries = [{ value: null, label: '---' }];
		this.listSeason = [{ value: null, label: '---' }];
		this.typeService.gets()
			.then((response2) => {
				for (let iii = 0; iii < response2.length; iii++) {
					self.listType.push({ value: response2[iii].id, label: response2[iii].name });
				}
			}).catch((response2) => {
				console.log(`get response22 : ${JSON.stringify(response2, null, 2)}`);
			});
		console.log(' END INIT ');
	}

	onChangeType(value: any): void {
		this.seriesId = null;
		this.updateType(value);
	}

	private updateType(value: any): void {
		console.log(`Change requested of type ... ${value}`);
		if (this.typeId === value) {
			return;
		}
		this.typeId = value;
		// this.data.series_id = null;
		// this.data.season_id = null;
		this.listSeries = [{ value: null, label: '---' }];
		this.listSeason = [{ value: null, label: '---' }];
		let self = this;
		this.updateNeedSend();
		if (this.typeId !== null) {
			self.seriesService.getSeriesWithType(this.typeId)
				.then((response2: Series[]) => {
					for (let iii = 0; iii < response2.length; iii++) {
						self.listSeries.push({ value: response2[iii].id, label: response2[iii].name });
					}
				}).catch((response2) => {
					console.log(`get response22 : ${JSON.stringify(response2, null, 2)}`);
				});
		}
	}

	onChangeSeries(value: any): void {
		this.seriesId = value;
		if (!(value === undefined || value === null)) {
			for (let iii = 0; iii < this.listSeries.length; iii++) {
				if (this.listSeries[iii].value === value) {
					this.globalSeries = this.listSeries[iii].label;
					break;
				}
			}
		}
		this.updateNeedSend();
		this.updateListOfVideoToCheck();
	}
	onSeason(value: any): void {
		this.globalSeason = value;
		// console.log("change episode ID: " + value + " ==> " + this.parseSeason.toString());
		this.updateNeedSend();
		this.updateListOfVideoToCheck();
	}

	onTitle(data: FileParsedElement, value: any): void {
		data.title = value;
		this.updateNeedSend();
	}
	removeElmentFromList(data: FileParsedElement, value: any): void {
		for (let iii = 0; iii < this.parsedElement.length; iii++) {
			if (this.parsedElement[iii] === data) {
				this.parsedElement.splice(iii, 1);
				break;
			}
		}
		this.parsedFailedElement.push(new FileFailParsedElement(data.file, 'Removed by user.'));
		this.updateNeedSend();
	}

	onEpisode(data: FileParsedElement, value: any): void {
		data.episode = value;
		// console.log("change episode ID: " + value + " ==> " + this.parseEpisode.toString());
		this.updateNeedSend();
	}

	onSeries(value: any): void {
		this.globalSeries = value;
		let self = this;
		if (this.globalSeries !== '') {
			this.seriesService.getLike(this.globalSeries)
				.then((response: any[]) => {
					console.log(`find element: ${response.length}`);
					for (let iii = 0; iii < response.length; iii++) {
						console.log(`    - ${JSON.stringify(response[iii])}`);
					}
					if (response.length === 0) {
						self.seriesId = null;
					} else if (response.length === 1) {
						self.seriesId = response[0].id;
					}
					self.updateListOfVideoToCheck();
				}).catch((response) => {
					console.log('CAN NOT find element: ');
					self.seriesId = null;
				});
		}
		this.updateNeedSend();
	}


	clearData() {
		this.globalSeries = '';
		this.globalSeason = null;
		this.parsedElement = [];
		this.parsedFailedElement = [];
		this.listFileInBdd = null;

		this.typeId = null;
		this.seriesId = null;
		this.seasonId = null;
		this.listSeries = [{ value: null, label: '---' }];
		this.listSeason = [{ value: null, label: '---' }];
	}

	addFileWithMetaData(file: File) {
		// parsedElement: FileParsedElement[] = [];
		let series: string = null;
		let season: number | null = null;
		let episode: number | null = null;
		let title: string = '';

		console.log(`select file ${file.name}`);
		let tmpName = file.name.replace(/[ \t]*-[ \t]*/g, '-');
		tmpName = tmpName.replace(/[Ss]([0-9]+)[- \t]+[Ee]([0-9]+)/g, '-s$1-e$2-');
		tmpName = tmpName.replace(/[Ee]([0-9]+)[- \t]+[Ss]([0-9]+)/g, '-s$2-e$1-');
		tmpName = tmpName.replace(/_/g, '-');
		tmpName = tmpName.replace(/--/g, '-');
		console.log(`select file ${tmpName}`);
		const splitElement = tmpName.split('-');
		if (splitElement.length === 1) {
			title = splitElement[0];
		} else {
			if (splitElement.length >= 2) {
				series = splitElement[0];
			}
			splitElement.splice(0, 1);
			if (splitElement.length === 1) {
				title = splitElement[0];
			} else {
				while (splitElement.length > 0) {
					let element = splitElement[0];
					let find = false;
					if (season === null) {
						if (element.length >= 1 && (element[0] === 's' || element[0] === 'S')) {
							element = element.substring(1);
							season = parseInt(element, 10);
							find = true;
						}
					}
					if (episode === null && find === false) {
						if (element.length >= 1 && (element[0] === 'e' || element[0] === 'E')) {
							element = element.substring(1);
							episode = parseInt(element, 10);
							find = true;
						}
					}
					if (find === false) {
						if (title === '') {
							title = element;
						} else {
							title = `${title}-${element}`;
						}
					}
					splitElement.splice(0, 1);
				}
			}
		}
		if (isNaN(episode)) {
			episode = null;
		}
		if (isNaN(season)) {
			season = null;
		}
		// remove extension
		title = title.replace(new RegExp('\\.(mkv|MKV|Mkv|webm|WEBM|Webm|mp4)'), '');
		const tmp = new FileParsedElement(this.dataUniqueId++, file, series, season, episode, title);
		console.log(`==>${JSON.stringify(tmp)}`);
		// add it in the list.
		this.parsedElement.push(tmp);
	}

	// At the file input element
	// (change)="selectFile($event)"
	onChangeFile(files: File[]): void {
		this.clearData();

		for (let iii = 0; iii < files.length; iii++) {
			this.addFileWithMetaData(files[iii]);
		}
		// check if all global parameters are generic:
		if (this.parsedElement.length === 0) {
			this.updateNeedSend();
			return;
		}
		// clean different series:
		for (let iii = 1; iii < this.parsedElement.length; iii++) {
			console.log(`check series [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[0].series} !== ${this.parsedElement[iii].series}'`);
			if (this.parsedElement[0].series !== this.parsedElement[iii].series) {
				this.parsedFailedElement.push(new FileFailParsedElement(this.parsedElement[iii].file, 'Remove from list due to wrong series value'));
				console.log(`Remove from list (!= series) : [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[iii].file.name}'`);
				this.parsedElement.splice(iii, 1);
				iii--;
			}
		}
		// clean different season:
		for (let iii = 1; iii < this.parsedElement.length; iii++) {
			console.log(`check season [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[0].season} !== ${this.parsedElement[iii].season}'`);
			if (this.parsedElement[0].season !== this.parsedElement[iii].season) {
				this.parsedFailedElement.push(new FileFailParsedElement(this.parsedElement[iii].file, 'Remove from list due to wrong season value'));
				console.log(`Remove from list (!= season) : [${iii + 1}/${this.parsedElement.length}] '${this.parsedElement[iii].file.name}'`);
				this.parsedElement.splice(iii, 1);
				iii--;
			}
		}
		console.log(`check : ${JSON.stringify(this.parsedElement[0])}`)
		this.globalSeries = this.parsedElement[0].series ?? '';
		this.globalSeason = this.parsedElement[0].season ?? null;

		this.updateNeedSend();
		this.seriesId = null;
		this.seasonId = null;
		let self = this;
		if (this.globalSeries !== '') {
			this.seriesService.getLike(this.globalSeries)
				.then((response: any[]) => {
					console.log(`find element: ${response.length}`);
					for (let iii = 0; iii < response.length; iii++) {
						console.log(`    - ${JSON.stringify(response[iii])}`);
					}
					if (response.length === 0) {
						self.seriesId = null;
					} else if (response.length === 1) {
						let seriesElem = response[0];
						self.seriesId = seriesElem.id;
						self.updateType(seriesElem.parentId);
					}
					self.updateListOfVideoToCheck();
				}).catch((response) => {
					console.log('CAN NOT find element: ');
				});
		}
	}


	sendFile(): void {
		console.log(`Send file requested ... ${this.parsedElement.length}`);
		this.upload = new UploadProgress();
		// display the upload pop-in
		this.popInService.open('popin-upload-progress');
		this.globalUpLoad(0, this.parsedElement.length);
	}

	globalUpLoad(id: number, total: number): void {
		let self = this;
		this.uploadFile(this.parsedElement[id], id, total, () => {
			let id2 = id + 1;
			if (id2 < total) {
				self.globalUpLoad(id2, total);
			} else {
				self.upload.result = 'Media creation done';
			}
		}, (value: string) => {
			console.log("Detect error from serveur ...********************");
			self.upload.error = `Error in the upload of the data...${value}`;
		});
	}
	uploadFile(element: FileParsedElement, id: number, total: number, sendDone: () => void, errorOccurred: (string) => void): void {
		let self = this;

		self.upload.labelMediaTitle = '';
		// add series
		if (self.globalSeries !== null) {
			if (self.upload.labelMediaTitle.length !== 0) {
				self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}:`;
			}
			self.upload.labelMediaTitle = self.upload.labelMediaTitle + self.globalSeries;
		}
		// add season
		if (self.globalSeason !== null && self.globalSeason !== undefined && self.globalSeason.toString().length !== 0) {
			if (self.upload.labelMediaTitle.length !== 0) {
				self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}-`;
			}
			self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}s${self.globalSeason.toString()}`;
		}
		// add episode ID
		if (element.episode !== null && element.episode !== undefined && element.episode.toString().length !== 0) {
			if (self.upload.labelMediaTitle.length !== 0) {
				self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}-`;
			}
			self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}e${element.episode.toString()}`;
		}
		// add title
		if (self.upload.labelMediaTitle.length !== 0) {
			self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}-`;
		}
		self.upload.labelMediaTitle = `[${id + 1}/${total}]${self.upload.labelMediaTitle}${element.title}`;

		self.MediaService.uploadFile(element.file,
			self.globalSeries,
			self.seriesId,
			self.globalSeason,
			element.episode,
			element.title,
			self.typeId,
			(count, totalTmp) => {
				// console.log("upload : " + count*100/totalTmp);
				self.upload.mediaSendSize = count;
				self.upload.mediaSize = totalTmp;
			}, this.cancelHandle)
			.then((response) => {
				console.log(`get response of video : ${JSON.stringify(response, null, 2)}`);
				sendDone();
			})
			.catch((response) => {
				// self.error = "Can not get the data";
				console.log('Can not add the data in the system...');
				errorOccurred(JSON.stringify(response, null, 2));
			});
	}

	public checkSimilarString(valueA: string, valueB: string): boolean {
		let valueAL = valueA.toLowerCase();
		let valueBL = valueB.toLowerCase();
		valueAL = valueAL.replace(/[ \t\n\r-_#~@]/g, '');
		valueBL = valueBL.replace(/[ \t\n\r-_#~@]/g, '');
		if (valueAL === valueBL) {
			return true;
		}
		if (valueAL.startsWith(valueBL)) {
			return true;
		}
		if (valueBL.startsWith(valueAL)) {
			return true;
		}
		return false;
	}

	checkConcordence(): void {
		if (this.parsedElement === null) {
			return;
		}
		// ckear checker
		for (let iii = 0; iii < this.parsedElement.length; iii++) {
			this.parsedElement[iii].nameDetected = false;
			this.parsedElement[iii].episodeDetected = false;
		}
		if (this.listFileInBdd === null) {
			return;
		}
		for (let iii = 0; iii < this.listFileInBdd.length; iii++) {
			this.listFileInBdd[iii].nameDetected = false;
			this.listFileInBdd[iii].episodeDetected = false;
		}
		for (let iii = 0; iii < this.parsedElement.length; iii++) {
			for (let jjj = 0; jjj < this.listFileInBdd.length; jjj++) {
				if (this.checkSimilarString(this.parsedElement[iii].title, this.listFileInBdd[jjj].name)) {
					this.parsedElement[iii].nameDetected = true;
					this.listFileInBdd[jjj].nameDetected = true;
				}
				if (this.parsedElement[iii].episode === this.listFileInBdd[jjj].episode) {
					this.parsedElement[iii].episodeDetected = true;
					this.listFileInBdd[jjj].episodeDetected = true;
				}
			}
		}
	}

	updateListOfVideoToCheck(): void {
		// No series ID set ==> nothing to do.
		if (this.seriesId === null) {
			this.listFileInBdd = null;
			return;
		}
		let self = this;
		// no season check only the series files.
		if (this.globalSeason === null) {
			self.seriesService.getVideo(self.seriesId)
				.then((response: any[]) => {
					self.listFileInBdd = response;
					// console.log("find video: " + response.length);
					// for (let iii = 0; iii<response.length; iii++) {
					//	console.log("    - " + JSON.stringify(response[iii]));
					// }
					self.checkConcordence();
				}).catch((response) => {
					self.listFileInBdd = null;
				});
			return;
		}

		self.seasonId = null;
		// set 1 find the ID of the season:
		this.seriesService.getSeason(this.seriesId)
			.then((response: any[]) => {
				// console.log("find season: " + response.length);
				for (let iii = 0; iii < response.length; iii++) {
					// console.log("    - " + JSON.stringify(response[iii]) + 'compare with : ' + JSON.stringify(self.globalSeason));
					if (response[iii].name === `${self.globalSeason}`) {
						self.seasonId = response[iii].id;
						break;
					}
				}
				if (self.seasonId === null) {
					return;
				}
				self.seasonService.getVideo(self.seasonId)
					.then((response2: any[]) => {
						self.listFileInBdd = response2;
						// console.log("find video: " + response2.length);
						// for (let iii = 0; iii<response2.length; iii++) {
						//	console.log("    - " + JSON.stringify(response2[iii]));
						// }
						self.checkConcordence();
					}).catch((response3) => {
						self.listFileInBdd = null;
					});
			}).catch((response4) => {
				self.listFileInBdd = null;
			});
	}

	abortUpload(): void {
		this.cancelHandle.abort();
	}

	eventPopUpSeason(event: string): void {
		console.log(`GET event: ${event}`);
		this.popInService.close('popin-new-season');
	}
	eventPopUpSeries(event: string): void {
		console.log(`GET event: ${event}`);
		this.popInService.close('popin-new-series');
	}
	eventPopUpType(event: string): void {
		console.log(`GET event: ${event}`);
		this.popInService.close('popin-new-type');
	}

	newSeason(): void {
		console.log('Request new Season...');
		this.popInService.open('popin-new-season');
	}
	newSeries(): void {
		console.log('Request new Series...');
		this.popInService.open('popin-new-series');
	}
	newType(): void {
		console.log('Request new Type...');
		this.popInService.open('popin-create-type');
	}
}
function isNullOrUndefined(abort: () => boolean) {
	throw new Error('Function not implemented.');
}

