import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { CultureInfo } from '@app/core/model/culture-info';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { UserListingModel } from '@app/core/model/user/user-listing';
import { AuthService } from '@app/core/services/auth/auth.service';
import { CultureService } from '@app/core/services/culture/culture-service';
import { UserService } from '@app/core/services/user/user.service';
import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core';
import * as moment from 'moment-timezone';
import { Observable, of } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { LanguageService } from '@app/core/services/language/language.service';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { Oauth2DialogService } from '../misc/oauth2-dialog/service/oauth2-dialog.service';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item';
import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service';
import { UserProfileEditorModel } from './user-profile-editor.model';
import { RoleOrganizationType } from '@app/core/common/enum/role-organization-type';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { AddAccountDialogComponent } from './add-account/add-account-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { UserCredentialModel } from '@app/core/model/user/user-credential';
import { AuthProvider } from '@app/core/common/enum/auth-provider';
import { MergeEmailConfirmationService } from '@app/core/services/merge-email-confirmation/merge-email-confirmation.service';
import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { HttpClient } from '@angular/common/http';
import {PopupNotificationDialogComponent} from "@app/library/notification/popup/popup-notification.component";

const availableLanguages: any[] = require('../../../assets/resources/language.json');

@Component({
	selector: 'app-user-profile',
	templateUrl: './user-profile.component.html',
	styleUrls: ['./user-profile.component.scss'],
})
export class UserProfileComponent extends BaseComponent implements OnInit, OnDestroy {

	userProfileEditorModel: UserProfileEditorModel;
	user: Observable<UserListingModel>;
	userCredentials: UserCredentialModel[];
	currentUserId: string;
	cultures: Observable<CultureInfo[]>;
	timezones: Observable<any[]>;
	editMode = false;
	languages = availableLanguages;
	zenodoToken: string;
	zenodoEmail: String;
	roleOrganizationEnum = RoleOrganizationType;
	authProviderEnum = AuthProvider;
	private oauthLock: boolean;
	errorMessages = [];
	nestedCount = [];
	nestedIndex = 0;

	organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
		filterFn: this.filterOrganisations.bind(this),
		initialItems: (excludedItems: any[]) => this.filterOrganisations('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
		displayFn: (item) => item['name'],
		titleFn: (item) => item['name'],
		subtitleFn: (item) => item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE'))
	};

	formGroup: FormGroup;
	constructor(
		private userService: UserService,
		private route: ActivatedRoute,
		private router: Router,
		private authService: AuthService,
		private language: TranslateService,
		private cultureService: CultureService,
		private externalSourcesService: ExternalSourcesService,
		private authentication: AuthService,
		private languageService: LanguageService,
		private configurationService: ConfigurationService,
		private oauth2DialogService: Oauth2DialogService,
		private uiNotificationService: UiNotificationService,
		private dialog: MatDialog,
		public enumUtils: EnumUtils,
		private mergeEmailConfirmation: MergeEmailConfirmationService,
		private httpClient: HttpClient,
		private matomoService: MatomoService
	) { super(); }

	ngOnInit() {
		this.matomoService.trackPageView('User Profile');
		this.route.params
			.pipe(takeUntil(this._destroyed))
			.subscribe((params: Params) => {
				this.currentUserId = this.authService.current().id;
				const userId = !params['id'] ? 'me' : params['id'];
				this.user = this.userService.getUser(userId).pipe(map(result => {
					//result['additionalinfo'] = JSON.parse(result['additionalinfo']);
					//this.zenodoToken = result['additionalinfo']['zenodoToken'];
					this.zenodoEmail = result['zenodoEmail'];

					this.userProfileEditorModel = new UserProfileEditorModel().fromModel(result);
					this.formGroup = this.userProfileEditorModel.buildForm();
					// this.formGroup = new FormBuilder().group({
					// 	language: new FormControl(result['language'] ? availableLanguages.filter(x => x.value === result['language']['value']).pop() : '', [Validators.required]),
					// 	timezone: new FormControl(result['timezone'], [Validators.required]),
					// 	culture: new FormControl(result['culture'], [Validators.required])
					// });

					//this.formGroup.get('language').valueChanges.pipe(takeUntil(this._destroyed)).subscribe(x => { if (x) this.translate.use(x.value) })
					this.formGroup.get('timezone').valueChanges
						.pipe(takeUntil(this._destroyed))
						.subscribe(x => { if (x) { this.timezones = this._filterTimezone(x); } });
					this.formGroup.get('culture').valueChanges
						.pipe(takeUntil(this._destroyed))
						.subscribe(x => { if (x) { this.cultures = this._filterCulture(x); } });
					// this.initializeDisabledFormGroup();
					this.unlock();
					return result;
				}));

				this.userService.getEmails(userId).pipe(takeUntil(this._destroyed))
					.subscribe(result => {
						this.userCredentials = result;
					});
			});

	}

