
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { ActivatedRoute, Router } from '@angular/router';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
import { GrantListingModel } from '@app/core/model/grant/grant-listing';
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component';
import { DmpCriteriaComponent } from '@app/ui/dmp/listing/criteria/dmp-criteria.component';
import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent';
import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core';
import { Observable, of as observableOf } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import { GrantService } from "@app/core/services/grant/grant.service";
import { DmpUploadDialogue } from './upload-dialogue/dmp-upload-dialogue.component';
import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { AuthService } from '@app/core/services/auth/auth.service';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { DmpCriteriaDialogComponent } from './criteria/dmp-criteria-dialog.component';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service';
import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.constants';
import { NgDialogAnimationService } from "ng-dialog-animation";
import { HttpClient } from '@angular/common/http';
import { MatomoService } from '@app/core/services/matomo/matomo-service';

@Component({
	selector: 'app-dmp-listing-component',
	templateUrl: 'dmp-listing.component.html',
	styleUrls: ['./dmp-listing.component.scss'],
})
export class DmpListingComponent extends BaseComponent implements OnInit, IBreadCrumbComponent {

	@ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator;
	@ViewChild(MatSort) sort: MatSort;
	// @ViewChild(DmpCriteriaComponent, { static: true }) criteria: DmpCriteriaComponent;

	breadCrumbs: Observable<BreadcrumbItem[]> = observableOf([{ parentComponentName: null, label: 'DMPs', url: "/plans" }]);
	itemId: string;
	grantId: string;
	showGrant: boolean;
	titlePrefix: string;
	totalCount: number;
	listingItems: DmpListingModel[] = [];
	allVersions: boolean = false;
	groupLabel: string;
	isPublic: boolean = false;
	public isVisible = true
	hasListingItems = null;

	startIndex: number = 0;
	pageSize: number = 5;

	criteria: DmpCriteria;
	criteriaFormGroup: FormGroup;
	public formGroup = new FormBuilder().group({
		like: new FormControl(),
		order: new FormControl()
	});

	scrollbar: boolean;
	order = RecentActivityOrder;
	dmpText: string;
	datasetText: string;

	constructor(
		private dmpService: DmpService,
		private router: Router,
		private route: ActivatedRoute,
		public dialogAnimation: NgDialogAnimationService,
		public dialog: MatDialog,
		public enumUtils: EnumUtils,
		private language: TranslateService,
		private grantService: GrantService,
		private uiNotificationService: UiNotificationService,
		private authService: AuthService,
		private guidedTourService: GuidedTourService,
		private httpClient: HttpClient,
		private matomoService: MatomoService
	) {
		super();
	}

