async function fetchInstallments(getInstallmentsUrl) {
    let moveInstallments;
    await fetch(getInstallmentsUrl, {
        method: "GET",
        headers: { 'Content-Type': 'application/json' }
    }).then((response) => response.json()
    ).then(async (data) => {
        moveInstallments = data;
    });

    return moveInstallments;
}

async function openInstallmentsModal(acKey, paymentMethods, installmentsLocalization, getInstallmentsUrl, createInstallmentsUrl, updateInstallmentsUrl, ClearInstallmentsUrl, printOutUrl, searchBankUrl, helpUlr, beforeCreate) {
    let moveInstallments = await fetchInstallments(getInstallmentsUrl);

    $().customModal({
        onCreated: function () {

        },
        onOpen: function () {

        },
        destroyOnClose: true,
        title: installmentsLocalization.installmentsTitle,
        openOnCreate: true,
        closeOtherModals: false,
        help: helpUlr,
        id: "installmentsModal",
        width: "80%",
        maxWidth: "1200px",
        height: "80%",
        maxHeight: "600px",
        type: "modal",
        draggable: true,
        class: "custom-modal-mobile-full-size",
        modalBodyClass: "custom-modal-body-ignore-overflow-y p-t-20",
        content: await generateInstallmentsModal(acKey, paymentMethods, moveInstallments, installmentsLocalization, createInstallmentsUrl, updateInstallmentsUrl, printOutUrl, searchBankUrl, beforeCreate),
        buttons: [
            {
                icon: 'fa fa-times',
                text: installmentsLocalization.cancel,
                closeOnAction: true,
                type: 'ghost'
            },
            {
                icon: 'fa fa-eraser',
                text: installmentsLocalization.clear,
                action: async function () {
                    await clearInstallments(acKey, paymentMethods, installmentsLocalization, ClearInstallmentsUrl, searchBankUrl, $("#installmentsModal"));
                },
                closeOnAction: false,
                type: 'ghost'
            },
            {
                icon: 'fa fa-print',
                text: installmentsLocalization.installmentContractPrintoutButtonText,
                action: async function () {
                    if ($("#installmentsModal table > tbody > tr").length > 0) {
                        await createPrintout(acKey, printOutUrl);
                    }
                    else {
                        $().customModal({
                            destroyOnClose: true,
                            type: "error",
                            closeOtherModals: false,
                            text: installmentsLocalization.canNotDisplayInstallmentsPrintout,
                            buttons: [{
                                text: $("#ConfirmLoc").val(),
                                icon: 'fa fa-check',
                                closeOnAction: true,
                                type: 'primary'
                            }]
                        });
                    }
                },
                closeOnAction: false,
                type: 'ghost'
            },
            {
                icon: 'fa fa-save',
                text: installmentsLocalization.save,
                action: async function () { await saveInstallments($("#installmentsModal"), updateInstallmentsUrl, true); },
                closeOnAction: false,
                type: 'primary'
            }
        ]
    });
}