	ngOnDestroy(): void {
	}

	logout(): void {
		this.authentication.logout();
	}

	getUserRole(dmp: DmpModel) {
		if (dmp.creator.id === this.currentUserId) {
			return this.language.instant('USER-PROFILE.DMPS.CREATOR');
		} else if (dmp.associatedUsers.map(x => x.id).indexOf(this.currentUserId) !== -1) {
			return this.language.instant('USER-PROFILE.DMPS.MEMBER');
		}
	}

	showAllDmps() {
		this.router.navigate(['/plans']);
	}

	navigateToDmp(dmp: DmpModel) {
		this.router.navigate(['/plans/edit/' + dmp.id]);
	}

	private filterOrganisations(value: string): Observable<ExternalSourceItemModel[]> {
		return this.externalSourcesService.searchDMPOrganizations(value);
	}

	private _filterTimezone(value: string): Observable<any[]> {
		if (value && typeof value === 'string') {
			const filterValue = value.toLowerCase();
			return of(moment.tz.names().filter(option => option.toLowerCase().includes(filterValue)));
		} else {
			return of(moment.tz.names());
		}
	}

	private _filterCulture(value: string): Observable<any[]> {
		if (value && typeof value === 'string') {
			const filterValue = value.toLowerCase();
			return of(this.cultureService.getCultureValues().filter(option => option.displayName.toLowerCase().includes(filterValue)));
		} else {
			return of(this.cultureService.getCultureValues());
		}
	}

	displayFn(culture?: CultureInfo): string | undefined {
		return culture ? culture.displayName + '-' + culture.nativeName : undefined;
	}

	save() {
		if (!this.formGroup.valid) {
			this.printErrors(this.formGroup);
			this.showValidationErrorsDialog();
			this.nestedCount = [];
			this.nestedIndex = 0;
			this.errorMessages = [];
			return;
		}
		this.userService.updateUserSettings(this.formGroup.value)
			.pipe(takeUntil(this._destroyed))
			.subscribe(
				x => {
					this.editMode = false;
					this.languageService.changeLanguage(this.formGroup.value.language.value);
					this.authService.current().culture = this.formGroup.value.culture.name;
					this.authService.me()
						.pipe(takeUntil(this._destroyed))
						.subscribe(result => {
							this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
							this.router.navigate(['/profile']);
						});
					// .subscribe(result => window.location.reload());
				},
				error => {
					console.log(error);
				});
	}

	public unlock() {
		this.editMode = true;
		this.formGroup.enable();
	}

	public initializeDisabledFormGroup() {
		this.formGroup.disable();
	}

	public lock() {
		if (!this.formGroup.valid) { return; }
		this.userService.updateUserSettings(this.formGroup.value)
			.pipe(takeUntil(this._destroyed))
			.subscribe(
				x => {
					this.editMode = false;
					this.languageService.changeLanguage(this.formGroup.value.language.value);
					this.authService.current().culture = this.formGroup.value.culture.name;
					this.formGroup.disable();
					this.authService.me()
						.pipe(takeUntil(this._destroyed))
						.subscribe(result => this.router.navigate(['/profile']));
					// .subscribe(result => window.location.reload());
				},
				error => {
					console.log(error);
				});
	}

