import { Component, OnDestroy, OnInit, TemplateRef } from "@angular/core";
import { ActivatedRoute, Params } from "@angular/router";
import { takeUntil, finalize } from "rxjs/operators";
import { NgbModal, NgbModalRef } from "@ng-bootstrap/ng-bootstrap";

import { IResource, IUserAccount, Page, GenericResponse, GenericStatus } from "@shared/models";
import { ResourceService, AppData, HttpService, NotifyService, FinalBillService } from "@shared/services";
import { ApiResources, UtilHelper } from "../../../../../shared/helpers";

import { IReceiptModel } from "../../models/receipt.model";
import { IReceiptTypeModel, ReceiptType } from "../../models/receipt-type.model";
import { PayType } from "../../models/pay-type.model";
import { FormGroup, FormBuilder, Validators } from "@angular/forms";
import { FinalBillBasicModel } from "../../models/final-bill-basic.model";
import { IAdmissionModel } from "../../models/admission.model";
import { HttpErrorResponse } from "@angular/common/http";
import { Appointment, Setting } from "../../../../../shared/entities";
import { Location } from "@angular/common";
import { AdmissionFetchHelper } from "../../../progress-report/shared/helper";
import { WhiteSpaceValidator } from "../../../../../shared/validators";
import { PaymentModule } from "../../../../../shared/enums";

//import * as moment from "moment";

@Component({
    templateUrl: "./receipts.html",
    styleUrls: ['../../services.css']
})
export class ReceiptsPage implements OnInit, OnDestroy {

    receiptType = ReceiptType;
    payType = PayType;
    page: Page;

    loading: boolean;
    isChargesLoading: boolean;
    records: Array<IReceiptModel>;

    submitting: boolean;
    submitted: boolean;
    admissionId: string;
    isAdmission: boolean;
    disableActionBtns: boolean = false;

    receiptTypes: Array<IReceiptTypeModel>;
    receiptForm: FormGroup;
    appointment: Appointment;

    modalRef: NgbModalRef;
    finalBillBasics: FinalBillBasicModel;
    selected: IReceiptModel;
    selectedReceipt: IReceiptModel;
    now: Date;

    admission: IAdmissionModel;
    amountPaid: number;
    amountRefunded: number;

    payTypeData: Array<IResource>;
    payTypeId: number;
    loadingPayTypes: boolean;
    errorMessage: string;
    isSalucro: boolean;
    loadingSettings: boolean;
    constructor(
        private readonly httpService: HttpService,
        private readonly route: ActivatedRoute,
        private readonly resourceService: ResourceService,
        private readonly finalBillService: FinalBillService,
        private readonly appData: AppData,
        private readonly modalService: NgbModal,
        private readonly formBuilder: FormBuilder,
        private readonly notifyService: NotifyService,
        private readonly location: Location,
        private readonly admissionFetchHelper: AdmissionFetchHelper,
    ) {
        this.finalBillBasics = new FinalBillBasicModel();
        this.records = new Array<IReceiptModel>();
        this.isChargesLoading = false;
        this.loading = true;
        this.page = new Page();
        this.buildReceiptForm();
    }

    ngOnInit() {
        this.appData.userAccount
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe((userAccount: IUserAccount) => {
                if (userAccount) {
                    this.page.userAccount = userAccount;
                    this.getSettingsData();
                    this.route.parent.paramMap
                        .subscribe((params: Params) => {
                            this.admissionId = params["params"]["id"];
                            this.isAdmission = params["params"]["type"] === "a";

                            if (!this.isAdmission)
                                this.getAppointment(this.admissionId);
                            this.getFinalBillBasics(() => {
                                this.admissionFetch();
                                this.fetch();
                                this.fetchPayTypes(this.isSalucro);
                            });
                        });
                } else {
                    this.page.userAccount = undefined;
                }
            });
    }

    get form() {
        return this.receiptForm.controls;
    }



    private buildReceiptForm() {
        this.receiptForm = this.formBuilder.group({
            receiptTypeId: [null, [Validators.required]],
            cost: [null, [Validators.required]],
            payTypeId: [null, [Validators.required]],
            paymentDetails: [null, [Validators.maxLength(50)]],
        });

        this.receiptForm.get("payTypeId").valueChanges.subscribe((value: number) => {
            var paymentDetails = this.receiptForm.get("paymentDetails");
            if (value > 1 && value < 9) {
                paymentDetails.setValidators([Validators.required, WhiteSpaceValidator.isValid]);
                paymentDetails.enable();
                paymentDetails.setValue("");

            } else {
                paymentDetails.clearValidators();
                paymentDetails.setErrors(null);
                paymentDetails.setValidators(null);
                paymentDetails.setValue("");
            }
        });
    }



