import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { environment } from '../../environments/environment';
import { Observable, EMPTY, throwError } from 'rxjs';
import * as crypto from 'crypto-js';
import { catchError, map, finalize } from 'rxjs/operators';
import { Router } from '@angular/router';
import { SharedService } from './shared.service';
// import { AlertService } from './shared-alert.service';
import { RequestPayLoadFormat } from './common-service-layer.service';
import { Config } from './config';
import { SessionService } from './session.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { LoaderServiceService } from '../common-components/loader/loader-service.service';
import { ToastrService } from '../common-components/toastr/toastr.service';


@Injectable({
    providedIn: 'root'
})
export class HttpLayerService {
    public currentRequest;
    private monitoring = {
        pendingRequestsNumber: 0
    };
    public currentDomain: any = window.location.hostname;


    public httpOptions = {
        headers: new HttpHeaders({
            'Content-Type': 'application/json'
        })
    };

    constructor(
        private http: HttpClient,
        private router: Router,
        private loaderService: LoaderServiceService,
        private sharedService: SharedService,
        private _toast: ToastrService,
        // private sessionService: SessionHandlerService,
        // private alert: AlertService,
        private session: SessionService,
        private modalService: NgbModal
    ) {
    }
    public AESencrypt(value: string, key: string): string {
        return crypto.AES.encrypt(value, key);
    }

    public AESdecrypt(textToDecrypt: string, key: string) {
        return crypto.AES.decrypt(textToDecrypt, key);
    }

    // tslint:disable:typedef
    get(url, request: RequestPayLoadFormat): Observable<any> {
        try {
            if (request.loader) {
                this.showLoader();
            }
            const headerJson = {
                Accept: 'application/json',
            };
            const headerOptions = { headers: new HttpHeaders(headerJson) };
            return this.handleResponse(this.http.get(
                url, headerOptions), request, url).pipe(finalize(() => {
                }));
        } catch (error) {
            console.log(error);
            return EMPTY;
        }
    }

    post(url, request: RequestPayLoadFormat): Observable<any> {
        request = JSON.parse(JSON.stringify(request));
        this.currentRequest = request;
        try {
            if (request.loader) {
                this.showLoader();
            }
            if (request.api === 'REFRESH_SESSION') {
                this.session.api.session.save('refresh', true);
            }
            if (!request.payLoad) {
                request.payLoad = {};
            }
            let headerJson: any = request.options ? request.options : {
                'Content-Type': 'application/json'
            };
            // let temp = this.getUserInfo();
            headerJson = { ...headerJson, ...this.getUserInfo() }
            // if (this.session.api.local.get(Config.ID_TOKEN)) {
            //     headerJson.idtoken = this.session.api.local.get(Config.ID_TOKEN);
            // }
            // if (this.session.api.local.get(Config.ACCESS_TOKEN)) {
            //     headerJson.accesstoken = this.session.api.local.get(Config.ACCESS_TOKEN);
            // }
            // if (this.session.api.local.get(Config.USER_IDENTIFIER)) {
            //     headerJson.userid = this.session.api.local.get(Config.USER_IDENTIFIER);
            // }
            // if (this.session.api.local.get(Config.USER_ROLE)) {
            //     headerJson.roleid = this.session.api.local.get(Config.USER_ROLE);
            // }
            // if (this.session.api.local.get(Config.PAGE_ID)) {
            //     headerJson.pageid = this.session.api.local.get(Config.PAGE_ID);
            // }
            headerJson.requestStartTime = String(new Date().getTime() / 1000);
            const headersConfig = new HttpHeaders(headerJson);
            const paramsConfig = request.params ?
                new HttpParams({ fromObject: JSON.parse(JSON.stringify(request.params)) }) : undefined;
            const requestOptions = {
                headers: headersConfig,
                params: paramsConfig
            };
            const body = request.payLoad;
            return this.handleResponse(this.http.post(
                url, body, requestOptions), request, url).pipe(finalize(() => {
                }));
        } catch (error) {
            console.log(error);
            return EMPTY;
        }
    }

