import { MessageService } from 'node_modules/primeng/api';
import { ConfirmationService } from 'node_modules/primeng/api';
import { AuthService } from '../auth/auth.service';
import { RequireInteractiveControl, RequireEmptyFunction } from '../interface/Interactive Component/RequireInteractiveControl';
import { WebNotificationService } from '../auth/webNotification.service';
import { Router, ActivatedRoute, NavigationEnd, NavigationStart } from '@angular/router';
import { BaseComponent } from './BaseComponent';
import { Location } from '@angular/common';
import { BaseService } from './BaseService';
import { LogHasChangeById, SpecifyLogHasChangeById } from '../interface/audit-trail';
import { AuditTrailService } from '../service/object/audit-trail.service';
import { EtableComponent } from '../ek-components/etable/etable.component';
import { FormGroup, Validators, FormArray } from '@angular/forms';
import { filter } from 'rxjs/operators';
import { Subscription, BehaviorSubject, Observable } from 'rxjs';
import { RouteHandleService } from 'ekangularbase/src/route/RouteHandle.service';

export class BaseComponentV2<T extends RequireInteractiveControl> extends BaseComponent<T> {

    disableDeleteButton = true;
    allowLazyLoading = false;
    lazyLoadingQuery = '';
    queryParamObj: any;

    strTableName = '';
    logColumnList: string[] = [];

    errorMessages = {};
    mandatoryField = {};

    listServiceDoneSubscription: Subscription;

    constructor(
        public confirmationService: ConfirmationService
        , public webNotificationservice: WebNotificationService
        , public messageService: MessageService
        , public objectservice: BaseService<T>
        , public objectname: string
        , public authService: AuthService
        , public routerNav?: Router
        , public locationNav?: Location
        , public route?: ActivatedRoute
        , public auditTrailService?: AuditTrailService
        , public objEmptyFuntion?: RequireEmptyFunction
        , public routehandleservice?: RouteHandleService
        , public actionitems: string[] = ['Insert', 'Delete', 'Update']
        , public blockUiControl: boolean = false
        , public SelectedOcChanged: boolean = false
    ) {
        super(confirmationService, webNotificationservice, messageService, objectservice,
            objectname, authService, routerNav, actionitems, blockUiControl, SelectedOcChanged, locationNav,
            route);

        this.listServiceDoneChange = new BehaviorSubject(false);
        this.getQueryParams();
    }

    baseOnInit() {
        this.startBlockUI();
        this.localBaseOnInit();

        this.listServiceDoneSubscription = this.listServiceDoneChange.subscribe(event => {
            this.onListServiceDoneChange(event);
        });

    }

    getQueryParams() {
        if (this.route && this.authService.getById !== true) {
            this.route.queryParams.subscribe(params => {
                console.log('queryParams', params);
                this.queryParamObj = params;
                this.objectservice.queryParamObj = params;

                if (this.objectIsNull(this.queryParamObj)
                    || this.objectIsNull(this.queryParamObj.id)
                    || !this.routehandleservice) {
                        // this.objectservice['selectedFinMthYrID'] = undefined;
                        return;
                    }

                const redirectDetails = this.routehandleservice.getRedirectDetail(this.queryParamObj.id);

                if (redirectDetails !== null && redirectDetails.type === 'excep') {
                    console.log('redirect isRedirect base');
                    this.authService.currentUrl = redirectDetails.url;
                    this.authService.isRedirect = true;
                    this.objectservice['selectedFinMthYrID'] = redirectDetails.mon;
                }
            });
        }
    }

    onListServiceDoneChange(event: boolean) {
        console.log('queryParams onListServiceDoneChange', event);
        if (event !== true || this.objectIsNull(this.queryParamObj)
            || this.objectIsNull(this.queryParamObj.id)) { return; }

        console.log('queryParams url', this.routerNav.url);

        try {
            const redirectDetails = this.routehandleservice.getRedirectDetail(this.queryParamObj.id);
            console.log('queryParams redirectDetails', redirectDetails);

            if (redirectDetails !== null && redirectDetails.type === 'excep'
                && this.getCurrentUrl() === redirectDetails.url) {
                this.exceptionFilterList(redirectDetails);
                console.log('queryParams objectlist', this.objectlist);
            }
        } catch (error) {
            console.log('queryParams error', error);
        }
    }