	private showValidationErrorsDialog(projectOnly?: boolean) {
		const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, {
			disableClose: true,
			autoFocus: false,
			restoreFocus: false,
			data: {
				errorMessages: this.errorMessages,
				projectOnly: projectOnly
			},
		});
	}

	public applyFallbackAvatar(ev: Event) {
		(ev.target as HTMLImageElement).src = 'assets/images/profile-placeholder.png';
	}

	public hasZenodo(): boolean {
		return !isNullOrUndefined(this.zenodoEmail) && this.zenodoEmail !== "";
	}

	public loginToZenodo() {
		this.showOauth2Dialog(this.getAccessUrl());
	}

	getAccessUrl(): string {
		const redirectUri = this.configurationService.app + 'oauth2';
		const url = this.configurationService.loginProviders.zenodoConfiguration.oauthUrl
			+ '?client_id=' + this.configurationService.loginProviders.zenodoConfiguration.clientId
			+ '&response_type=code&scope=deposit:write+deposit:actions+user:email&state=astate&redirect_uri='
			+ redirectUri;
		return url;
	}

	showOauth2Dialog(url: string) {
		this.oauth2DialogService.login(url)
			.pipe(takeUntil(this._destroyed))
			.subscribe(result => {
				if (result !== undefined) {
					if (result.oauthCode !== undefined && result.oauthCode !== null && !this.oauthLock) {
						this.userService.registerDOIToken(result.oauthCode, this.configurationService.app + 'oauth2')
							.pipe(takeUntil(this._destroyed))
							.subscribe(() => this.router.navigate(['/reload']).then(() => this.router.navigate(['/profile'])));
						this.oauthLock = true;
					}
				} else {
					this.oauthLock = false;
				}
			});
	}

	public RemoveZenodo() {
		this.userService.deleteDOIToken()
			.pipe(takeUntil(this._destroyed))
			.subscribe(() => this.router.navigate(['/reload']).then(() => this.router.navigate(['/profile'])));
	}

	public removeAccount() {

	}

	public addAccount() {
		const dialogRef = this.dialog.open(AddAccountDialogComponent, {
			restoreFocus: false,
			autoFocus: false,
			width: '653px',
			maxHeight: '90vh',
			data: {
			}
		});
		dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
			if (result) {
				this.mergeEmailConfirmation.sendConfirmationEmail(result).pipe(takeUntil(this._destroyed))
					.subscribe(res => {
						this.dialog.open(PopupNotificationDialogComponent, {
							data: {
								title: this.language.instant('USER-PROFILE.MERGING-EMAILS-DIALOG.TITLE'),
								message: this.language.instant('USER-PROFILE.MERGING-EMAILS-DIALOG.MESSAGE')
							}, maxWidth: '30em'
						});
					}, err => { });
			}
		});
	}

	printErrors(rootform: FormGroup) {
		if (!rootform.valid) {
			Object.keys(rootform.controls).forEach(key => {
				const errors = rootform.get(key).errors;
				if (errors !== null) {
					let numbering: string = '';
					for (let j = 0; j < this.nestedCount.length; j++) {
						numbering += this.nestedCount[j];
						if (j < this.nestedIndex) {
							numbering += '.';
						} else {
							break;
						}
					}
					Object.keys(errors).forEach(keyError => {
						if (typeof errors[keyError] === 'boolean') {
							this.errorMessages.push(numbering + ' ' + key + ' is ' + keyError);
						} else {
							this.errorMessages.push(numbering + ' ' + key + ': ' + keyError + ': ' + JSON.stringify(errors[keyError]));
						}
					});
				} else {
					if (rootform.get(key) instanceof FormGroup) {
						this.printErrors(<FormGroup>rootform.get(key));
					} else if (rootform.get(key) instanceof FormArray) {
						this.nestedIndex++;
						this.nestedCount[this.nestedIndex] = 0;
						for (let childForm of (<FormArray>rootform.get(key)).controls) {
							this.nestedCount[this.nestedIndex]++;
							this.printErrors(<any>childForm);
						}
						this.nestedCount[this.nestedIndex] = 0;
						this.nestedIndex--;

					}
				}
			});
		}
	}

}