    getAppointment = (admissionId: string) => {
        const request = { appointmentId: parseInt(admissionId) };
        this.httpService.post(ApiResources.getURI(ApiResources.appointments.base, ApiResources.appointments.find), request)
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe((response: Appointment) => {
                this.appointment = response;
                this.disableActionBtns = this.appointment && this.appointment.status === "C";
            });
    }

    admissionFetch = () => {
        this.admissionFetchHelper.admissionFetch(+this.admissionId, this.isAdmission, (data: IAdmissionModel) => {
            this.loading = false
            this.admission = data;
        });
    }

    onOpenModel(content: TemplateRef<any>, isCash: boolean = true, selected: IReceiptModel = null) {

        this.fetchPayTypes(this.isSalucro);
        if (!selected && this.finalBillBasics.finalAmount !== 0) {
            this.notifyService.info("Receipts can not be added once the final bill is generated, please cancel the Final Bill and try again.");
            return;
        }

        this.selected = selected;
        this.receiptForm.reset();
        //if (isCash === undefined) {
        //    this.receiptForm.patchValue({
        //        receiptTypeId: null,
        //        cost: selected ? selected.cost : null
        //    });

        //}
        //if (isCash != undefined) {
        this.receiptForm.patchValue({
            receiptTypeId: isCash ? ReceiptType.Cash : ReceiptType.Refund,
            cost: selected ? selected.cost : null
        });
        //}
        this.modalRef = this.modalService.open(content, {
            backdrop: "static",
            keyboard: false,
            centered: true,
            size: "lg",
            windowClass: "custom-modal slots-modal effect-scale"
        });

        return;
    }

    onOpenViewModel(content: TemplateRef<any>, item: IReceiptModel) {
        this.selectedReceipt = item;
        this.now = new Date();

        this.modalRef = this.modalService.open(content, {
            backdrop: "static",
            keyboard: false,
            centered: true,
            size: "lg",
            windowClass: "custom-modal slots-modal effect-scale"
        });

        return;
    }

    onCloseModal() {
        try {
            this.modalRef.close();
            this.modalRef = undefined;
        } catch (e) {
            // ignored;
        }

        this.submitting = undefined;
        this.submitted = undefined;
    }