    exceptionFilterList(redirectDetails) {
        this.objectlist = this.objectlist.filter(l => l['empCode'] === redirectDetails.empCode
            && l['transDate'] === redirectDetails.transDate);
    }

    getCurrentUrl(): string {
        if (this.routerNav.url && this.routerNav.url !== '/') {
            const indexSlash = this.routerNav.url.indexOf('/', 1);

            let curUrl = this.routerNav.url;

            if (indexSlash !== -1) { curUrl = curUrl.substr(0, indexSlash); }

            const i = curUrl.indexOf('?');
            if (i === -1) {
                return curUrl;
            } else {
                const preUrl = curUrl.substr(0, i);
                return preUrl;
            }
        }

        return '';
    }

    localBaseOnInit() {}

    startBlockUI() {
        if (this.authService.pageName === 'Input') {
            this.baseblockUI.start('Loading...');
            this.totalDropdownSubscription = this.totalDropdownChange.subscribe(totalDropdown => {
                this.onTotalDropdownChange(totalDropdown);
            });
        }
    }

    list() {
        this.disableDeleteButton = true;

        if (this.allowLazyLoading === false) {
            this.objectlist = [];
            this.loading = true;
            this.isDataFinishLoaded = false;
            this.detectChanges();
            this.listService();
        } else {
            this.objectlist = [];
            this.isDataFinishLoaded = true;
            this.detectChanges();
            if (this.lazyLoadingQuery !== '') { this.lazyLoadingApiCallService(this.lazyLoadingQuery); }
        }
    }

    lazyLoadingApiCall(event) {
        console.log('query: ', event.query);
        this.lazyLoadingQuery = event.query;
        this.lazyLoadingApiCallService(this.lazyLoadingQuery).subscribe(res => {
            this.objectlist = res;
            this.detectChanges({ lazyLoadingChanges: this.lazyLoadingQuery });
        });
    }

    lazyLoadingApiCallService(query: string): Observable<any> {
        return this.objectservice.Get();
    }

    listService() {
        this.objectservice.Get().subscribe(obj => {
            this.listServiceDone(obj);
            this.dataFinishLoaded();
            }, error => {
                console.log(error);
                this.dataFinishLoaded();
            }
        );
    }

    listServiceDone(obj: T[]) {
        if (!obj || obj == null) { obj = []; }
        console.log(obj);
        this.objectlist = obj;
        this.obvobjlist.next(obj);
        this.cols.forEach(s => {
            if (s.isSubObject) { s.sortFeild = s.field + '.' + s.subField; }
        });
        this.listServiceDoneChange.next(true);
    }

    dataFinishLoaded() {
        this.loading = false;
        this.isDataFinishLoaded = true;
        const event = {};
        event['selectAllCheckBox'] = false;
        console.log('dataFinishLoaded v2', event);
        this.detectChanges(event);
        this.startGetHasAuditLog();
    }

    startGetHasAuditLog() {}

    detectNavigation() {
        this.detectRefresSubscription = this.routerNav.events
        .pipe(filter((rs): rs is NavigationEnd => rs instanceof NavigationEnd))
        .subscribe(event => {
        if (
            event.id === 1 &&
            event.url === event.urlAfterRedirects
        ) {
            console.log('browser Refresh', this.routerNav.url);
            this.ResetFlagAndRedirectToHome();
        }
        });

        this.detectBackSubscription = this.routerNav.events
        .pipe(filter((rs): rs is NavigationStart => rs instanceof NavigationStart))
        .subscribe(event => {
        if (event.navigationTrigger === 'popstate') {
            console.log('browser click back');
            this.authService.ResetFlag();
            this.authService.pageState = 'back';
            this.routerNav.navigate(['']);
        }
      });
    }