	ngOnInit() {
		this.matomoService.trackPageView('DMPs');
		this.isPublic = this.router.url.startsWith('/explore-plans');
		if (this.isPublic) {
			this.formGroup.get('order').setValue(this.order.PUBLISHED);
		} else {
			this.formGroup.get('order').setValue(this.order.MODIFIED);
		}
		if (!this.isPublic && isNullOrUndefined(this.authService.current())) {
			this.router.navigateByUrl("/explore-plans");
		}
		this.route.params
			.pipe(takeUntil(this._destroyed))
			.subscribe(async params => {
				let grantLabel;
				if (params['grantId']) {
					this.grantId = params['grantId'];
					this.showGrant = true;
					this.grantService.getSingle(this.grantId)
						.subscribe((grant: GrantListingModel) => {
							// const grant: GrantListingModel = {
							// 	id: this.grantId
							// }
							// this.breadCrumbs = Observable.of([{ parentComponentName: 'GrantEditorComponent', label: grantLabel, url: '/grants/edit/' + this.grantId }]);
							grantLabel = this.route.snapshot.queryParams.grantLabel;

							this.criteria = { like: null, grants: [grant], groupIds: null, allVersions: false }
							// this.criteria.setCriteria({ like: null, grants: [grant], groupIds: null, allVersions: false });

							this.refresh();
							// this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages));
						})

				} else if (params['groupId']) {
					this.itemId = params['groupId'];
					this.showGrant = true;
					this.allVersions = true;

					this.language.get('NAV-BAR.MY-DMPS').pipe(takeUntil(this._destroyed)).subscribe(x => {
						this.breadCrumbs = observableOf([
							{
								parentComponentName: null,
								label: x,
								url: '/plans'
							}]
						);
					})
					this.groupLabel = this.route.snapshot.queryParams.groupLabel;

					// this.criteria.setCriteria(this.getDefaultCriteria());
					this.criteria = this.getDefaultCriteria();
					this.criteria.groupIds ? this.criteria.groupIds.push(this.itemId) : this.criteria.groupIds = [this.itemId];
					this.refresh();
					// this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages));
				} else {
					this.itemId = params['groupId'];
					this.showGrant = true;
					const breadCrumbs = [];

					// if (this.itemId) {
					// 	const dmplabel = this.route.snapshot.queryParams.groupLabel;
					// 	breadCrumbs.push({
					// 		parentComponentName: null,
					// 		label: this.language.instant('NAV-BAR.DMPS'),
					// 		url: '/plans'
					// 	});
					// }
					// else

					this.language.get('NAV-BAR.MY-DMPS').pipe(takeUntil(this._destroyed)).subscribe(x => {
						this.breadCrumbs = observableOf([
							{
								parentComponentName: null,
								label: x,
								url: '/plans'
							}]
						);
					})
					// this.criteria.setCriteria(this.getDefaultCriteria());
					this.criteria = this.getDefaultCriteria();
					this.refresh();
					// this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages));
				}

				if (this.grantId != null) {
					if (grantLabel !== undefined) {
						this.titlePrefix = 'for ' + grantLabel;
					}
				}

			});

		this.formGroup.get('like').valueChanges
			.pipe(takeUntil(this._destroyed), debounceTime(500))
			.subscribe(x => this.controlModified());
		this.formGroup.get('order').valueChanges
			.pipe(takeUntil(this._destroyed))
			.subscribe(x => this.refresh());
	}

	public dashboardTour: GuidedTour = {
		tourId: 'dmp-dataset-tour',
		useOrb: true,
		steps: [
			{
				selector: '.dmp-tour',
				content: 'Step 1',
				orientation: Orientation.Right,
				isStepUnique: false
			},
			{
				selector: '.dataset-tour',
				content: 'Step 2',
				orientation: Orientation.Right,
				isStepUnique: false
			}
		]
	};

	public isAuthenticated(): boolean {
		return !(!this.authService.current());
	}

	ngAfterContentChecked(): void {
		this.scrollbar = this.hasScrollbar();
	}

	openTour() {
		this.language.get('DMP-LISTING.TEXT-INFO').pipe(takeUntil(this._destroyed)).subscribe((x: string) => {
			this.dashboardTour.steps[0].title = x + '\n\n' +
				this.language.instant('DMP-LISTING.TEXT-INFO-QUESTION') + ' ' +
				this.language.instant('DMP-LISTING.LINK-ZENODO') + ' ' +
				this.language.instant('DMP-LISTING.GET-IDEA');

			this.dashboardTour.steps[1].title = this.language.instant('DATASET-LISTING.TEXT-INFO') +
				this.language.instant('DATASET-LISTING.LINK-PUBLIC-DATASETS') + ' ' +
				this.language.instant('DATASET-LISTING.TEXT-INFO-REST') + '\n\n' +
				this.language.instant('DATASET-LISTING.TEXT-INFO-PAR');

			this.guidedTourService.startTour(this.dashboardTour);
		});
	}

	public refresh(resetPages = false) {
		// if (this._paginator.pageSize === undefined) this._paginator.pageSize = 10;
		// if (resetPages) this._paginator.pageIndex = 0;
		// const startIndex = this._paginator.pageIndex * this._paginator.pageSize;

		// let fields: Array<string> = new Array();
		// if (this.sort && this.sort.active) { fields = this.sort.direction === 'asc' ? ['+' + this.sort.active] : ['-' + this.sort.active]; }
		// fields.push('-modified');
		const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
		this.startIndex = 0;

		const request = new DataTableRequest<DmpCriteria>(this.startIndex, this.pageSize, { fields: fields });
		this.setPublicCriteria();
		request.criteria = this.criteria;

		this.dmpService.getPaged(request, "listing").pipe(takeUntil(this._destroyed)).subscribe(result => {
			if (!result) { return []; }
			result.data.map(item => {
				item['datasets'].map(dmp => {
					dmp.url = 'datasets/edit/' + dmp.url;
					dmp.all = 'datasets/dmp/' + item.id;
					return dmp;
				});
				return item;
			});
			this.listingItems = result.data;
			this.hasListingItems = true;
			if (!this.isPublic && this.listingItems.length === 0 && !this.hasCriteria() && !this.hasLikeCriteria()) {
				this.openTour();
			}
			this.totalCount = result.totalCount;
		});
	}

