
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing';
import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { DatasetCriteriaComponent } from '@app/ui/dataset/listing/criteria/dataset-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 { ExternalTagEditorModel, DatasetWizardEditorModel } from '../dataset-wizard/dataset-wizard-editor.model';
import { AuthService } from '@app/core/services/auth/auth.service';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DatasetCriteriaDialogComponent } from './criteria/dataset-criteria-dialogue/dataset-criteria-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { FormGroup, FormBuilder, FormControl } from '@angular/forms';
import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service';
import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.constants';
import { StartNewDatasetDialogComponent } from '@app/ui/dmp/start-new-dataset-dialogue/start-new-dataset-dialog.component';
import { StartNewDmpDialogComponent } from '@app/ui/dmp/start-new-dmp-dialogue/start-new-dmp-dialog.component';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http';

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

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

	breadCrumbs: Observable<BreadcrumbItem[]>;

	titlePrefix: String;
	dmpId: string;
	status: Number;
	totalCount: number;
	dmpSearchEnabled = true;
	listingItems: DatasetListingModel[] = [];
	hasListingItems = null;

	isPublic: boolean = false;
	public isVisible = true

	startIndex: number = 0;
	pageSize: number = 5;
	criteria: DatasetCriteria;
	criteriaFormGroup: FormGroup;
	public formGroup = new FormBuilder().group({
		like: new FormControl(),
		order: new FormControl()
	});

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

	constructor(
		private datasetService: DatasetService,
		private router: Router,
		private route: ActivatedRoute,
		public dialog: MatDialog,
		private dmpService: DmpService,
		private language: TranslateService,
		private authService: AuthService,
		public enumUtils: EnumUtils,
		private authentication: AuthService,
		private guidedTourService: GuidedTourService,
		private httpClient: HttpClient,
		private matomoService: MatomoService
	) {
		super();
	}

	ngOnInit() {
		this.matomoService.trackPageView('Datasets');
		this.isPublic = this.router.url === '/explore';
		if (this.isPublic) {
			this.formGroup.get('order').setValue(this.order.DATASETPUBLISHED);
		} else {
			this.formGroup.get('order').setValue(this.order.MODIFIED);
		}
		if (!this.isPublic && isNullOrUndefined(this.authService.current())) {
			this.router.navigateByUrl("/explore");
		}
		this.route.params
			.pipe(takeUntil(this._destroyed))
			.subscribe(async (params: Params) => {
				const queryParams = this.route.snapshot.queryParams;
				this.dmpId = queryParams['dmpId'];
				this.status = queryParams['status'];
				// Makes multiple post requests
				// this.criteria.setRefreshCallback(() => this.refresh());
				if (this.dmpId != null) {
					this.dmpSearchEnabled = false;
					const dmp = await this.dmpService.getSingle(this.dmpId).toPromise();
					this.criteria = this.getDefaultCriteria(dmp);
					// this.criteria.setCriteria(this.getDefaultCriteria(dmp));
					this.refresh();
					// this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages));
					this.breadCrumbs = observableOf([{
						parentComponentName: 'DmpEditorComponent',
						label: dmp.label,
						url: '/plans/edit/' + this.dmpId
					}]);
					if (params['dmpLabel'] !== undefined) {
						this.titlePrefix = 'for ' + params['dmpLabel'];
					}
				} else {
					this.criteria = this.getDefaultCriteria();
					// this.criteria.setCriteria(this.getDefaultCriteria());
					this.refresh();
					// this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages));
					this.breadCrumbs = observableOf([{
						parentComponentName: null,
						label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'),
						url: this.isPublic ? "/explore" : "/datasets"
					}]);
				}

				if (this.status != null && this.status == DatasetStatus.Draft) {
					this.criteria = this.getDraftCriteria();
					// this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages));
					this.refresh();
				}
			});

		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());
	}

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

	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.authentication.current());
	}

	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();
	}

	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();
		// fields.push('-modified');
		//if (this.sort && this.sort.active) { fields = this.sort.direction === 'asc' ? ['+' + this.sort.active] : ['-' + this.sort.active]; }
		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<DatasetCriteria>(this.startIndex, this.pageSize, { fields: fields });
		this.criteria.isPublic = this.isPublic;
		request.criteria = this.criteria;

		this.datasetService.getPaged(request).pipe(takeUntil(this._destroyed)).subscribe(result => {
			if (!result) { return []; }
			// if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
			this.totalCount = result.totalCount;
			this.listingItems = result.data;
			this.hasListingItems = true;
		});
	}

	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<DatasetCriteria>(this.startIndex, this.pageSize, { fields: fields });
		this.criteria.isPublic = this.isPublic;
		request.criteria = this.criteria;

		this.datasetService.getPaged(request).pipe(takeUntil(this._destroyed)).subscribe(result => {
			if (!result) { return []; }
			// if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
			// this.listingItems = this.listingItems.concat(result.data);
			this.listingItems = this.listingItems.length > 0 ? this.mergeTwoSortedLists(this.listingItems, result.data, this.formGroup.get('order').value) : result.data;
			this.hasListingItems = true;
		});
	}

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

	getDefaultCriteria(dmp: any = null): DatasetCriteria {
		const defaultCriteria = new DatasetCriteria();
		if (dmp != null) {
			defaultCriteria.dmpIds.push(dmp);
		}
		return defaultCriteria;
	}

	getDraftCriteria(): DatasetCriteria {
		const draftCriteria = new DatasetCriteria();
		draftCriteria.status = DatasetStatus.Draft;
		return draftCriteria;
	}

	makeItPublic(id: String) {
		this.datasetService.makeDatasetPublic(id)
			.pipe(takeUntil(this._destroyed))
			.subscribe();
	}

	openFiltersDialog(): void {
		const dialogRef = this.dialog.open(DatasetCriteriaDialogComponent, {
			width: '456px',
			height: '100%',
			id: 'filters',
			restoreFocus: false,
			data: {
				isPublic: this.isPublic,
				status: this.status,
				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'
		});

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

	updateDataFn(criteria: DatasetCriteriaComponent): void {
		this.criteriaFormGroup = criteria.formGroup;
		this.toDatasetCriteria(criteria);
		this.refresh();
	}

	toDatasetCriteria(criteria: DatasetCriteriaComponent) {
		let formGroup = criteria.formGroup;
		this.criteria = {
			like: formGroup.get("like").value,
			status: formGroup.get("status").value,
			allVersions: formGroup.get("allVersions").value,
			role: formGroup.get("role").value
		}
		if (formGroup.get("tags") && formGroup.get("tags").value) {
			this.criteria.tags = formGroup.get("tags").value.map(x => (<ExternalTagEditorModel>x));
		}
		if (formGroup.get("collaborators") && formGroup.get("collaborators").value) {
			this.criteria.collaborators = formGroup.get("collaborators").value.map(x => x.id);
		}
		if (formGroup.get("dmpIds") && formGroup.get("dmpIds").value) {
			this.criteria.dmpIds = formGroup.get("dmpIds").value.map(x => x.id);
		}
		if (formGroup.get("groupIds") && formGroup.get("groupIds").value) {
			this.criteria.groupIds = formGroup.get("groupIds").value.map(x => x.groupId);
		}
		if (formGroup.get("grants") && formGroup.get("grants").value) {
			this.criteria.grants = formGroup.get("grants").value.map(x => x.id);
		}
		if (formGroup.get("organisations") && formGroup.get("organisations").value) {
			this.criteria.organisations = formGroup.get("organisations").value.map(x => x.id);
		}
		if (formGroup.get("datasetTemplates") && formGroup.get("datasetTemplates").value) {
			this.criteria.datasetTemplates = formGroup.get("datasetTemplates").value.map(x => x.id)
		}
		if (formGroup.get("grantStatus") && formGroup.get("grantStatus").value) {
			this.criteria.grantStatus = formGroup.get("grantStatus").value;
		}
		this.criteria.isPublic = this.isPublic;
		// if (this.itemId) {
		// 	// this.criteria.groupIds = [this.itemId];
		// 	this.criteria.allVersions = true;
		// }
	}

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

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

	private mergeTwoSortedLists(arr1: DatasetListingModel[], arr2: DatasetListingModel[], order: string): DatasetListingModel[] {
		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].modified) > new Date(arr2[index2].modified)))) {
					merged[current] = arr1[index1];
					index1++;
				} else {
					merged[current] = arr2[index2];
					index2++;
				}
			} else if (order === 'created') {
				if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].created) > new Date(arr2[index2].created)))) {
					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 === 'dmp:publishedAt|join|') {
				if (!isArr1Depleted && (isArr2Depleted || (new Date(arr1[index1].dmpPublishedAt) > new Date(arr2[index2].dmpPublishedAt)))) {
					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);
	}

	openNewDmpDialog() {
		if (this.dialog.openDialogs.length > 0) {
			this.dialog.closeAll();
		}
		else {
			const dialogRef = this.dialog.open(StartNewDmpDialogComponent, {
				disableClose: false,
				data: {
					isDialog: true
				}
			});
		}
	}

	addNewDataset() {
		const dialogRef = this.dialog.open(StartNewDatasetDialogComponent, {
			disableClose: false,
			restoreFocus: false,
			data: {
				startNewDmp: false,
				formGroup: new DatasetWizardEditorModel().buildForm()
			}
		});
		dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
			if (result) {
				if (result.startNewDmp) {
					this.openNewDmpDialog();
				} else {
					this.router.navigate(['/datasets', 'new', result.formGroup.get('dmp').value.id]);
				}
			}
		});
	}

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

	// rowClicked(dataset: DatasetListingModel) {
	// 	this.router.navigate(['/datasets/edit/' + dataset.id]);
	// }
}
