import { Component, Input, OnInit, ElementRef, ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { LANG } from '../translate.component';
import { NotificationService } from '../../service/notification/notification.service';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { FunctionsService } from '../../service/functions.service';
import { tap, exhaustMap, map, startWith, catchError, finalize, filter } from 'rxjs/operators';
import { FormControl } from '@angular/forms';
import { LatinisePipe } from 'ngx-pipes';
import { Observable, of } from 'rxjs';
import { MatDialog } from '@angular/material/dialog';
import { AddAvisModelModalComponent } from './addAvisModel/add-avis-model-modal.component';
import { ConfirmComponent } from '../../plugins/modal/confirm.component';

@Component({
    selector: 'app-avis-workflow',
    templateUrl: 'avis-workflow.component.html',
    styleUrls: ['avis-workflow.component.scss']
})
export class AvisWorkflowComponent implements OnInit {

    lang: any = LANG;
    avisWorkflow: any = {
        roles: ['sign', 'avis'],
        items: []
    };
    avisWorkflowClone: any = [];
    avisTemplates: any = {
        private: [],
        public: []
    };

    availableRoles: any[] = [];

    signAvisUsers: any = [];
    filteredSignAvisUsers: Observable<string[]>;
    filteredPublicModels: Observable<string[]>;
    filteredPrivateModels: Observable<string[]>;

    loading: boolean = false;
    avisModelListNotLoaded: boolean = true;
    data: any;

    @Input('injectDatas') injectDatas: any;
    @Input('adminMode') adminMode: boolean;
    @Input('resId') resId: number = null;

    @Input('showListModels') showListModels: boolean = true;

    @Input('mode') mode: 'parallel' | 'circuit' = 'circuit';

    @ViewChild('searchAvisUserInput', { static: false }) searchAvisUserInput: ElementRef;

    searchAvisUser = new FormControl();

    constructor(
        public http: HttpClient,
        private notify: NotificationService,
        public functions: FunctionsService,
        private latinisePipe: LatinisePipe,
        public dialog: MatDialog
    ) { }

    ngOnInit(): void {
        if (this.mode === 'parallel' && this.adminMode) {
            this.loadAvisRoles();
        }

        if (this.resId !== null) {
            if (this.mode === 'circuit') {
                this.loadWorkflow(this.resId);
            } else {
                this.loadParallelWorkflow(this.resId);
            }
        }
    }

    drop(event: CdkDragDrop<string[]>) {
        if (event.previousContainer === event.container) {
            if (this.functions.empty(this.avisWorkflow.items[event.currentIndex].process_date)) {
                moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
            } else {
                this.notify.error(`${this.lang.moveAvisUserErr1} <b>${this.avisWorkflow.items[event.previousIndex].labelToDisplay}</b> ${this.lang.moveAvisUserErr2}.`);
            }
        }
    }

    loadAvisRoles() {
        return new Promise((resolve, reject) => {
            this.http.get(`../rest/roles`).pipe(
                tap((data: any) => {
                    this.availableRoles = data.roles.filter((role: any) => ['avis', 'avis_copy', 'avis_info'].indexOf(role.id) > -1).map((role: any) => {
                        return {
                            id: role.id,
                            label: role.label
                        }
                    });
                    resolve(true);
                }),
                catchError((err: any) => {
                    this.notify.handleErrors(err);
                    return of(false);
                })
            ).subscribe();
        });
    }

    getRoleLabel(id: string) {
        return this.availableRoles.filter(role => role.id === id)[0].label;
    }

    loadListModel(entityId: number) {
        this.loading = true;

        this.avisWorkflow.items = [];

        this.http.get(`../rest/listTemplates/entities/${entityId}?type=opinionCircuit`)
            .subscribe((data: any) => {
                if (data.listTemplates[0]) {
                    this.avisWorkflow.items = data.listTemplates[0].items.map((item: any) => {
                        return {
                            ...item,
                            item_entity: item.descriptionToDisplay,
                        }
                    });
                }
                this.avisWorkflowClone = JSON.parse(JSON.stringify(this.avisWorkflow.items));
                this.loading = false;
            });
    }

    loadAvisUsersList() {
        return new Promise((resolve, reject) => {
            this.http.get(`../rest/autocomplete/users/circuit?circuit=opinion`).pipe(
                map((data: any) => {
                    data = data.map((user: any) => {
                        return {
                            id: user.id,
                            title: `${user.idToDisplay} (${user.otherInfo})`,
                            label: user.idToDisplay,
                            entity: user.otherInfo,
                            type: 'user'
                        }
                    });
                    return data;
                }),
                tap((data) => {
                    this.signAvisUsers = data;
                    this.filteredSignAvisUsers = this.searchAvisUser.valueChanges
                        .pipe(
                            startWith(''),
                            map(value => this._filter(value))
                        );
                    resolve(true);
                }),
                catchError((err: any) => {
                    this.notify.handleSoftErrors(err);
                    return of(false);
                })
            ).subscribe();
        });
    }

    async loadAvisModelList() {
        if (this.resId !== null) {
            await this.loadDefaultModel();
        }

        return new Promise((resolve, reject) => {
            this.http.get(`../rest/availableCircuits?circuit=opinion`).pipe(
                tap((data: any) => {
                    this.avisTemplates.public = this.avisTemplates.public.concat(data.circuits.filter((item: any) => !item.private).map((item: any) => {
                        return {
                            id: item.id,
                            title: item.title,
                            label: item.title,
                            type: 'entity'
                        }
                    }));

                    this.avisTemplates.private = data.circuits.filter((item: any) => item.private).map((item: any) => {
                        return {
                            id: item.id,
                            title: item.title,
                            label: item.title,
                            type: 'entity'
                        }
                    });
                    this.filteredPublicModels = this.searchAvisUser.valueChanges
                        .pipe(
                            startWith(''),
                            map(value => this._filterPublicModel(value))
                        );
                    this.filteredPrivateModels = this.searchAvisUser.valueChanges
                        .pipe(
                            startWith(''),
                            map(value => this._filterPrivateModel(value))
                        );
                    resolve(true);
                })
            ).subscribe();
        });
    }

    loadDefaultModel() {
        this.avisTemplates.public = [];

        return new Promise((resolve, reject) => {
            this.http.get(`../rest/resources/${this.resId}/defaultCircuit?circuit=opinion`).pipe(
                tap((data: any) => {
                    if (!this.functions.empty(data.itemsRemoved)) {
                        this.notify.error(this.lang.itemRemovedFromAvisTemplate + ' : ' + data.itemsRemoved.join(', '));
                    }
                }),
                filter((data: any) => !this.functions.empty(data.circuit)),
                tap((data: any) => {
                    if (!this.functions.empty(data.circuit)) {
                        this.avisTemplates.public.push({
                            id: data.circuit.id,
                            title: data.circuit.title,
                            label: data.circuit.title,
                            type: 'entity'
                        });
                    }
                }),
                finalize(() => resolve(true)),
                catchError((err: any) => {
                    this.notify.handleSoftErrors(err);
                    return of(false);
                })
            ).subscribe();
        });
    }

    async initFilterAvisModelList() {
        if (this.avisModelListNotLoaded) {
            await this.loadAvisUsersList();

            if (this.showListModels) {
                await this.loadAvisModelList();
            }

            this.searchAvisUser.reset();

            this.avisModelListNotLoaded = false;
        }
    }

    private _filter(value: string): string[] {
        if (typeof value === 'string') {
            const filterValue = this.latinisePipe.transform(value.toLowerCase());
            return this.signAvisUsers.filter((option: any) => this.latinisePipe.transform(option['title'].toLowerCase()).includes(filterValue));
        } else {
            return this.signAvisUsers;
        }
    }

    private _filterPrivateModel(value: string): string[] {
        if (typeof value === 'string') {
            const filterValue = this.latinisePipe.transform(value.toLowerCase());
            return this.avisTemplates.private.filter((option: any) => this.latinisePipe.transform(option['title'].toLowerCase()).includes(filterValue));
        } else {
            return this.avisTemplates.private;
        }
    }

    private _filterPublicModel(value: string): string[] {
        if (typeof value === 'string') {
            const filterValue = this.latinisePipe.transform(value.toLowerCase());
            return this.avisTemplates.public.filter((option: any) => this.latinisePipe.transform(option['title'].toLowerCase()).includes(filterValue));
        } else {
            return this.avisTemplates.public;
        }
    }

    loadWorkflow(resId: number) {
        this.resId = resId;
        this.loading = true;
        this.avisWorkflow.items = [];
        return new Promise((resolve, reject) => {
            this.http.get("../rest/resources/" + resId + "/opinionCircuit").pipe(
                tap((data: any) => {
                    if (!this.functions.empty(data.itemsRemoved)) {
                        this.notify.error(this.lang.itemRemovedFromAvisTemplate + ' : ' + data.itemsRemoved.join(', '));
                    }
                }),
                filter((data: any) => !this.functions.empty(data.circuit)),
                tap((data: any) => {
                    data.circuit.forEach((element: any) => {
                        this.avisWorkflow.items.push(
                            {
                                ...element,
                                difflist_type: this.mode === 'circuit' ? 'AVIS_CIRCUIT' : 'entity_id'
                            });
                    });
                    this.avisWorkflowClone = JSON.parse(JSON.stringify(this.avisWorkflow.items))
                }),
                finalize(() => {
                    this.loading = false;
                    resolve(true);
                }),
                catchError((err: any) => {
                    this.notify.handleSoftErrors(err);
                    return of(false);
                })
            ).subscribe();
        });

    }

    loadParallelWorkflow(resId: number) {
        this.resId = resId;
        this.loading = true;
        this.avisWorkflow.items = [];
        return new Promise((resolve, reject) => {
            this.http.get("../rest/resources/" + resId + "/parallelOpinion")
                .subscribe((data: any) => {
                    data.forEach((element: any) => {
                        this.avisWorkflow.items.push(
                            {
                                ...element,
                                difflist_type: 'entity_id'
                            });
                    });
                    this.avisWorkflowClone = JSON.parse(JSON.stringify(this.avisWorkflow.items));
                    this.loading = false;
                    resolve(true);
                }, (err: any) => {
                    this.notify.handleErrors(err);
                });
        });

    }

    loadDefaultWorkflow(resId: number) {
        this.loading = true;
        this.avisWorkflow.items = [];
        this.http.get("../rest/resources/" + resId + "/defaultCircuit?circuit=opinion").pipe(
            tap((data: any) => {
                if (!this.functions.empty(data.itemsRemoved)) {
                    this.notify.error(this.lang.itemRemovedFromAvisTemplate + ' : ' + data.itemsRemoved.join(', '));
                }
            }),
            filter((data: any) => !this.functions.empty(data.circuit)),
            tap((data: any) => {
                data.circuit.items.forEach((element: any) => {
                    this.avisWorkflow.items.push(
                        {
                            ...element,
                            difflist_type: this.mode === 'circuit' ? 'AVIS_CIRCUIT' : 'entity_id',
                            item_entity: element.descriptionToDisplay
                        });
                });
                this.avisWorkflowClone = JSON.parse(JSON.stringify(this.avisWorkflow.items))
            }),
            finalize(() => this.loading = false),
            catchError((err: any) => {
                this.notify.handleSoftErrors(err);
                return of(false);
            })
        ).subscribe();
    }

    deleteItem(index: number) {
        this.avisWorkflow.items.splice(index, 1);
    }

    getAvisCount() {
        return this.avisWorkflow.items.length;
    }

    changeRole(role: any, i: number) {
        this.avisWorkflow.items[i].item_mode = role.id;
    }

    getWorkflow() {
        return this.avisWorkflow.items;
    }

    getCurrentAvisUserIndex() {

        const index = this.avisWorkflow.items.map((item: any) => item.listinstance_id).indexOf(this.getLastAvisUser().listinstance_id);

        return (index + 1);
    }

    getFirstAvisUser() {
        return !this.functions.empty(this.avisWorkflow.items[0]) ? this.avisWorkflow.items[0] : '';
    }

    getCurrentAvisUser() {

        const index = this.avisWorkflow.items.map((item: any) => item.listinstance_id).indexOf(this.getLastAvisUser().listinstance_id);

        return !this.functions.empty(this.avisWorkflow.items[index + 1]) ? this.avisWorkflow.items[index + 1] : '';
    }

    getNextAvisUser() {

        const index = this.avisWorkflow.items.map((item: any) => item.listinstance_id).indexOf(this.getLastAvisUser().listinstance_id);

        return !this.functions.empty(this.avisWorkflow.items[index + 2]) ? this.avisWorkflow.items[index + 2] : '';
    }

    getLastAvisUser() {
        let arrOnlyProcess = this.avisWorkflow.items.filter((item: any) => !this.functions.empty(item.process_date));

        return !this.functions.empty(arrOnlyProcess[arrOnlyProcess.length - 1]) ? arrOnlyProcess[arrOnlyProcess.length - 1] : '';
    }

    saveAvisWorkflow(resIds: number[] = [this.resId]) {
        return new Promise((resolve, reject) => {
            if (this.avisWorkflow.items.length === 0) {
                this.http.delete(`../rest/resources/${resIds[0]}/circuits/opinionCircuit`).pipe(
                    tap(() => {
                        this.avisWorkflowClone = JSON.parse(JSON.stringify(this.avisWorkflow.items));
                        this.notify.success(this.lang.avisWorkflowDeleted);
                        resolve(true);
                    }),
                    catchError((err: any) => {
                        this.notify.handleSoftErrors(err);
                        return of(false);
                    })
                ).subscribe();
            } else if (this.isValidWorkflow()) {
                const arrAvis = resIds.map(resId => {
                    return {
                        resId: resId,
                        listInstances: this.avisWorkflow.items
                    }
                });
                this.http.put(`../rest/circuits/opinionCircuit`, { resources: arrAvis }).pipe(
                    tap((data: any) => {
                        this.avisWorkflowClone = JSON.parse(JSON.stringify(this.avisWorkflow.items));
                        this.notify.success(this.lang.avisWorkflowUpdated);
                        resolve(true);
                    }),
                    catchError((err: any) => {
                        this.notify.handleSoftErrors(err);
                        return of(false);
                    })
                ).subscribe();
            } else {
                this.notify.error(this.getError());
                resolve(false);
            }
        });
    }

    addItemToWorkflow(item: any) {
        return new Promise((resolve, reject) => {
            if (item.type === 'user') {
                this.avisWorkflow.items.push({
                    item_id: item.id,
                    item_type: 'user',
                    item_entity: item.entity,
                    item_mode: 'avis',
                    labelToDisplay: item.label,
                    externalId: !this.functions.empty(item.externalId) ? item.externalId : null,
                    difflist_type: this.mode === 'circuit' ? 'AVIS_CIRCUIT' : 'entity_id',
                    hasPrivilege : true
                });
                this.searchAvisUser.reset();
                this.searchAvisUserInput.nativeElement.blur();
                resolve(true);
            } else if (item.type === 'entity') {
                this.http.get(`../rest/listTemplates/${item.id}`).pipe(
                    tap((data: any) => {
                        this.avisWorkflow.items = this.avisWorkflow.items.concat(
                            data.listTemplate.items.map((itemTemplate: any) => {
                                return {
                                    item_id: itemTemplate.item_id,
                                    item_type: 'user',
                                    labelToDisplay: itemTemplate.idToDisplay,
                                    item_entity: itemTemplate.descriptionToDisplay,
                                    item_mode: 'avis',
                                    difflist_type: this.mode === 'circuit' ? 'AVIS_CIRCUIT' : 'entity_id',
                                    hasPrivilege : itemTemplate.hasPrivilege
                                }
                            })
                        );
                        this.searchAvisUser.reset();
                        this.searchAvisUserInput.nativeElement.blur();
                        resolve(true);
                    })
                ).subscribe();
            }
        });
    }

    resetWorkflow() {
        this.avisWorkflow.items = [];
    }

    isValidWorkflow() {
        if (this.avisWorkflow.items.filter((item: any) => !item.hasPrivilege).length === 0 && this.avisWorkflow.items.length > 0) {
            return true;
        } else {
            return false;
        }
    }

    getError() {
        return this.lang.mustDeleteUsersWithNoPrivileges;
    }

    emptyWorkflow() {
        return this.avisWorkflow.items.length === 0;
    }

    workflowEnd() {
        if (this.avisWorkflow.items.filter((item: any) => !this.functions.empty(item.process_date)).length === this.avisWorkflow.items.length) {
            return true;
        } else {
            return false;
        }
    }

    openPromptSaveModel() {
        const dialogRef = this.dialog.open(AddAvisModelModalComponent, { panelClass: 'maarch-modal', data: { avisWorkflow: this.avisWorkflow.items } });

        dialogRef.afterClosed().pipe(
            filter((data: string) => !this.functions.empty(data)),

            tap((data: any) => {
                this.avisTemplates.private.push({
                    id: data.id,
                    title: data.title,
                    label: data.title,
                    type: 'entity'
                });
                this.searchAvisUser.reset();
            }),
            catchError((err: any) => {
                this.notify.handleSoftErrors(err);
                return of(false);
            })
        ).subscribe();
    }

    deletePrivateModel(model: any) {
        const dialogRef = this.dialog.open(ConfirmComponent, { panelClass: 'maarch-modal', autoFocus: false, disableClose: true, data: { title: this.lang.delete, msg: this.lang.confirmAction } });

        dialogRef.afterClosed().pipe(
            filter((data: string) => data === 'ok'),
            exhaustMap(() => this.http.delete(`../rest/listTemplates/${model.id}`)),
            tap(() => {
                this.avisTemplates.private = this.avisTemplates.private.filter((template: any) => template.id !== model.id);
                this.searchAvisUser.reset();
                this.notify.success(this.lang.modelDeleted);
            }),
            catchError((err: any) => {
                this.notify.handleErrors(err);
                return of(false);
            })
        ).subscribe();
    }

    getMaarchParapheurUserAvatar(externalId: string, key: number) {
        if (!this.functions.empty(externalId)) {
            this.http.get("../rest/maarchParapheur/user/" + externalId + "/picture")
                .subscribe((data: any) => {
                    this.avisWorkflow.items[key].picture = data.picture;
                }, (err: any) => {
                    this.notify.handleErrors(err);
                });
        }
    }

    isModified() {
        if (this.loading || JSON.stringify(this.avisWorkflow.items) === JSON.stringify(this.avisWorkflowClone)) {
            return false;
        } else {
            return true;
        }
    }
}