async function generateInstallmentsModal(acKey, paymentMethods, moveInstallments, installmentsLocalization, createInstallmentsUrl, updateInstallmentsUrl, printOutUrl, searchBankUrl, beforeCreate) {
    let $installmentsModal = $("<form class='full-height'></form>");
    let $installmentsModalContent = $("<div class='full-height'></div>");

    //First row
    let $filtersRow = $("<div class='row' style='margin-left:-24px; margin-right:-24px;margin-top:-20px'></div>");
    let $filters = generateInstallemtnsFilters(installmentsLocalization, createInstallmentsUrl, updateInstallmentsUrl, printOutUrl, searchBankUrl,
        paymentMethods, moveInstallments, acKey, $installmentsModal, beforeCreate);
    $filtersRow.append($filters);

    //Buttons
    let $displayButtonRow = $("<div class='row m-b-sm m-t-sm'></div>");
    let $createButtonColumn = $("<div class='col-xs-12'></div>");
    let $createButton = $("<button type='button' class='btn btn-primary pull-right'><i class='fa fa-check'></i> " + installmentsLocalization.installmentsCreateButtonText + "</button>");
    $createButton.on("click", async function () {
        $(this).find("i").addClass("fa-spinner fa-spin");
        let formData = $(this).closest("form").serializeArray().reduce(function (json, { name, value }) {
            json[name] = value;
            return json;
        }, {});
        await runCreateInstallments(acKey, paymentMethods, formData, installmentsLocalization, createInstallmentsUrl, updateInstallmentsUrl, searchBankUrl, $installmentsModal, beforeCreate);
        $(this).find("i").removeClass("fa-spinner fa-spin");
    });
    $createButtonColumn.append($createButton);
    $displayButtonRow.append($createButtonColumn);

    //Table row
    let $tableRow = $("<div class='row' style='height: calc(100% - 130px);'></div>");
    let $installmentsTable = await generateInstallmentsTable(moveInstallments, installmentsLocalization, paymentMethods, $installmentsModal, searchBankUrl);
    $tableRow.append($installmentsTable);

    //Append all
    $installmentsModalContent.append($filtersRow);
    $installmentsModalContent.append($displayButtonRow);
    $installmentsModalContent.append($tableRow);
    $installmentsModal.append($installmentsModalContent);

    $installmentsModal.find(".datepicker").datepicker({
        format: 'dd.mm.yyyy',
        language: $('#siteLocale').val(),
        startDate: "moment().format('DD.MM.YYYY')"
    });

    $installmentsModal.find(".custom-select").customSelect();

    $installmentsModal.find("input[name='installmentRate']").val(moveInstallments != null ? moveInstallments.length : 0);
    formatNumberInput($installmentsModal.find("input[name='toPayValue']"));

    updateSums(paymentMethods, $installmentsModal);

    return $installmentsModal;
}

function generateInstallemtnsFilters(installmentsLocalization, createInstallmentsUrl, updateInstallmentsUrl, printOutUrl, searchBankUrl,
    paymentMethods, moveInstallments, acKey, $installmentsModal, beforeCreate) {
    $filters = $("<div class='document-head custom-modal-header-divider '></div>");

    //Date of isntallments creation
    $filters.append(generateFormGroup(installmentsLocalization.dateOfInstallmentCreation, "<input type='text' class='form-control datepicker' name='installmentDate' value='" + moment(new Date()).format("DD.MM.YYYY") + "' class='datepicker' />", "col-xs-3"));

    //Frequency
    let $installmentsFrequency = $("<select class='form-control custom-select' name='installmentsFrequency'></select>");
    $installmentsFrequency.append("<option value='0'> " + installmentsLocalization.installmentIntervalDay + "</option>");
    $installmentsFrequency.append("<option value='1'> " + installmentsLocalization.installmentIntervalWeek + "</option>");
    $installmentsFrequency.append("<option value='2' selected> " + installmentsLocalization.installmentIntervalMonth + "</option>");

    $filters.append(generateFormGroup(installmentsLocalization.installmentFrequency, $installmentsFrequency[0].outerHTML, "col-xs-3"));

    //Number of installments
    $filters.append(generateFormGroup(installmentsLocalization.numberOfInstallments, "<input type='text' name='installmentRate' class='form-control' value='1' />", "col-xs-2"));

    //To pay value
    $filters.append(generateFormGroup(installmentsLocalization.installmentsToPayValueText, "<input type='text' name='toPayValue' class='form-control' value='" + paymentMethods.reduce((acc, b) => { return +(acc + b.amount).toFixed(12) }, 0) + "' disabled />", "col-xs-2 document-head-disabled-input"));

    //Open value
    $filters.append(generateFormGroup(installmentsLocalization.installmentsOpenValueText, "<input type='text' name='openValue' class='form-control' disabled />", "col-xs-2 document-head-disabled-input"));

    return $filters;
}