	public loadMore() {
		this.startIndex = this.startIndex + this.pageSize;
		// const fields: Array<string> = ["-modified"];
		const fields: Array<string> = [((this.formGroup.get('order').value === 'status') || (this.formGroup.get('order').value === 'label') ? '+' : "-") + this.formGroup.get('order').value];
		const request = new DataTableRequest<DmpCriteria>(this.startIndex, this.pageSize, { fields: fields });
		this.setPublicCriteria();
		request.criteria = this.criteria;

		this.dmpService.getPaged(request, "listing").pipe(takeUntil(this._destroyed)).subscribe(result => {
			if (!result) { return []; }
			result.data.map(item => {
				item['datasets'].map(dmp => {
					dmp.url = 'datasets/edit/' + dmp.url;
					dmp.all = 'datasets/dmp/' + item.id;
					return dmp;
				});
				return item;
			});
			// this.listingItems = this.listingItems.concat(result.data);
			this.listingItems = this.mergeTwoSortedLists(this.listingItems, result.data, this.formGroup.get('order').value);
			this.hasListingItems = true;
		});
	}

	pageThisEvent(event) {
		this.refresh();
	}

	hasCriteria(): boolean {
		if (this.criteria.organisations && this.criteria.organisations.length > 0 ||
			this.criteria.grants && this.criteria.grants.length > 0 ||
			this.criteria.collaborators && this.criteria.collaborators.length > 0 ||
			this.criteria.datasetTemplates && this.criteria.datasetTemplates.length > 0 ||
			this.criteria.onlyPublic === true
		) { return true; } else { return false; }
	}

	controlModified(): void {
		// this.clearErrorModel();
		// if (this.refreshCallback != null &&
		// 	(this.formGroup.get('like').value == null || this.formGroup.get('like').value.length === 0 || this.formGroup.get('like').value.length > 2)
		// ) {
		// 	setTimeout(() => this.refreshCallback(true));
		// }
		this.criteria.like = this.formGroup.get("like").value;
		this.startIndex = 0;
		this.refresh();
	}

	// rowClicked(dmp: DmpListingModel) {
	// 	this.router.navigate(['/plans/overview/' + dmp.id]);
	// }

	public closeCard(): void {
		this.isVisible = false;
	}

	// addDataset(rowId: String) {
	// 	this.router.navigate(['/datasets/new/' + rowId]);
	// }

	showDatasets(rowId: String, rowLabel: String) {
		this.router.navigate(['/datasets/dmp/' + rowId, { dmpLabel: rowLabel }]);
	}

	viewVersions(rowId: String, rowLabel: String) {
		this.router.navigate(['/plans/versions/' + rowId], { queryParams: { groupLabel: rowLabel } });
	}

	getDefaultCriteria(): DmpCriteria {
		const defaultCriteria = new DmpCriteria();
		if (this.isPublic) {
			defaultCriteria.isPublic = true;
			defaultCriteria.onlyPublic = true;
		}
		if (this.allVersions) {
			defaultCriteria.allVersions = true;
		}
		return defaultCriteria;
	}

	openShareDialog(rowId: any, rowName: any) {
		const dialogRef = this.dialog.open(DmpInvitationDialogComponent, {
			autoFocus: false,
			data: {
				dmpId: rowId,
				dmpName: rowName
			}
		});
	}