    postDownload(url, request: RequestPayLoadFormat): Observable<any> {
        request = JSON.parse(JSON.stringify(request));
        this.currentRequest = request;
        try {
            if (request.loader) {
                this.showLoader();
            }
            if (!request.payLoad) {
                request.payLoad = {};
            }
            let headerJson: any = request.options ? request.options : {
                'Content-Type': 'application/json',
                'Accept': 'text/html, application/xhtml+xml, /',
            };
            headerJson = { ...headerJson, ...this.getUserInfo() }
            // if (this.session.api.local.get(Config.ID_TOKEN)) {
            //     headerJson.idtoken = this.session.api.local.get(Config.ID_TOKEN);
            // }
            // if (this.session.api.local.get(Config.ACCESS_TOKEN)) {
            //     headerJson.accesstoken = this.session.api.local.get(Config.ACCESS_TOKEN);
            // }
            // if (this.session.api.local.get(Config.USER_IDENTIFIER)) {
            //     headerJson.userid = this.session.api.local.get(Config.USER_IDENTIFIER);
            // }
            // if (this.session.api.local.get(Config.USER_ROLE)) {
            //     headerJson.roleid = this.session.api.local.get(Config.USER_ROLE);
            // }
            // if (this.session.api.local.get(Config.PAGE_ID)) {
            //     headerJson.pageid = this.session.api.local.get(Config.PAGE_ID);
            // }
            headerJson.requestStartTime = String(new Date().getTime() / 1000);
            const headersConfig = new HttpHeaders(headerJson);
            const paramsConfig = request.params ?
                new HttpParams({ fromObject: JSON.parse(JSON.stringify(request.params)) }) : undefined;
            const requestOptions = {
                headers: headersConfig,
                // params: paramsConfig,
                responseType: 'arraybuffer' as 'json'
            };
            const body = request.payLoad;
            return this.handleResponse(this.http.post(
                url, body, requestOptions), request, url).pipe(finalize(() => {
                }));
        } catch (error) {
            console.log(error);
            return EMPTY;
        }
    }

    postText(url, request: RequestPayLoadFormat): Observable<any> {
        request = JSON.parse(JSON.stringify(request));
        try {
            if (request.loader) {
                this.showLoader();
            }
            const headerJson: any = request.options ? request.options : {
                'Content-Type': 'text/plain',
            };
            const headersConfig = new HttpHeaders(headerJson);
            const requestOptions: any = { headersConfig, responseType: 'text' };
            const userDetails = this.getUserDetails();
            request.payLoad = Object.assign(userDetails, request.payLoad);
            const body = JSON.stringify(request.payLoad);
            return this.handleResponse(this.http.post(
                url, body, requestOptions).pipe(map((res: any) => {
                    res = JSON.parse(res);
                    return res;
                })), request, url
            ).pipe(finalize(() => {
            }));
        } catch (error) {
            console.log(error);
            return EMPTY;
        }
    }

    postFile(url, request: RequestPayLoadFormat): Observable<any> {
        /**
         * With header 'Content-Type': 'multipart/form-data' file was not getting in BE
         */
        // const headerJson = {
        //     Accept: 'application/json',
        // };
        let headerJson: any = request.options ? request.options : {
            Accept: 'application/json'
        };
        headerJson = { ...headerJson, ...this.getUserInfo() }
        // if (this.session.api.local.get(Config.ID_TOKEN)) {
        //     headerJson.idtoken = this.session.api.local.get(Config.ID_TOKEN);
        // }
        // if (this.session.api.local.get(Config.ACCESS_TOKEN)) {
        //     headerJson.accesstoken = this.session.api.local.get(Config.ACCESS_TOKEN);
        // }
        // if (this.session.api.local.get(Config.USER_IDENTIFIER)) {
        //     headerJson.userid = this.session.api.local.get(Config.USER_IDENTIFIER);
        // }
        // if (this.session.api.local.get(Config.USER_ROLE)) {
        //     headerJson.roleid = this.session.api.local.get(Config.USER_ROLE);
        // }
        // if (this.session.api.local.get(Config.PAGE_ID)) {
        //     headerJson.pageid = this.session.api.local.get(Config.PAGE_ID);
        // }
        // const headersConfig = new HttpHeaders(headerJson);
        // const paramsConfig = request.params ?
        //     new HttpParams({ fromObject: JSON.parse(JSON.stringify(request.params)) }) : undefined;
        // const requestOptions = {
        //     headers: headersConfig,
        //     params: paramsConfig
        // };
        const headerOptions = { headers: new HttpHeaders(headerJson) };
        try {
            if (request.loader) {
                this.showLoader();
            }
            if (request.payLoad) {
                request.formData.set('metaData', JSON.stringify(request.payLoad));
            }
            request.formData.set('userName', localStorage.getItem('userName'));
            request.formData.set('userId', localStorage.getItem('userId'));
            return this.handleResponse(this.http.post(
                url, request.formData, headerOptions), request, url).pipe(finalize(() => {
                }));
        } catch (error) {
            console.log(error);
            return EMPTY;
            // throw 500;
        }
    }

