import { Component, OnInit, OnDestroy, TemplateRef, ViewChild } from "@angular/core";
import { Page, IUserAccount, Pagination, IResource } from "@shared/models";
import { AppData, HttpService, NotifyService, ResourceService } from "@shared/services";
import { takeUntil, finalize } from "rxjs/operators";
import { NgbModalRef, NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { ApiResources, UtilHelper } from "@shared/helpers";
import { UserImportHistory, PatientRawImport, PateintImportHistory } from "@shared/entities";
//import readXlsxFile from "read-excel-file";
import readXlsxFile from 'xlsx/xlsx.js';
import { HttpErrorResponse } from "@angular/common/http";
import { Patient } from "@shared/entities";
import * as moment from "moment";

class PreDefinedHeaders {
    patientHeader: Array<string>; 

    constructor() {      
        this.patientHeader = ["UmrNo","Salutation(*)", "FirstName(*)", "LastName(*)", "Mobile(*)", "Gender(*)(F/M)", "DateOfBirth(DD/MM/YYYY)", "Age(*)", "Email", "Address(*)", "PinCode", "Relation", "RelativeName", "RelativeMobile"];
       //                    Salutation(*)	FirstName(*)	LastName(*)	Mobile(*)	Gender(*)	DateOfBirth(*)(DD / MM / YYYY)	Age(*)	Email	Address(*)	PinCode	Relation  	RelativeName 	RelativeMobile

    }
}

class Threading {
    totalRecord: number = 0;
    inUploading: number = 0;
    percentage: number = 0;
    currentlyUploaded: number = 0;
}

class FilterOption {
}

class Filter {
    options: FilterOption;
    applied: boolean;
    constructor() {
        this.init();
    }
    init() {
        this.applied = false;
        this.options = new FilterOption();
    }
}

class ReturnTuples {
    item1: any;
    item2: Array<any>;
}

@Component({
    templateUrl: "./patient-import.html",
    styleUrls: ['./patient-import-excel.css']
})
export class PatientImportPage implements OnInit, OnDestroy {
    @ViewChild("templateReturnedData", { static: true }) templateReturnedData: TemplateRef<any>;

    page: Page;
    loading: boolean;
    modalRef: NgbModalRef;
    pagination: Pagination;
    excelHistory: Array<PateintImportHistory>;
    filters: Filter;
    headerClass: PreDefinedHeaders;
    isUploading: boolean;
    fileUploadFail: boolean;
    loadingFile: boolean;
    uploadedFile: File;
    sheetName: string;
    rawRecords: Array<any>;
    rawPatients: Array<PatientRawImport>;
    isUploadingPatientSheet: boolean;
    submitting: boolean;
    threading: Threading;
    rawPatientProcessed: Array<any>;
    loadingLocations: boolean;
    locations: Array<IResource>;
    loadingRoles: boolean;
    roles: Array<IResource>;
    recordsPerThread: number;
    selectedHistory: UserImportHistory;
    loadingPatients: boolean;
    patient: Array<Patient>;
    isDuplicate: boolean;
    isDuplicatePatient: boolean;
    returnedData: Array<ReturnTuples>;
    mobNumberPattern = "^((\\+91-?)|0)?[0-9]{10}$";
    emailPattern: "/^[\w-]+(?:\.[\w-]+)*@(?:[\w-]+\.)+[a-zA-Z]{2,7}$/";
    mobileFilter: any;
    EmailFilter: any;
    whiteSpace: any;
    dateFilter: any;
    isEmail: boolean;
    loadingRelations: boolean;
    relations: Array<IResource>;
    isValidFormSubmitted = false;
    checkEmail: any;    
    checkMobileValid: any;
    date: any;
    checkEmailInfo: number;
    patients: Array<Patient>;
    flag: boolean;
    constructor(
        private readonly appData: AppData,
        private readonly modalService: NgbModal,
        private readonly httpService: HttpService,
        private readonly notifyService: NotifyService,
        private readonly resourceService: ResourceService
    ) {
        this.dateFilter = new RegExp( /^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g);
        this.whiteSpace = new RegExp(/^[\s]{1,}|[\s]{2,}|[\s]{1,}$/);
        this.mobileFilter = new RegExp(/^\b\d{10}?\b$/);
        this.EmailFilter = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
        this.page = new Page();
        this.initPagination();
        this.filters = new Filter();
        this.excelHistory = new Array<PateintImportHistory>();
        this.headerClass = new PreDefinedHeaders();
        this.rawRecords = new Array<any>();
        this.rawPatients = new Array<PatientRawImport>();
        this.threading = new Threading();
        this.rawPatientProcessed = new Array<any>();
        this.locations = new Array<IResource>();
        this.roles = new Array<IResource>();
        this.recordsPerThread = 50;
        this.selectedHistory = new UserImportHistory();
        this.patient = new Array<Patient>();
        this.returnedData = new Array<ReturnTuples>();
        this.date = new Date().toLocaleDateString();
    }

    initPagination() {
        this.pagination = new Pagination();
        this.pagination.pageSize = 12;
        this.pagination.pageIndex = 1;
    }
    checkText(record) {
       
        if (this.whiteSpace.test(record.address)) {
            record.isAddress = true;
        }
        else {
            record.isAddress = false;
        }
    }
    matchPatientRole(record) {
        if (!record.role) {
            record.isMatchRole = false;
            return;
        }
        let find = this.roles.find(x => x.value.toLowerCase() === record.role.toLowerCase());
        if (find != null) {
            record.role = find.value;
            record.isMatchRole = true;
            record.roleId = find.id;
        }
        else {
            record.role = null;
            record.isMatchRole = false;
        }
    }

    matchPatientMail(record) {
        if (!record.email) {
            record.isEmail = false;
            return;
        }
        let find = this.roles.find(x => x.value.toLowerCase() === record.role.toLowerCase());
        if (find != null) {
            record.role = find.value;
            record.isMatchRole = true;
            record.roleId = find.id;
        }
        else {
            record.role = null;
            record.isMatchRole = false;
        }
    }

    onMatchRoles() {
        this.rawPatientProcessed.forEach((item) => {
            this.matchPatientRole(item);
        });
    }

    matchPatientLocation(record) {
        if (!record.location) {
            record.isMatchLocation = false;
            return;
        }
        let find = this.locations.find(x => x.name.toLowerCase() === record.location.toLowerCase());
        if (find != null) {
            record.location = find.name;
            record.isMatchLocation = true;
            record.locationIds = find.id;
            let myInt = find.id;
            // Getting the string as a parameter
            // and typecasting it into an integer
            let myFunc = num => Number(num);
            let intArr = Array.from(String(myInt), myFunc);
            record.locationIds = intArr;
            record.locationId = intArr;
        }
        else {
            record.location = null;
            record.isMatchLocation = false;
        }
    }
    onMatchLocation() {
        this.rawRecords.forEach((item) => {
            this.matchPatientLocation(item);
        });
    }

    fetchUploadHistory() {
        this.loading = true;
        const request = Object.assign(UtilHelper.clone(this.filters.options), this.pagination);

        this.httpService.post(ApiResources.getURI(ApiResources.patientImport.base, ApiResources.patientImport.fetchUploadHistory), request)
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => this.loading = false))
            .subscribe((response: Array<PateintImportHistory>) => {
                this.excelHistory = response
                UtilHelper.applyPagination(this.excelHistory, this.pagination);
            }, () => {
                this.excelHistory = new Array<PateintImportHistory>();
                this.notifyService.error("Error occured in fetching upload history.");
            });
    }

    onFileUpload(event) {
        this.loadingFile = true;
        this.uploadedFile = event.target.files[0];
        this.fileUploadFail = false;
        this.sheetName = this.uploadedFile.name;
        let extension = this.uploadedFile.name.split(".").pop();
        if (extension === "xlsx" || extension === "xls") {
            this.fileChangeEvent();
        }
        else {
            this.loadingFile = false;
            this.uploadedFile = null;
            this.fileUploadFail = true;
        }
    }

    private fetchRelations() {
        this.loadingRelations = true;
        this.resourceService.relationships()
            .pipe(finalize(() => { this.loadingRelations = false }))
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe((response: Array<IResource>) => {
                this.relations = response;
            });
    }
    fileChangeEvent() {
        let records = [];
        setTimeout(() => {
            readXlsxFile(this.uploadedFile).then((rows) => {
                let index = 0;
                for (let row of rows) {
                    if (index === 0) {
                        let checkArray = new Array<string>();
                        for (let single of row) {
                            checkArray.push((single as any).toString());
                        }
                        let headerAsArray = JSON.stringify(checkArray);
                        let patientHeader = JSON.stringify(this.headerClass.patientHeader);
                        if (headerAsArray === patientHeader) {
                            this.isUploadingPatientSheet = true;
                        }
                        else {
                            this.notifyService.warning("Sheet Cannot be Uploaded, Sheet might not Match with Sample Sheet provided!");
                            break;
                        }
                    }
                    else {
                        var x = this.checkNull(row[6] as any) ? row[6].toString().trim() : "";
                        this.checkEmail = this.EmailFilter.test(x);
                       
                        if (this.EmailFilter.test(x)) {
                            this.isEmail = true;
                        }
                        else {
                            this.isEmail = false;
                        }
                        records.push({
                            umrNo: this.checkNull(row[0] as any) ? row[0].toString().trim() : "",
                            salutation: this.checkNull(row[1] as any) ? row[1].toString().trim() : "",
                            firstName: this.checkNull(row[2] as any) ? row[2].toString().trim() : "",
                            lastName: this.checkNull(row[3] as any) ? row[3].toString().trim() : "",
                            mobile: this.checkNull(row[4] as any) ? row[4].toString().trim() : "",                           
                            dateOfBirth: UtilHelper.isEmpty(row[6] as any) ? moment(new Date(row[6].toString().trim())).format("DD-MM-YYYY") : null,
                            age: this.checkNull(row[7] as any) ? row[7].toString().trim() : "",
                            email: this.checkNull(row[8] as any) ? row[8].toString().trim() : "",
                            address: this.checkNull(row[9] as any) ? row[9].toString().trim() : "",
                            gender: this.checkNull(row[5] as any) ? row[5].toString()[0].trim() : "",
                            pinCode: this.checkNull(row[10] as any) ? row[10].toString().trim() : "",
                            relationType: this.checkNull(row[11] as any) ? row[11].toString().trim() : "",
                            relativeName: this.checkNull(row[12] as any) ? row[12].toString().trim() : "",
                            relativeMobile: this.checkNull(row[13] as any) ? row[13].toString().trim() : "",
                            isMatchLocation: true,
                            isMatchRole: true,
                            isEmail: this.isEmail,
                            isAddress:this.whiteSpace                            
                        })
                    }
                    index++;
                }
                if (this.isUploadingPatientSheet) {
                    this.rawRecords = records;
                    this.rawPatientProcessed = records
                    this.threading.totalRecord = this.rawRecords.length;   
                    this.fetchRelations();
                    setTimeout(() => {
                        this.onPatientSheet();
                    }, 1000)
                }
                this.loadingFile = false;
            });
        }, 1000);
    }

    onPatientSheet() {
        this.rawPatientProcessed = new Array<any>();
        this.rawRecords.forEach((patient) => {
            let patientModel = {
                umrNo: patient.umrNo,
                salutation: patient.salutation,
                firstName: patient.firstName,
                lastName: patient.lastName,               
                mobile: patient.mobile,
                dateOfBirth: patient.dateOfBirth,
                age: patient.age,
                email: patient.email,
                address: patient.address,
                pinCode: patient.pinCode,
                relationType: patient.relationType,
                gender: patient.gender,
                relativeName: patient.relativeName,
                relativeMobile: patient.relativeMobile,
                isMatchRole: patient.isMatchRole,
                isMatchLocation: patient.isMatchLocation,
                isEmail: patient.isEmail
            }
            this.rawPatientProcessed.push(patientModel);
        });

        this.threading.totalRecord = this.rawPatientProcessed.length;
    }

    onThreadingPatientUpload(uploadId: number) {
        if (this.isUploadingPatientSheet) {
           
            //let checkEmail = this.rawPatientProcessed.filter(x => !(this.EmailFilter.test(x.email)));
            let checkMobileValid = this.rawPatientProcessed.filter(x => !(this.mobileFilter.test(x.mobile)));
            let checkAddress = this.rawPatientProcessed.filter(x => (this.whiteSpace.test(x.address)));
            //let checkDOB = this.rawPatientProcessed.filter(x => (this.whiteSpace.test(x.dateOfBirth)));
            let checkAge = this.rawPatientProcessed.filter(x => (this.whiteSpace.test(x.age)));
            let checkDateFormat = this.rawPatientProcessed.filter(x => (this.dateFilter.test(x.dateOfBirth)));
            this.rawPatientProcessed.forEach((item) => {
                this.matchPatientRole(item);
                this.httpService
                    .post<Array<Patient>>(ApiResources.getURI(ApiResources.patients.base, ApiResources.patients.fetch), {})
                    .pipe(takeUntil(this.page.unSubscribe))
                    .pipe(finalize(() => this.loading = false))
                    .subscribe(
                        (response: Array<Patient>) => {
                            this.patients = response;
                            var res1 = this.patients.filter(x => x.email.toLowerCase().toString().trim() == item.email.toLowerCase().toString().trim()); 
                            var res = this.patients.filter(x => x.patientId == 6001)
                            if (res1.length > 0) {
                                this.flag = true;                                
                            }
                            if (res.length > 0) {
                                //return;
                            }
                        },
                        () => {
                            this.patients = [];
                        }
                    );
            });
            if (checkDateFormat.length > 0) {
                this.notifyService.warning("Please enter valid Date of Birth format.");
                return;
            }
            //if (checkDOB.length > 0) {
            //    this.notifyService.warning("Please enter valid Date of Birth.");
            //    return;
            //}
            if (checkAge.length > 0) {
                this.notifyService.warning("Please enter valid Age.");
                return;
            }
            if (checkAddress.length > 0) {
                this.notifyService.warning("Please enter valid Address.");
                return;
            }
            //if (checkEmail.length > 0) {
            //    this.notifyService.warning("Please enter valid Email.");
            //    return;
            //}           
            if (checkMobileValid.length > 0) {
                this.notifyService.warning("Please enter 10 digit valid Mobile number.");
                return;
            }
            let findGender = this.rawPatientProcessed.filter(x => !UtilHelper.isEmpty(x.gender));
            if (findGender.length > 0) {
                this.notifyService.warning("Please fill gender field in <b>M</b> or <b>F</b>.");
                return;
            }
            this.isUploading = true;
            const record = this.rawPatientProcessed.splice(0, this.recordsPerThread);
            this.threading.inUploading = record.length;
            const request = {
                patientExcelHistoryId: 0,
                patients: record,
                createdBy: this.page.userAccount.accountId,
                roleId: this.page.userAccount.roleId,
                sheetName: this.sheetName
            };
            if (uploadId > 0) {
                this.threading.currentlyUploaded += this.threading.inUploading;
                if (this.rawPatients.length === 0 && record.length === 0) {
                    this.isUploading = false;
                    this.fetchUploadHistory();
                    this.onCloseModal();
                    if (this.returnedData.length > 0) {
                        this.onOpenModel(this.templateReturnedData, "xl")
                    }
                    this.notifyService.successToast("Excel sheet uploaded successfully");
                }
                else if (this.rawPatients.length === 0 && record.length > 0) {
                    request["patientExcelHistoryId"] = uploadId;
                    this.onUploadPatientSheet(request);
                }
                else {
                    request["patientExcelHistoryId"] = uploadId;
                    this.onUploadPatientSheet(request);
                }
            }
            else {
                //this.checkEmail(request);
               this.onUploadPatientSheet(request);
            }
        }
    }


    
    private onUploadPatientSheet(requestedData: any) {
        this.submitting = true;
        const request = requestedData;
        request["roleId"] = this.page.userAccount.roleId;
        request["uploadedByName"] = this.page.userAccount.fullName;

        let url = ApiResources.getURI(ApiResources.patientImport.base, ApiResources.patientImport.addPatientSheet);
        this.httpService
            .post(url, request)
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => this.submitting = false))
            .subscribe((response: ReturnTuples) => {
                console.log(response.item2);
                if (response.item2.length > 0) {
                    this.notifyService.warningToast("Data is already existed");
                    this.onCloseModal();
                }
                else {
                    this.returnedData = response.item1
                    this.onThreadingPatientUpload(response.item1 as number);
                    //return;
                }
            }, (error: HttpErrorResponse) => {
                const errorMessage = UtilHelper.handleError(error);
                if (errorMessage) {
                    this.notifyService.warning(errorMessage);
                } else {
                    this.notifyService.defaultError();
                }
                this.onCloseModal();
            }
            );
    }

    private fetchUploadedPatients() {
        const request = this.selectedHistory;
        this.httpService.post(ApiResources.getURI(ApiResources.patientImport.base, ApiResources.patientImport.fetchUplodedPatients), request)
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => {
                this.loadingPatients = false;
            }))
            .subscribe((response: Array<Patient>) => {
                this.patient = response;
            }, () => {
                this.patient = new Array<Patient>();
                this.notifyService.warning("Error occured while fetching products.");
            });
    }

    onOpenPatientView(content: TemplateRef<any>, item: UserImportHistory) {
        this.selectedHistory = item;
        this.onOpenModel(content, "xxl");
        this.fetchUploadedPatients();
    }

    onOpenModel(content: TemplateRef<any>, size: string) {
        this.modalRef = this.modalService.open(content, {
            backdrop: "static",
            keyboard: false,
            centered: false,
            size: size,
            windowClass: "custom-modal effect-scale"
        });
    }

    onCloseModal() {
        try {
            this.modalRef.close();
            this.modalRef = undefined;

        }
        catch (e) {
            //ignore;
        }
        this.sheetName = null;
        this.loadingFile = false
        this.selectedHistory = new UserImportHistory();
        this.rawPatients = new Array<PatientRawImport>();
        this.threading = new Threading();
        this.rawRecords = new Array<any>();
        this.isUploading = false;
        this.rawPatientProcessed = new Array<any>();
    }

    onCloseDownloadModel() {

        setTimeout(() => {
            this.onCloseModal();
        }, 500);
    }
    checkNull(values: string) {
        if (values !== undefined)
            if (values !== null) {
                if (values !== "") {
                    return true;
                } else {
                    return false;
                }
            } else
                return false;
        else {
            return false;

        }
    }

    ngOnInit() {
        this.appData.userAccount
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe((userAccount: IUserAccount) => {
                if (userAccount) {
                    this.page.userAccount = userAccount;
                    this.fetchUploadHistory();
                }
                else {
                    this.page.userAccount = undefined;
                }
            });
    }

    ngOnDestroy() {
        this.page.unsubscribeAll();
    }
}