    checkUrl(): boolean {
        // console.log('routerNav');
        // console.log(this.routerNav.url);
        // console.log(this.authService.currentSidebarMenu);
        if (this.authService.currentSidebarMenu && this.authService.currentSidebarMenu.length > 0
            && this.routerNav.url && this.routerNav.url !== '/') {
                const indexSlash = this.routerNav.url.indexOf('/', 1);

                let curUrl = this.routerNav.url;

                if (indexSlash !== -1) { curUrl = curUrl.substr(0, indexSlash); }

                const i = curUrl.indexOf('?');
                if (i === -1) {
                    const m = this.authService.currentSidebarMenu.find(s => s.routerLink === curUrl);

                    if (!m) {
                        console.log('url not found');
                        this.ResetFlagAndRedirectToHome();
                        return false;
                    } else if (curUrl !== this.authService.currentUrl) {
                        console.log('url not authorize');
                        this.ResetFlagAndRedirectToHome();
                        return false;
                    }
                } else {
                    const preUrl = curUrl.substr(0, i);

                    const menus = this.authService.currentSidebarMenu.filter(s => s.routerLink === preUrl);
                    console.log(menus);

                    if (!menus || menus.length === 0) {
                        console.log('url not found');
                        this.ResetFlagAndRedirectToHome();
                        return false;
                    } else if (curUrl !== this.authService.currentUrl) {
                        console.log('url not authorize');
                        this.ResetFlagAndRedirectToHome();
                        return false;
                    }

                    let found = false;

                    const queryParams = curUrl.substr(i + 1, curUrl.length - i - 1);

                    const queryParam = queryParams.split(',');

                    // queryParam.forEach(q => {
                    //     q = '\"' + q.replace('=', '\":\"') + '\"';
                    // });

                    menus.forEach(menu => {
                        queryParam.forEach(q => {
                            menu.queryParams = menu.queryParams.replace(/:/g, '=');
                            menu.queryParams = menu.queryParams.replace(/"/g, '');

                            const iq = menu.queryParams.indexOf(q);

                            if (iq !== -1) {
                                found = true;
                            }
                        });
                    });

                    if (!found) {
                        console.log('url not found');
                        this.ResetFlagAndRedirectToHome();
                        return false;
                    }

                }
        }

        return true;
    }

    onBackButtonClick(routerLink = '') {
        // this.locationNav.back();
        const currentUrl = routerLink === '' ? this.authService.currentUrl : routerLink;
        this.authService.ResetFlag();
        this.authService.currentUrl = currentUrl;
        if (routerLink === '' && !this.objectIsNull(this.objectservice.queryParamObj)
            && !this.objectIsNull(this.objectservice.queryParamObj.id)) {
            this.routerNav.navigate([currentUrl], { queryParams: {id: this.objectservice.queryParamObj.id} });
        } else {
            this.routerNav.navigate([currentUrl]);
        }
    }

    OcChangeAction(currentOC) {
        if (this.authService.previousOC == null) {
            this.authService.previousOC = currentOC;
            this.ResetFlagAndRedirectToHome();
            return;
        } else if ((this.authService.previousOC !== currentOC)) {
            this.authService.previousOC = currentOC;
            this.ResetFlagAndRedirectToHome();
            return;
        } else if (this.authService.pageState === 'back') {
            this.ResetFlagAndRedirectToHome();
            return;
        }

        if (this.authService.getById) { // input page
            this.baseblockUI.start('Loading...');
            this.objectservice.GetById(this.objectservice.data['id']).subscribe(res => {
            //    this.authService.getById = false;
                if (res == null) {
                    this.messageService.add({ severity: 'Info', summary: 'Info',
                    detail: 'Object not found' });
                    this.ResetFlagAndRedirectToHome();
                }

                this.selectedObject = res;
                this.baseblockUI.stop();
                this.loadFormValues();
                this.ngOnInitLocal();
                this.getHasFieldAuditLog();
            });
        } else if (this.authService.isAdd) {
            this.loadFormValues();
            this.ngOnInitLocal();
        }

        if (this.authService.pageName === 'List') { // listing page
            this.ngOnInitLocal();
            this.GetList();
        } else if (this.authService.pageName === 'Customize') {
            this.ngOnInitLocal();
        }
    }

    loadFormValues() {
        try {
            if (this.selectedObject === undefined && !this.authService.isAdd) {
              this.onBackButtonClick();
            }
            let obj = <T>{};
            obj = this.objEmptyFuntion.empty();
            if (!this.authService.isAdd) {
                for (const prop of Object.keys(obj)) {
                    try {
                        obj[prop] = this.selectedObject[prop];
                    } catch (error) {
                    }
                }
                obj['isLocked'] = false;
              this.selectedObject = obj;
              this.customFormValues();
              (<FormGroup>this.userform).patchValue(this.selectedObject, { onlySelf: true });
            } else {
              this.selectedObject = obj;
              (<FormGroup>this.userform).patchValue(this.selectedObject, { onlySelf: true });
            }
        } catch (error) {
            console.log(this.selectedObject);
            console.error(error);
            this.messageService.add({ key: 'errorDialog', sticky: true, severity: 'error',
            summary: 'Error', detail: error });
        }
    }

    customFormValues() {}

    getHasFieldAuditLog() {
        this.auditTrailService.GetHasChanges(this.strTableName, this.selectedObject.id).subscribe(res => {
          this.objHasAuditField = res;
        }, error => {
          console.error(error);
        });
    }

    getHasAuditLog(objectlist, dt: EtableComponent) {
        if (!this.auditTrailService) { return; }

        const hasChangesList: LogHasChangeById[] = [];

        objectlist.forEach(element => {
            const o: LogHasChangeById = { id: element.id, hasChanges: false };
            hasChangesList.push(o);
        });

        const specifyLogHasChangeById: SpecifyLogHasChangeById = {
            fieldsToCheck: this.logColumnList,
            recordsToCheck: hasChangesList
         };

        this.auditTrailService.HasSpecifyChangesList(this.strTableName, specifyLogHasChangeById).subscribe(res => {
            if (res && res.recordsToCheck) {
                res.recordsToCheck.forEach(s => {
                    if (s.hasChanges) {
                        const obj = objectlist.find(o => o.id === s.id);
                        if (obj !== null) { obj['hasChanges'] = true; }
                    }
                });
            }
            dt.detectChanges();
        }, error => {
            console.error(error);
        });
    }

    saveResponse(response: any) {
        this.baseblockUI.stop();

        if (response == null) { return; }
        const errorMessages = [];

        if (!response.synced) {
          if (response.errorList && Object.keys(response['errorList']).length > 0) {
            // tslint:disable-next-line: forin
            for (const item in response.errorList) {
              errorMessages.push(response.errorList[item][0]);
            }
          } else {
            errorMessages.push(response.errorMessage);
          }
          this.showMultipleErrorMessage(errorMessages);
          // this.messageService.add({
          //   key: 'multipleErrorDialog', sticky: true, severity: 'error',
          //   summary: 'Error',
          //   data: errorMessages
          // });
          return;
        }
        let saveMessage;
        if (this.authService.isAdd) {
          this.isnewobject = false;
          saveMessage = 'Records Saved';
        } else {
          saveMessage = 'Records Updated';
        }
        try {
          this.showSuccessMessage(saveMessage);
         // this.messageService.add({ severity: 'success', summary: 'Success', detail: saveMessage });
        } catch (error) {
          console.log('error: ' + error);
          return;
        }
        this.authService.getById = false;
        this.authService.isAdd = false;
        this.selectedObject = null;
        this.displayDialog = false;
        if (this.authService.pageName === 'Input') {
          this.onBackButtonClick();
        } else if (this.authService.pageName === 'List') {
          this.GetList();
        }
      }

      GetList() {
        this.list();
    }

    onRowAdd() {
        this.onRowAddUpdateObject();
        this.authService.isAdd = true;
        this.routerNav.navigate(['input'], { relativeTo: this.route });
    }

    onRowEdit(row: T) {
        this.onRowEditUpdateObject(row);
        this.objectservice.data = row;
        this.authService.isAdd = false;
        this.authService.getById = true;
        this.routerNav.navigate(['input'], { relativeTo: this.route });
    }

    formValidationOnSubmit(): boolean {
        return true;
    }

    onRowInsert() {
        if (!this.mandatoryChecking()) {
            return;
        }

        this.baseblockUI.start('Loading...');

        if (!this.formValidationOnSubmit()) {
            this.baseblockUI.stop();
            return;
        }

        // for (const field in this.userform.controls) {
        //     this.selectedObject[field] = this.userform.get(field).value;
        //   }

        Object.keys(this.userform.controls).forEach(key => {
            this.selectedObject[key] = this.userform.get(key).value;
        });

          this.setItemBeforeSave();

        if (this.authService.isAdd) {
            this.selectedObject['id'] = '00000000-0000-0000-0000-000000000000';
            this.selectedObject['ocCode'] = this.authService.getSelectedOc();
            console.log(this.selectedObject);
            this.objectservice.Create(this.selectedObject)
                .subscribe(res => {
                    this.saveResponse(res);
                });
        } else {
            console.log(this.selectedObject);
            if (!this.selectedObject.isLocked) {
                //  rowObject.empID = this.overtimeForm.get("empID").value;
                //  rowObject.transDate = this.overtimeForm.get("transDate").value;
                this.objectservice.Update(this.selectedObject)
                    .subscribe(res => {
                        this.saveResponse(res);
                    });
            } else {
                this.baseblockUI.stop();
                this.messageService.add({ severity: 'Info', summary: 'Info',
                detail: 'The object is updated, pelase refresh the page.' });
                return;
            }
        }

    }

    ngOnDestroy() {
        if (this.SelectedOcChangedSubscription !== undefined) {
            this.SelectedOcChangedSubscription.unsubscribe();
        }
        if (this.detectRefresSubscription !== undefined) {
            this.detectRefresSubscription.unsubscribe();
        }
        if (this.detectBackSubscription !== undefined) {
            this.detectBackSubscription.unsubscribe();
        }
        if (this.totalDropdownSubscription !== undefined) {
            this.totalDropdownSubscription.unsubscribe();
        }
        if (this.listServiceDoneSubscription !== undefined) {
            this.listServiceDoneSubscription.unsubscribe();
        }
        this.webNotificationservice.off();
        if (this.blockUiControl) {
            this.baseblockUI.stop();
        }
        this.objectlist = [];
    }

    enableControl(ctrlName: string, resetValue: boolean = true, defaultValue: any = '') {
        if (resetValue) { this.userform.get(ctrlName).setValue(defaultValue); }
        this.userform.get(ctrlName).enable();
    }

    disableControl(ctrlName: string, resetValue: boolean = true, defaultValue: any = '') {
        if (resetValue) { this.userform.get(ctrlName).setValue(defaultValue); }
        this.userform.get(ctrlName).markAsPristine();
        this.userform.get(ctrlName).disable();
    }

    // resetCheckBox(ctrlName: string) {
    //     this.userform.get(ctrlName).setValue(false);
    // }

    setRequiredValidator(ctrlName: string, resetValue: boolean = true, defaultValue: any = null
        , validator: any = [Validators.required]) {
        this.userform.get(ctrlName).setValidators(validator);
        this.userform.get(ctrlName).updateValueAndValidity();
        this.mandatoryField[ctrlName] = true;
        if (resetValue) {
            this.userform.get(ctrlName).setValue(defaultValue);
            // this.userform.get(ctrlName).markAsDirty();
        }
    }

    setNotRequiredValidator(ctrlName: string, resetValue: boolean = true, defaultValue: any = ''
        , validator: any = null) {
        // this.userform.get(ctrlName).clearValidators();
        this.userform.get(ctrlName).setValidators(validator);
        this.userform.get(ctrlName).updateValueAndValidity();
        this.mandatoryField[ctrlName] = false;
        if (resetValue) {
            this.userform.get(ctrlName).setValue(defaultValue);
            this.userform.get(ctrlName).markAsPristine();
        }
    }

    showInputPageActionHeaderTitle(): string {
        let inputPageHeaderTitle;
        if (this.authService.isAdd) {
            inputPageHeaderTitle = 'Add Mode';
        } else {
            inputPageHeaderTitle = 'Edit Mode';
        }
        return inputPageHeaderTitle;
    }

    getAllErrors(form: FormGroup | FormArray): { [key: string]: any; } | null {
        let hasError = false;
        const result = Object.keys(form.controls).reduce((acc, key) => {
            const control = form.get(key);
            const errors = (control instanceof FormGroup || control instanceof FormArray)
                ? this.getAllErrors(control)
                : control.errors;
            if (errors) {
                if (!acc['Error']) { acc['Error'] = ''; }
                const err = this.errorMessages[key] ? this.errorMessages[key] : key;
                acc['Error'] += err + ', ',
                hasError = true;
            }
            return acc;
        }, {} as { [key: string]: any; });
        return hasError ? result : null;
    }

    getFormErrors(form: FormGroup | FormArray): any {
        if (form.status === 'INVALID') {
            let errMsg = '';
            const errors = form.errors;
            if (errors && errors !== null) {
                Object.keys(errors).forEach(key => {
                    const err = this.errorMessages[key] ? this.errorMessages[key] : key;
                    errMsg += err + ', ';
                });
                return errMsg;
            }
        }
        return null;
    }

    getAllError(form: FormGroup | FormArray): any {
        const result = this.getAllErrors(form);
        const resultFrom = this.getFormErrors(form);
        if (result === null && resultFrom === null) { return 'Save';
        } else if (resultFrom === null) { return result['Error'];
        } else if (result === null) { return resultFrom;
        } else { return resultFrom + result['Error']; }
    }

    showSuccessMessage(Message: string, summary = 'Success') {
        this.messageService.add({ severity: 'success',
        summary: summary, detail: Message });
    }

    showInfoMessage(Message: string, summary = 'Info') {
        this.messageService.add({ severity: 'info',
        summary: summary, detail: Message });
    }

    showErrorMessage(Message: string, summary = 'Error') {
        this.messageService.add({ key: 'errorDialog', sticky: true, severity: 'error',
        summary: summary, detail: Message });
    }

    showMultipleErrorMessage(Messages: string[], Message = '', summary = 'Error') {
        this.messageService.add({ key: 'multipleErrorDialog', sticky: true, severity: 'error',
        summary: summary, detail: Message, data: Messages });
    }

    getSelectedRecords(): T[] {
        if (this.objectlist && this.objectlist !== null) {
            return this.objectlist.filter(item => item['isSelected'] === true);
        } else {
            return [];
        }
    }

    onRowSelect(event: any, field: string) {
        if (field !== 'onSelectAllClick') {
            this.selectedObject = event;
        }

        switch (field) {
            case 'onRowSelect': { // for user management
                this.edit(event);
                break;
            }
            case 'deleteRecord': { // for user management
                this.deleteRecord(event);
                break;
            }
            case 'onEdit': {
                this.onRowEdit(event);
                break;
            }
            case 'onDelete': {
                this.onRowDelete(event);
                break;
            }
            case 'onRestore': {
                this.onRowRestore(event);
                break;
            }
            case 'onActivate': {
                this.onActivate(event);
                break;
            }
            case 'onSelectAllClick': {
                this.onSelectAllClick(event, field);
                break;
            }
            case 'isSelected': {
                this.onIsSelected(event);
                break;
            }
            default: {
                console.log('Invalid choice');
                break;
            }
        }
    }

    onIsSelected(event) {
        if (event.isSelected === true) {
            this.disableDeleteButton = false;
            return;
        }

        const x = this.objectlist.find(s => s['isSelected'] === true);

        if (x) {
            this.disableDeleteButton = false;
        } else {
            this.disableDeleteButton = true;
        }
    }

    onSelectAllClick(event: any, field: string) {
        this.objectlist.forEach(s => {
            s['isSelected'] = event.args === true ? true : false;
        });

        if (event.args === true) {
            this.disableDeleteButton = false;
        } else {
            this.disableDeleteButton = true;
        }
    }

}