	fileSave(event) {
		const dialogRef = this.dialog.open(DmpUploadDialogue, {
			data: {
				fileList: FileList,
				success: Boolean,
				dmpTitle: String
			}
		});
		dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
			if (result && result.success) {
				this.dmpService.uploadXml(result.fileList[0], result.dmpTitle, result.dmpProfiles)
					.pipe(takeUntil(this._destroyed))
					.subscribe((complete) => this.onCallbackImportComplete(),
						(error) => this.onCallbackImportFail(error.error));
			}
		});
	}

	private onCallbackImportComplete() {
		this.uiNotificationService.snackBarNotification(this.language.instant('DMP-UPLOAD.UPLOAD-SUCCESS'), SnackBarNotificationLevel.Success);
		this.router.navigate(['/reload']).then(() => this.isPublic ? this.router.navigate(['/explore-plans']) : this.router.navigate(['/plans']));
	}

	private onCallbackImportFail(error: any) {
		this.uiNotificationService.snackBarNotification(error.message, SnackBarNotificationLevel.Error);
	}

	openFiltersDialog(): void {
		const dialogRef = this.dialog.open(DmpCriteriaDialogComponent, {
			width: '456px',
			height: '100%',
			id: 'filters',
			restoreFocus: false,
			data: {
				showGrant: this.showGrant,
				isPublic: this.isPublic,
				criteria: this.criteria,
				formGroup: this.criteriaFormGroup,
				// criteria: this.grantId ? this.criteria : this.getDefaultCriteria(),
				updateDataFn: this.updateDataFn.bind(this)
			},
			position: { right: '0px;' },
			panelClass: 'dialog-side-panel',
			// may remove NgDialogAnimationService package
			// animation: {
			// 	to: "left",
			// 	incomingOptions: {
			// 		keyframeAnimationOptions: { duration: 300, easing: "ease-in-out" }
			// 	}
			// }
		});

		dialogRef.afterClosed().subscribe(result => {
		});
	}

	updateDataFn(criteria: DmpCriteriaComponent): void {
		this.criteriaFormGroup = criteria.formGroup;
		this.toDmpCriteria(criteria);
		this.refresh();
	}

	toDmpCriteria(criteria: DmpCriteriaComponent): void {
		let formGroup = criteria.formGroup;
		this.criteria = {
			like: formGroup.get('like').value,
			grants: formGroup.get('grants').value,
			role: formGroup.get('role').value
		}
		this.criteria.status = formGroup.get('status').value;
		this.setPublicCriteria(formGroup);
		if (formGroup.get('datasetTemplates').value)
			this.criteria.datasetTemplates = formGroup.get('datasetTemplates').value.map(x => x.id);
		if (formGroup.get('collaborators').value)
			this.criteria.collaborators = formGroup.get('collaborators').value.map(x => x.id);
		if (formGroup.get('organisations').value)
			this.criteria.organisations = formGroup.get('organisations').value.map(x => x.id);
		if (this.itemId) {
			this.criteria.groupIds = [this.itemId];
			this.criteria.allVersions = true;
		}
		this.criteria.grantStatus = formGroup.get('grantStatus').value;
	}

	setPublicCriteria(formGroup?: FormGroup): void {
		if (!isNullOrUndefined(formGroup)) {
			if (formGroup.get('status').value == 2) {
				this.criteria.status = 1;
				this.criteria.isPublic = true;
			} else {
				this.criteria.isPublic = false;
			}
		}

		this.criteria.onlyPublic = this.isPublic;
		if (this.isPublic) {
			this.criteria.isPublic = true;
		}
		// } else {
		// 	this.criteria.isPublic = false;
		// }
	}

	hasScrollbar(): boolean {
		return document.getElementById("main-page").scrollHeight > document.documentElement.clientHeight
	}

	private mergeTwoSortedLists(arr1: DmpListingModel[], arr2: DmpListingModel[], order: string): DmpListingModel[] {
		let merged = [];
		let index1 = 0;
		let index2 = 0;
		let current = 0;

		while (current < (arr1.length + arr2.length)) {

			let isArr1Depleted = index1 >= arr1.length;
			let isArr2Depleted = index2 >= arr2.length;

			if (order === 'modified') {
				if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].modifiedTime) > new Date(arr2[index2].modifiedTime)))) {
					merged[current] = arr1[index1];
					index1++;
				} else {
					merged[current] = arr2[index2];
					index2++;
				}
			} else if (order === 'created') {
				if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].creationTime) > new Date(arr2[index2].creationTime)))) {
					merged[current] = arr1[index1];
					index1++;
				} else {
					merged[current] = arr2[index2];
					index2++;
				}
			} else if (order === 'label') {
				if (!isArr1Depleted && (isArr2Depleted || (arr1[index1].label.localeCompare(arr2[index2].label)))) {
					merged[current] = arr1[index1];
					index1++;
				} else {
					merged[current] = arr2[index2];
					index2++;
				}
			} else if (order === 'status') {
				if (!isArr1Depleted && (isArr2Depleted || (arr1[index1].status < arr2[index2].status))) {
					merged[current] = arr1[index1];
					index1++;
				} else {
					merged[current] = arr2[index2];
					index2++;
				}
			} else if (order === "publishedAt") {
				if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].publishedAt) > new Date(arr2[index2].publishedAt)))) {
					merged[current] = arr1[index1];
					index1++;
				} else {
					merged[current] = arr2[index2];
					index2++;
				}
			}
			current++;
		}
		return merged;
	}

	public setDashboardTourDmpText(): void {
		this.dmpText = this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' +
			this.language.instant('DMP-LISTING.TEXT-INFO-QUESTION') + ' ' +
			this.language.instant('DMP-LISTING.LINK-ZENODO') + ' ' +
			this.language.instant('DMP-LISTING.GET-IDEA');
		this.dashboardTour.steps[0].title = this.dmpText;
	}

	public setDashboardTourDatasetText(): void {
		this.datasetText = this.language.instant('DATASET-LISTING.TEXT-INFO') +
			this.language.instant('DATASET-LISTING.LINK-PUBLIC-DATASETS') + ' ' +
			this.language.instant('DATASET-LISTING.TEXT-INFO-REST') + '\n\n' +
			this.language.instant('DATASET-LISTING.TEXT-INFO-PAR');
		this.dashboardTour.steps[1].title = this.datasetText;
	}

	public restartTour(): void {
		this.setDashboardTourDmpText();
		this.setDashboardTourDatasetText();
		this.guidedTourService.startTour(this.dashboardTour);
	}

	public hasLikeCriteria(): boolean {
		return this.criteria.like !== undefined && this.criteria.like !== null;
	}
}