function generateFormGroup(labelText, componentHtml, outerClass) {
    return $filters.append("<div class='" + outerClass + "'><div class='form-group'><label title='" + labelText + "' class='control-label'>" + labelText + "</label><div>" + componentHtml + "</div></div></div>");
}

function generateInstallmentsTable(moveInstallments, installmentsLocalization, paymentMethods, $modal, searchBankUrl) {
    let $tableWrapper = $("<div class='col-xs-12 document-table' style='height:100%!important'></div>");
    let $installmentsTable = $("<table class='table table-bordered table-sm full-height' style='margin-bottom:0;'></table>");
    let $installmentsTableHead = $("<tr></tr>");

    for (let i = 0; i < installmentsLocalization.installmentsTableTitles.length; i++) {
        $installmentsTableHead.append("<th>" + installmentsLocalization.installmentsTableTitles[i] + "</th>");
    }
    $installmentsTable.append("<thead>" + $installmentsTableHead[0].outerHTML + "</thead>");

    $installmentsBody = $("<tbody></tbody>");
    for (let i = 0; i < moveInstallments?.length; i++) {
        let installment = moveInstallments[i];
        let paymentMethod = paymentMethods.find(x => x.id === installment.PayMethod);
        let $installmentRow = $("<tr " + (moveInstallments?.length > i + 1 ? "style='height:1px'" : "") + "data-id='" + installment.AnQid + "' data-paymentMethod='" + installment.PayMethod + "' data-installmentNumber='" + installment.InstallmentNumber + "'></tr>");
        $installmentRow.append("<td width='60px' class='no-padding'><input type='text' class='form-control' disabled value='" + installment.InstallmentNumber + "'/></td>");
        $installmentRow.append("<td width='100px' class='no-padding'><input type='text' class='datepicker form-control' disabled value='" + moment(installment.Date).format("DD.MM.YYYY") + "'/></td>");
        $installmentRow.append("<td class='no-padding'><input type='text' class='numberInput form-control installmentAmount' value='" + installment.Amount + "'/></td>");
        $installmentRow.append("<td class='no-padding'><input type='text' class='form-control' disabled value='" + (paymentMethod ? paymentMethod.name : installment.PayMethod) + "'/></td>");
        $installmentRow.append("<td width='170px' class='no-padding'><input type='text' maxlength='18' class='form-control installmentNumber' value='" + (installment.Number != null ? installment.Number : "") + "'/></td>");
        $installmentRow.append("<td width='180px' class='no-padding'><input type='text' maxlength='21' class='form-control installmentInvoice' value='" + (installment.Invoice != null ? installment.Invoice : "") + "'/></td>");
        $installmentRow.append("<td class='no-padding' style='position:relative'><input type='text' class='form-control installmentBank typeahead-normal custom-select' value='" + (installment.Bank != null ? installment.Bank : "") + "'/></td>");

        formatNumberInput($installmentRow.find(".numberInput"));

        $installmentsBody.append($installmentRow);
    }

    $installmentsTable.append($installmentsBody);

    $installmentsTable.find(".installmentAmount").on("blur", function () {
        updateSums(paymentMethods, $modal);
    });

    $installmentsTable.find('.installmentBank').each(function () {
        initializeBankTypeahead(searchBankUrl, $(this), $(this));
    });

    $tableWrapper.append($installmentsTable);
    return $tableWrapper;
}