    getUserInfo() {
        try {
            let headerJson: any = {}
            if (this.session.api.local.get(Config.ID_TOKEN)) {
                headerJson.idtoken = this.session.api.local.get(Config.ID_TOKEN);
            } else {
                headerJson.idtoken = 'test';
            }
            if (this.session.api.local.get(Config.ACCESS_TOKEN)) {
                headerJson.accesstoken = this.session.api.local.get(Config.ACCESS_TOKEN);
            } else {
                headerJson.accesstoken = 'test';
            }
            if (this.session.api.local.get(Config.USER_IDENTIFIER)) {
                headerJson.userid = this.session.api.local.get(Config.USER_IDENTIFIER);
            }
            if (this.session.api.local.get(Config.USER_ROLE)) {
                headerJson.roleid = this.session.api.local.get(Config.USER_ROLE);
            }
            if (this.session.api.local.get(Config.PAGE_ID)) {
                headerJson.pageid = this.session.api.local.get(Config.PAGE_ID);
            }
            return headerJson;
        } catch (error) {
            console.log(error);
        }
    }

    getUserDetails() {
        try {
            return {
                userName: localStorage.getItem('userName'),
                userRole: localStorage.getItem('userRole'),
                userId: localStorage.getItem('userId'),
            };
        } catch (error) {
            console.log(error);
            return {};
        }
    }

    getUseruserCredentialData() {
        try {
            return {
                userData: localStorage.getItem('userData'),
            };
        } catch (error) {
            console.log(error);
            return {};
        }
    }



    handleResponse(observable: Observable<any>, request?, url?): Observable<any> {
        try {
            return observable.pipe(catchError((err) => {
                if (err.status === 401) {
                    console.log(url, request);
                    console.log(this.session.api.session.get('refresh'));
                    if (this.session.api.session.get('refresh')) {
                        if (request.loader) {
                            this.hideLoader();
                        }
                        setTimeout(() => {
                           // window.location.reload();
                        }, 1000);

                    } else {
                        if (request.loader) {
                            this._toast.toast('error', '', environment.sessionInvalidMessage, true);
                            // this._toast.toast('error', environment.sessionInvalidMessage,   err.error.detail || err.message, true);
                            // const alertConf: AlertConfig = { type: 'error', title: environment.sessionInvalidMessage, body: err.message };
                            // this.alert.open(alertConf);
                        }
                        setTimeout(() => {
                            this.logOut();
                        }, 1000);
                    }
                } else {
                    if (request.loader) {
                        this.sharedService.handleHttpErrorResponse(err);
                    }
                }
                // tslint:disable-next-line: deprecation
                return throwError(err);
            })).pipe(finalize(() => {
                const d1 = new Date();
                Config.CONSTANTS.LAST_API_CALL_TIME = d1.getTime();
                if (request.api) {
                    this.session.api.session.save(request.api + Math.random(), d1.getTime() / 1000);
                }
                if (request.api && request.api === 'REFRESH_SESSION') {
                    setTimeout(() => {
                        this.session.api.session.remove('refresh');
                    }, 10000);
                }
                if (request.loader) {
                    this.hideLoader();
                }
            }));
        } catch (e) {
            console.log(e);
            return EMPTY;
        }
    }

    public logOut() {
        localStorage.clear();
        sessionStorage.clear();
        document.cookie = null;
        this.modalService.dismissAll();
        this.router.navigate(['p/login']);
    }

    public handleError(error: any) {
        const errMsg = (error.message) ? error.message :
            error.status ? `${error.status} - ${error.statusText}` : 'Server error';
        // tslint:disable-next-line: deprecation
        return throwError(() => new Error('errMsg'));
    }

    private showLoader(): void {
        this.monitoring.pendingRequestsNumber++;
        this.loaderService.show();
    }

    private hideLoader(): void {
        this.monitoring.pendingRequestsNumber--;
        if (this.monitoring.pendingRequestsNumber <= 0) {
            this.loaderService.hide();
        }
    }
}