// export class DmpDataSource extends DataSource<DmpListingModel> {

// 	totalCount = 0;

// 	constructor(
// 		private _service: DmpService,
// 		private _paginator: MatPaginator,
// 		private _sort: MatSort,
// 		private _criteria: DmpCriteriaComponent,
// 		private itemId
// 	) {
// 		super();
// 	}

// 	connect(): Observable<DmpListingModel[]> {
// 		const displayDataChanges = [
// 			this._paginator.page
// 		];

// 		return Observable.merge(...displayDataChanges)
// 			.startWith(null)
// 			.switchMap(() => {
// 				const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
// 				let fields: Array<string> = new Array();
// 				if (this._sort.active) { fields = this._sort.direction === 'asc' ? ['+' + this._sort.active] : ['-' + this._sort.active]; }
// 				const request = new DataTableRequest<DmpCriteria>(startIndex, this._paginator.pageSize, { fields: fields });
// 				request.criteria = this._criteria.formGroup.value;
// 				if (this.itemId) {
// 					request.criteria.groupIds = [this.itemId];
// 					request.criteria.allVersions = true;
// 				}
// 				return this._service.getPaged(request, "listing");
// 			})
// 			/*.catch((error: any) => {
// 			  this._snackBar.openFromComponent(SnackBarNotificationComponent, {
// 				data: { message: 'GENERAL.SNACK-BAR.FORMS-BAD-REQUEST', language: this._languageService },
// 				duration: 3000,
// 				extraClasses: ['snackbar-warning']
// 			  });
// 			  return Observable.of(null);
// 			})*/
// 			.map(result => {
// 				result.data = result.data;
// 				return result;
// 			})
// 			.map(result => {
// 				return result;
// 			})
// 			.map(result => {
// 				if (!result) { return []; }
// 				if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
// 				return result.data.map(item => {
// 					item['datasets'].map(dmp => {
// 						dmp.url = 'datasets/edit/' + dmp.url;
// 						dmp.all = 'datasets/dmp/' + item.id;
// 						return dmp;
// 					});
// 					return item;
// 				});
// 			});
// 	}

// 	disconnect() {
// 	}
// }