    fetch = () => {
        this.httpService
            .post<GenericResponse>(ApiResources.getURI(ApiResources.receipt.base, ApiResources.receipt.fetch),
                { id: this.admissionId, isAdmission: this.isAdmission })
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => this.loading = false))
            .subscribe(
                (response: GenericResponse) => {
                    const records = response.data.records as Array<IReceiptModel>;
                    records.forEach(item => {
                        item.receiptNo = String(item.receiptId).padStart(6, '0');
                    });
                    this.amountPaid = records.filter(x => x.receiptTypeId === ReceiptType.Cash && x.active)
                        .map(x => x.cost).reduce((a, b) => a + b, 0);
                    this.amountRefunded = records.filter(x => x.receiptTypeId === ReceiptType.Refund && x.active)
                        .map(x => x.cost).reduce((a, b) => a + b, 0);
                    this.records = records;
                    this.unshiftPending();
                },
                () => {
                    this.records = new Array<IReceiptModel>();
                }
            );

    }

    getFinalBillBasics = (callback = () => { }) => {
        this.httpService
            .post<GenericResponse>(ApiResources.getURI(ApiResources.finalBill.base, ApiResources.finalBill.getBasics), { id: this.admissionId, isAdmission: this.isAdmission })
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe(
                (response: GenericResponse) => {
                    this.finalBillBasics = response.data as FinalBillBasicModel;
                    callback();
                },
                () => {
                    this.finalBillBasics = new FinalBillBasicModel();
                }
            );
    }

    unshiftPending = () => {
        if (this.finalBillBasics.isFinalBillGenerated && this.finalBillBasics.pendingAmount !== 0) {
            let record = {} as IReceiptModel;
            if (this.finalBillBasics.pendingAmount < 0) {
                // Due
                record = {
                    isSpecial: true,
                    payTypeId: null,
                    receiptTypeId: ReceiptType.Cash,
                    paymentDetails: null,
                    cost: (this.finalBillBasics.pendingAmount * -1),
                } as IReceiptModel;

            } else {
                // Refund
                record = {
                    isSpecial: true,
                    payTypeId: null,
                    receiptTypeId: ReceiptType.Refund,
                    paymentDetails: null,
                    cost: this.finalBillBasics.pendingAmount,
                } as IReceiptModel;
            }
            this.records.unshift(record);
        }
    }

    onCancel = (item: IReceiptModel) => {
        if (item.cancelling) return;

        item.cancelling = true;
        this.notifyService.confirm("Do you really want to cancel this receipt? This process can not be undone.",
            () => {
                this.httpService
                    .post(ApiResources.getURI(ApiResources.receipt.base, ApiResources.receipt.cancel),
                        { id: item.receiptId, loginAccountId: this.page.userAccount.accountId, loginRoleId: this.page.userAccount.roleId })
                    .pipe(finalize(() => { item.cancelling = false; }))
                    .pipe(takeUntil(this.page.unSubscribe))
                    .subscribe((response: GenericResponse) => {
                        if (response.status === GenericStatus[GenericStatus.Success]) {
                            this.fetch();
                            this.getFinalBillBasics(() => {
                                this.finalBillService.set(true);
                                this.fetch();
                            });
                        } else {
                            this.notifyService.defaultError();
                        }
                    },
                        (error: HttpErrorResponse) => {
                            item.cancelling = false;
                            const errorMessage = UtilHelper.handleError(error);
                            if (errorMessage) {
                                this.notifyService.warning(errorMessage);
                            } else {
                                this.notifyService.defaultError();
                            }
                        });
            },
            () => {
                item.cancelling = false;
            });
    }

    onBack = () => {
        this.location.back();
    }

    onAddReceipt = () => {
        this.submitted = true;
        if (!this.receiptForm.valid) {
            this.notifyService.infoToast("Please fill all the mandatory fields.");
            return;
        }

        const self = this;
        function callback(response: Document): void {
            if (response) {
                $("#dvContent").html(response.body.innerHTML);
                $(".payment-content form #paynow").click();
                self.submitting = false;
            } else {
                self.submitting = false;
                self.errorMessage = UtilHelper.defaultErrorMessage();
            }
        }

        this.submitting = true;
        const data = {
            ...this.receiptForm.value,
            id: this.admissionId,
            isAdmission: this.isAdmission,
            createdBy: this.page.userAccount.accountId,
            roleId: this.page.userAccount.roleId,
            roleName: this.page.userAccount.roleName,
            createdByName: this.page.userAccount.fullName
        };

        if (this.selected && this.selected.receiptTypeId === ReceiptType.Refund) {
            data["isRefunded"] = true;
        }

        data["totalAmount"] = data["cost"];
        data["logFrom"] = this.page.userAccount.roleId;
        data["locationId"] = this.page.userAccount.locationId;
        data["patientId"] = this.admission.patientId;

        const paymentModel = {
            type: PaymentModule.Admission,
            json: JSON.stringify(data),
            mode: data["isRefunded"] ? "Refund" : "Payment"
        }
        const model = (this.isSalucro && (data.totalAmount > 0)) ? paymentModel : data;
        const formData = UtilHelper.prepareFormData(UtilHelper.clone(model));
        let url = (this.isSalucro && (data.totalAmount > 0)) ? ApiResources.getURI(ApiResources.appointments.base, ApiResources.appointments.initiatePayment) : ApiResources.getURI(ApiResources.receipt.base, ApiResources.receipt.insert);
        this.httpService
            .postFile<GenericResponse>(url, formData)
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => this.submitting = false))
            .subscribe(
                (response: GenericResponse) => {
                    if (response.status === GenericStatus[GenericStatus.Success]) {
                        const data = response.data;
                        if (typeof (data) === "number") {
                            this.onCloseModal();
                            this.getFinalBillBasics(() => {
                                this.finalBillService.set(true);
                                this.fetch();
                            });
                        }
                        else {
                            UtilHelper.getHtml(data, callback);
                        }
                    } else {
                        if (response.message) {
                            this.notifyService.info(response.message);
                        } else {
                            this.notifyService.defaultError();
                        }
                    }
                },
                () => {
                    this.receiptTypes = new Array<IReceiptTypeModel>();
                }
            );
    }

    ngOnDestroy() {
        this.page.unSubscribe.next();
        this.page.unSubscribe.complete();
    }

    private fetchPayTypes(isSalucro?: boolean) {
        let salucro = isSalucro === true ? true : false;
        this.loadingPayTypes = true;
        this.resourceService.payType(salucro)
            .pipe(finalize(() => { this.loadingPayTypes = false }))
            .pipe(takeUntil(this.page.unSubscribe))
            .subscribe((response: Array<IResource>) => {
                this.payTypeData = response;
                let findPayType = null;
                if (salucro) {
                    this.receiptForm.patchValue({
                        payTypeId: 13
                    });
                }
                else {
                    this.receiptForm.patchValue({
                        payTypeId: findPayType ? findPayType.value : null
                    });
                }
            });
    }

    private getSettingsData() {
        this.loadingSettings = true;
        this.httpService.get<Array<Setting>>(ApiResources.getURI(ApiResources.setting.base, ApiResources.setting.fetch), { name: "Salucro" })
            .pipe(takeUntil(this.page.unSubscribe))
            .pipe(finalize(() => this.loadingSettings = false))
            .subscribe((response: Array<Setting>) => {
                if (response.length > 0) {
                    this.isSalucro = response[0].active;
                }
            });
    }
}