async function runCreateInstallments(ackey, paymentMethods, data, installmentsLocalization, createInstallmentsUrl, updateInstallmentsUrl, searchBankUrl, $installmentsModal, beforeCreate) {
    if ($installmentsModal.find("table tr").length > 1) {
        $().customModal({
            destroyOnClose: true,
            type: "question",
            closeOtherModals: false,
            text: installmentsLocalization.deleteExistingInstallments,
            buttons: [{
                text: $("#YesLoc").val(),
                icon: 'fa fa-check',
                closeOnAction: true,
                type: 'primary',
                action: async function () {
                    data.clearInstallments = true;
                    await createInstallments(ackey, paymentMethods, data, installmentsLocalization, createInstallmentsUrl, searchBankUrl, $installmentsModal, beforeCreate)
                }
            }, {
                text: $("#NoLoc").val(),
                icon: 'fa fa-times',
                closeOnAction: true,
                type: 'primary',
                action: async function () {
                    await saveInstallments($installmentsModal, updateInstallmentsUrl, false);
                    data.clearInstallments = false;
                    await createInstallments(ackey, paymentMethods, data, installmentsLocalization, createInstallmentsUrl, searchBankUrl, $installmentsModal, beforeCreate)
                }
            }
            ]
        });
    }
    else {
        await createInstallments(ackey, paymentMethods, data, installmentsLocalization, createInstallmentsUrl, searchBankUrl, $installmentsModal, beforeCreate)
    }
}

async function createInstallments(ackey, paymentMethods, data, installmentsLocalization, createInstallmentsUrl, searchBankUrl, $installmentsModal, beforeCreate) {
    if (beforeCreate !== undefined) await beforeCreate();

    data.acKey = ackey;
    let moveInstallments = [];

    for (let i = 0; i < paymentMethods.length; i++) {
        data.payMethod = paymentMethods[i].id;

        await fetch(createInstallmentsUrl, {
            method: "POST",
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(data)
        }).then((response) => response.json()
        ).then(async (data) => {
            if (data.Succcess === true) {
                moveInstallments = data.Installments;
            }
            else {
                $().customModal({
                    destroyOnClose: true,
                    title: $("#ErrorLoc").val(),
                    type: "error",
                    closeOtherModals: false,
                    text: GeneralErrorLoc,
                    buttons: [{
                        text: $("#ConfirmLoc").val(),
                        icon: 'fa fa-check',
                        closeOnAction: true,
                        type: 'primary'
                    }]
                });
            }
        });
    }

    let $installmentsTable = await generateInstallmentsTable(moveInstallments, installmentsLocalization, paymentMethods, $installmentsModal, searchBankUrl);
    $installmentsModal.find(".document-table").replaceWith($installmentsTable);
    updateSums(paymentMethods, $installmentsModal);
}

var printWindow;
async function createPrintout(acKey, printOutUrl) {
    printWindow = createPrintWindow(printWindow);
    printPAAS("20B", false, false);
}

async function saveInstallments($installmentsModal, updateInstallmentsUrl, closeIfValid) {
    let rows = $installmentsModal.find("table tr").toArray();
    let installments = [];
    let valid = true;

    for (let i = 0; i < rows.length; i++) {
        $row = $(rows[i]);
        if ($row.attr("data-id") !== undefined) {
            let installment = {
                anQId: $row.attr("data-id"),
                installmentNumber: $row.attr("data-installmentNumber"),
                payMethod: $row.attr("data-paymentMethod"),
                date: $row.find(".datepicker").val(),
                amount: toNumber($row.find(".installmentAmount").val()),
                number: $row.find(".installmentNumber").val() === "" ? undefined : $row.find(".installmentNumber").val(),
                invoice: $row.find(".installmentInvoice").val() === "" ? undefined : $row.find(".installmentInvoice").val(),
                bank: $row.find(".installmentBank").val() === "" ? undefined : $row.find(".installmentBank").val(),
            };

            installments.push(installment);

            let rowValid = validateInstallment(installment, $row);
            if (!rowValid) valid = false;
        }
    }

    if (valid) {
        for (let i = 0; i < installments.length; i++) {
            await updateInstallment(installments[i], updateInstallmentsUrl);
        }

        if (closeIfValid) {
            $("#installmentsModal").customModal("close");
        }
    }
}

function validateInstallment(installment, $row) {
    let valid = true;

    if (installment.date === undefined) {
        $row.find(".datepicker").addClass("datatable-error-input");
        valid = false;
    }
    else {
        $row.find(".datepicker").removeClass("datatable-error-input");
    }

    if (installment.number?.length > 18) {
        $row.find(".installmentNumber").addClass("datatable-error-input");
        valid = false;
    }
    else {
        $row.find(".installmentNumber").removeClass("datatable-error-input");

    }

    if (installment.invoice?.length > 21) {
        $row.find(".installmentInvoice").addClass("datatable-error-input");
        valid = false;
    }
    else {
        $row.find(".installmentInvoice").removeClass("datatable-error-input");
    }

    return valid;
}

async function updateInstallment(installment, updateInstallmentsUrl) {
    await fetch(updateInstallmentsUrl, {
        method: "POST",
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(installment)
    }).then((response) => response.json()
    ).then(async (data) => {
        if (data !== true) {
            $().customModal({
                destroyOnClose: true,
                title: $("#ErrorLoc").val() + " - " + installment.anQId,
                type: "error",
                closeOtherModals: false,
                text: GeneralErrorLoc,
                buttons: [{
                    text: $("#ConfirmLoc").val(),
                    icon: 'fa fa-check',
                    closeOnAction: true,
                    type: 'primary'
                }]
            });
        }
    });
}

async function clearInstallments(acKey, paymentMethods, installmentsLocalization, clearInstallmentsUrl, searchBankUrl, $installmentsModal) {
    await fetch(clearInstallmentsUrl, {
        method: "POST",
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ acKey })
    }).then((response) => response.json()
    ).then(async (data) => {
        if (data === true) {
            let $installmentsTable = await generateInstallmentsTable(null, installmentsLocalization, null, $installmentsModal, searchBankUrl);
            $installmentsModal.find(".document-table").replaceWith($installmentsTable);
            updateSums(paymentMethods, $installmentsModal);
        }
        else {
            $().customModal({
                destroyOnClose: true,
                title: $("#ErrorLoc").val(),
                type: "error",
                closeOtherModals: false,
                text: GeneralErrorLoc,
                buttons: [{
                    text: $("#ConfirmLoc").val(),
                    icon: 'fa fa-check',
                    closeOnAction: true,
                    type: 'primary'
                }]
            });
        }
    });
}

async function checkInstallmentsPayment(getInstallmentsUrl, paymentMethods, errorMessageTemplate, currency) {
    let response = { success: true, errorMessage: undefined };
    let moveInstallments = await fetchInstallments(getInstallmentsUrl);
    for (let i = 0; i < paymentMethods.length; i++) {
        let paymentMethod = paymentMethods[i];

        let paymentMoveInstallments = moveInstallments.filter(x => x.PayMethod === paymentMethod.id);
        let installmentsSum = paymentMoveInstallments.reduce((sum, x) => +(sum + x.Amount).toFixed(12), 0);

        if (installmentsSum !== paymentMethod.amount) {
            response.success = false;
            response.errorMessage = errorMessageTemplate ?
                errorMessageTemplate
                    .replace("{0}", paymentMethod.name)
                    .replace("{1}", paymentMethod.amount + (currency ? " " + currency : ""))
                    .replace("{2}", installmentsSum + (currency ? " " + currency : ""))
                : "Error " + paymentMethod.name;
            return response;
        }
    }

    return response;
}

function updateSums(paymentMethods, $modal) {
    let sumDifference = 0;
    for (let i = 0; i < paymentMethods.length; i++) {
        let paymentMethod = paymentMethods[i]
        let paymentMethodSum = paymentMethod.amount;
        let installmentsSum = $modal.find("table tr[data-paymentMethod='" + paymentMethod.id + "']").toArray().reduce((sum, row) => { return +(sum + toNumber($(row).find(".installmentAmount").val())).toFixed(12); }, 0);

        sumDifference += (paymentMethodSum - installmentsSum);
    }

    let $openValueInput = $modal.find("input[name='openValue']");
    $openValueInput.val(sumDifference);
    formatNumberInput($openValueInput);
}