package cz.moneta.test.regression.transactional.payments.cashless.payment_engine.foreign.ingoing;

import cz.moneta.test.dsl.Harness;
import cz.moneta.test.dsl.payment_engine.enums.ParameterChannels;
import cz.moneta.test.dsl.payment_engine.enums.TransactionReasonPAE;
import cz.moneta.test.dsl.payment_engine.home.PaymentEngineHomePage;
import cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_monitoring.PaymentEngineMonitoringInstanceFileRecords;
import cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_monitoring.PaymentEngineMonitoringInstanceLifeCycle;
import cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_monitoring.PaymentEngineRunInstance;
import cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_search.PaymentEngineSearchTransactionRecordDetail;
import cz.moneta.test.dsl.payment_engine.tasks.PaymentEngineTasks;
import cz.moneta.test.dsl.payment_engine.utils.PaymentEngineUtils;
import cz.moneta.test.dsl.util.DateUtils;
import cz.moneta.test.dsl.util.credentials.Keys;
import cz.moneta.test.dsl.util.data.payment.PaymentData;
import cz.moneta.test.harness.annotations.*;
import cz.moneta.test.harness.support.auth.Credentials;
import cz.moneta.test.harness.support.auth.Key;
import cz.moneta.test.dsl.payment_engine.model.FileForInputPreparation;
import org.apache.commons.lang.StringUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Order;

import java.io.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;

import static cz.moneta.test.dsl.payment_engine.enums.CurrencyPAE.CURRENCY_CZK_LONG;
import static cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_administration.PaymentEngineParametersChannelParameters.PARAMETER_VALUE_ID_KEY;
import static cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_monitoring.PaymentEngineMonitoringInstanceFileRecords.TRANSACTION_ID_KEY;
import static cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_monitoring.PaymentEngineMonitoringInstanceLifeCycle.FEE_TRANSACTION_ID_KEY;
import static cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_monitoring.PaymentEngineRunInstance.LAST_SEQUENCE_NUMBER_KEY;
import static cz.moneta.test.dsl.payment_engine.enums.TransactionReasonPAE.*;
import static cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_search.PaymentEngineSearchPage.EQUIVALENT_AMOUNT_KEY;
import static cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_search.PaymentEngineSearchTransactionDetail.REF_TRANSACTION_KEY;
import static cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_search.PaymentEngineSearchTransactionDetailLifeCycle.*;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

@NonConcurrentTestScenario
@TestScenarioWithOrder(name = "Ingoing foreign payment controller")
public class IngoingMt103Test extends FileForInputPreparation {

    private String MT_FILE = "";
    private String MT103_FOR_HD21;
    private String MT103_OUR;
    private String HD21_WITH_MT191;
    private String HD21_FILE;
    private String MT103_WITH_MT191;
    private String TOKEN_CBL;
    private String transactionId;
    private String returnedAmount;
    private final String transactionTypeFee = "xCT Klientsky poplatek";
    private final String transactionTypeHD21 = "HD:21 proplaceni odchozi";
    private final String filesTabName = "Soubory";
    private PaymentData data;
    private PaymentEngineTasks tasks;

    @BeforeAll
    public void testSetUp(Harness harness) {
        data = PaymentData.builder()
                .todayDate(DateUtils.getFormattedTodayDate("yyyyMMdd"))
                .distributionDate(LocalDate.now().format(DateTimeFormatter.ofPattern("dd.MM.yyyy")))
                .transactionType("xCT MT103 Return odchozi")
                .build();
        MT103_FOR_HD21 = harness.getConfig("payments_cashless.foreignPayment.MT103_FOR_HD21");
        MT103_OUR = harness.getConfig("payments_cashless.foreignPayment.MT103_OUR");
        HD21_WITH_MT191 = harness.getConfig("payments_cashless.foreignPayment.HD21_WITH_MT191");
        HD21_FILE = harness.getConfig("payments_cashless.foreignPayment.HD21_FILE");
        MT103_WITH_MT191 = harness.getConfig("payments_cashless.foreignPayment.MT103_WITH_MT191");
        TOKEN_CBL = harness.tasks().wso2().authorization().getToken("DigitalchannelsSB_CBL");
    }

    @BeforeEach
    public void setUpUniqueData(Harness harness) {
        data.setRandom("HARNESS" + ThreadLocalRandom.current().nextInt(100000000, 999999999));
        data.setMessageId("HARNESS" + ThreadLocalRandom.current().nextInt(100000000, 999999999));
        data.setAmount(ThreadLocalRandom.current().nextInt(10, 99) + "," + ThreadLocalRandom.current().nextInt(10, 99));
        data.setAmount1(data.getAmount().replace(",", ""));
        data.setAmountIcbs(data.getAmount().replace(",", "."));
        data.setLastNonpriorityField(ThreadLocalRandom.current().nextInt(501, 699));
        tasks = harness.tasks().paymentEngineTasks();
    }

    private void checkForeignTransactionStatusBooked(Harness harness, String account, String amountICBS, String transactionId) {
        String request = harness.tasks()
                .wso2()
                .payments()
                .createRequestForTransactionCheck(account, data.getTodayDate(), amountICBS);
        harness.tasks()
                .wso2()
                .payments()
                .checkForeignTransactionStatusBooked(TOKEN_CBL, request, transactionId);
    }

    @Disabled
    @Order(1)
    @JiraTestCase(id = "PAY-T1849")
    @TestCase(environments = {Environment.TST1, Environment.PPE})
    public void simulateIngoingMt103(Harness harness, @Key(Keys.paymentEngine.firstUser) Credentials user1) throws IOException {
        data.setIban(harness.getConfig("payments_cashless.foreignPayment.MT103"));
        assumptionForTestExecution_IngoingPayment(harness, user1);
        harness.log("Random amount is: " + data.getAmount());
        MT_FILE = "regression/transactional/cashless/MT103.out";
        PaymentEngineRunInstance getId = getLastMTId(harness, logInToPae(harness, user1), tasks);

        lastField = Integer.valueOf(harness.get(LAST_SEQUENCE_NUMBER_KEY));
        String newFileName = String.format("0106%04d.out", lastField + 1);
        File file = prepareFileForInput(harness, MT_FILE, newFileName, data);

        try {
            uploadFileAndCheckMtTransactionStatus(harness, getId,
                    ARCHIV, file.getAbsolutePath(), newFileName);
            harness.withPaymentEngine().closePaymentEngine();
        } catch (Exception e) {
            throw e;
        } finally {
            file.delete();
        }
        transactionId = harness.get(TRANSACTION_ID_KEY);

        harness.store("reports.tmfj.execution.comment", "Transaction amount: " + data.getAmount()
                + "\nMT103 file name: " + newFileName
                + "\nPrevious file ID: " + lastField
                + "\nTransaction ID: " + transactionId);
    }

    @Order(2)
    @JiraTestCase(id = "PAY-T3630")
    @TestCase(name = "Simulate Ingoing SCT Recall", environments = {Environment.TST1, Environment.PPE})
    public void simulateIngoingSCTRecall(Harness harness, @Key(Keys.paymentEngine.firstUser) Credentials user1,
                                         @Key(Keys.paymentEngine.secondUser) Credentials user2) {
        data.setDebtorAcc(harness.getConfig("payments_cashless.foreignPayment.MT103acc"));

        logInToPae(harness, user1)
                .then(tasks.createRequestForSCTIngoingPaymentReturn(transactionId));
        harness.withPaymentEngine().closePaymentEngine();

        logInToPae(harness, user2)
                .then(tasks.verifyIngoing(transactionId))
                .then(tasks.searchTransactionAndWaitForStatus(RETURN, transactionId))
                .then(tasks.checkLifeCycleAndWaitForStatus(data, DISTRIBUTION))
                .storeTransactionIdByType(data.getTransactionType())
                .closeTab()
                .then(tasks.sendAndRunXCTDistribution())
                .then(tasks.searchTransactionAndWaitForStatus(ARCHIV, harness.get(TRANSACTION_BY_TYPE_ID_KEY)))
                .storeEquivalentAmountUsd();
        harness.withPaymentEngine().closePaymentEngine();
        returnedAmount = harness.get(EQUIVALENT_AMOUNT_KEY).toString().replace(".", "").replace(",", ".");

        checkForeignTransactionStatusBooked(harness, data.getDebtorAcc(), returnedAmount, harness.get(TRANSACTION_BY_TYPE_ID_KEY));

        PaymentEngineUtils.logResultOfReturn(harness, transactionId,
                harness.get(TRANSACTION_BY_TYPE_ID_KEY), data.getDebtorAcc(), data.getAmountIcbs(), returnedAmount);
    }

    @Disabled
    @Order(3)
    @JiraTestCase(id = "PAY-T2460")
    @TestCase(environments = {Environment.TST1, Environment.PPE})
    public void simulateIngoingMt103WithCover(Harness harness, @Key(Keys.paymentEngine.firstUser) Credentials user1) throws IOException {
        data.setIban(harness.getConfig("payments_cashless.foreignPayment.MT103"));
        assumptionForTestExecution_IngoingPayment(harness, user1);
        harness.log("Random amount is: " + data.getAmount());
        MT_FILE = "regression/transactional/cashless/MT103_WITH_COVER.out";

        PaymentEngineRunInstance getId = getLastMTId(harness, logInToPae(harness, user1), tasks);

        lastField = Integer.valueOf(harness.get(LAST_SEQUENCE_NUMBER_KEY));
        String mt103FileName = String.format("0106%04d.out", lastField + 1);
        File mt103File = prepareFileForInput(harness, MT_FILE, mt103FileName, data);
        PaymentEngineMonitoringInstanceFileRecords mt;

        try {
            mt = uploadFileAndCheckMtTransactionStatus(harness, getId,
                    COVER_WAIT, mt103File.getAbsolutePath(), mt103FileName);
            harness.withPaymentEngine().closePaymentEngine();
        } catch (Exception e) {
            throw e;
        } finally {
            mt103File.delete();
        }

        MT_FILE = "regression/transactional/cashless/MT910_COVER.out";

        getId = getLastMTId(harness, logInToPae(harness, user1), tasks);

        lastField = Integer.valueOf(harness.get(LAST_SEQUENCE_NUMBER_KEY));
        String mt109FileName = String.format("0106%04d.out", lastField + 1);
        File mt109File = prepareFileForInput(harness, MT_FILE, mt109FileName, data);

        try {
            mt = uploadFileAndCheckMtTransactionStatus(harness, getId,
                    ARCHIV, mt109File.getAbsolutePath(), mt109FileName);
        } catch (Exception e) {
            throw e;
        } finally {
            mt109File.delete();
        }

        mt.clickOnLifeCycleButton()
                .waitForXctStatus(harness, ARCHIV.getStatus());
        harness.withPaymentEngine().closePaymentEngine();

        harness.store("reports.tmfj.execution.comment", "Transaction amount is: " + data.getAmount()
                + "\nMT103 file name is: " + mt103FileName
                + "\nMT109 file name is: " + mt109FileName
                + "\nPrevious file ID: " + lastField
                + "\nTransaction ID is: " + harness.get(TRANSACTION_ID_KEY));
    }

    @Disabled
    @Order(4)
    @JiraTestCase(id = "PAY-T2490")
    @TestCase(name = "Create Ingoing MT103 with HD:21", environments = {Environment.TST1, Environment.PPE})
    void createIngoingMt103ForHd21(Harness harness, @Key(Keys.paymentEngine.firstUser) Credentials user1) throws IOException {

        data.setIban(harness.getConfig("payments_cashless.foreignPayment.foreignIban"));
        data.setRandom(String.valueOf(ThreadLocalRandom.current().nextInt(100, 999)));
        data.setCreditorAcc(harness.getConfig("payments_cashless.foreignPayment.foreignCreditor"));

        logInToPae(harness, user1)
                .then(tasks.storeLastMTId(filesTabName));
        harness.withPaymentEngine().closePaymentEngine();

        lastField = Integer.valueOf(harness.get(LAST_SEQUENCE_NUMBER_KEY));
        String MT103FileName = String.format("0106%04d.out", lastField + 1);
        File MT103File = prepareFileForInput(harness, MT103_FOR_HD21, MT103FileName, data);

        String HD21FileName = data.getTodayDate() + "_0600_000" + data.getLastNonpriorityField() + "_IL";
        File HD21File = prepareFileForInput(harness, HD21_FILE, HD21FileName, data);

        try {
            logInToPae(harness, user1)
                    .then(tasks.inputMTFromSAA(MT103File.getAbsolutePath()))
                    .then(tasks.checkStatusOfMTFromSAA(MT103FileName, COVER_WAIT))
                    .closeTab()
                    .then(tasks.inputCCIFromCERTIS(HD21File.getAbsolutePath()))
                    .then(tasks.checkStatusOfCCIFromCERTIS(HD21FileName, ARCHIV))
                    .then(tasks.checkStatusOfTransactionsFromSAA(MT103FileName, ARCHIV, data.getAmount(), transactionTypeFee));
            harness.withPaymentEngine().closePaymentEngine();

            String transactionId = harness.get(PaymentEngineMonitoringInstanceFileRecords.TRANSACTION_ID_KEY);
            String ingoingTransactionId = harness.get(PaymentEngineMonitoringInstanceLifeCycle.INGOING_TRANSACTION_ID_KEY);
            String feeTransactionId = harness.get(PaymentEngineMonitoringInstanceLifeCycle.FEE_TRANSACTION_ID_KEY);
            String feeAmount = harness.get(PaymentEngineMonitoringInstanceLifeCycle.FEE_AMOUNT_KEY).toString().replace(",", ".");

            checkForeignTransactionStatusBooked(harness, data.getCreditorAcc(), data.getAmountIcbs(), transactionId);

            PaymentEngineUtils.logResultWithFeeAmount(harness, transactionId, ingoingTransactionId, feeTransactionId, data.getCreditorAcc(), data.getAmount(), feeAmount);

        } catch (Exception e) {
            throw e;
        } finally {
            MT103File.delete();
            HD21File.delete();
        }
    }

    @Disabled
    @Order(5)
    @JiraTestCase(id = "PAY-T2491")
    @TestCase(name = "Create Ingoing MT103 with credit statement HD:21", environments = {Environment.TST1, Environment.PPE})
    void createIngoingMt103WithCreditStatementHd21(Harness harness, @Key(Keys.paymentEngine.firstUser) Credentials user1,
                                                   @Key(Keys.paymentEngine.secondUser) Credentials user2) throws IOException {

        data.setIban(harness.getConfig("payments_cashless.foreignPayment.foreignIban"));
        data.setRandom(String.valueOf(ThreadLocalRandom.current().nextInt(100, 999)));
        data.setDebtorAcc(harness.getConfig("payments_cashless.foreignPayment.coverAccountIngoing"));
        data.setCreditorAcc(harness.getConfig("payments_cashless.foreignPayment.foreignCreditor"));

        logInToPae(harness, user1)
                .then(tasks.storeLastMTId(filesTabName));
        harness.withPaymentEngine().closePaymentEngine();

        lastField = Integer.valueOf(harness.get(LAST_SEQUENCE_NUMBER_KEY));
        String MT103FileName = String.format("0106%04d.out", lastField + 1);
        File MT103File = prepareFileForInput(harness, MT103_OUR, MT103FileName, data);
        File HD21File = null;

        try {
            logInToPae(harness, user1)
                    .then(tasks.inputMTFromSAA(MT103File.getAbsolutePath()))
                    .then(tasks.checkStatusOfMTFromSAA(MT103FileName, COVER_WAIT))
                    .closeTab()
                    .then(tasks.editAndReleaseIngoingWaiting(harness.get(PaymentEngineMonitoringInstanceFileRecords.TRANSACTION_ID_KEY), data.getDebtorAcc()));
            harness.withPaymentEngine().closePaymentEngine();

            String transactionId = harness.get(PaymentEngineMonitoringInstanceFileRecords.TRANSACTION_ID_KEY);

            logInToPae(harness, user2)
                    .then(tasks.verifyIngoing(transactionId))
                    .then(tasks.searchTransactionAndWaitForStatus(ARCHIV, transactionId))
                    .then(tasks.checkLifeCycleAndStoreRowTransactionId(DISTRIBUTION))
                    .then(tasks.sendAndRunXCTDistribution());
            harness.withPaymentEngine().closePaymentEngine();

            String mt191TransactionId = harness.get(SECOND_ROW_TRANSACTION_ID_KEY);
            String mt191Amount = harness.get(SECOND_ROW_TRANSACTION_AMOUNT_KEY);
            data.setTrxReference(harness.get(REF_TRANSACTION_KEY));

            String HD21FileName = data.getTodayDate() + "_0600_000" + data.getLastNonpriorityField() + "_IL";
            HD21File = prepareFileForInput(harness, HD21_WITH_MT191, HD21FileName, data);

            logInToPae(harness, user1)
                    .then(tasks.inputCCIFromCERTIS(HD21File.getAbsolutePath()))
                    .then(tasks.checkStatusOfCCIFromCERTIS(HD21FileName, ARCHIV))
                    .then(tasks.searchTransactionAndWaitForStatus(ARCHIV, mt191TransactionId))
                    .then(tasks.checkLifeCycleAndStoreThirdRowTransactionId(ARCHIV));
            harness.withPaymentEngine().closePaymentEngine();

            String creditStatementHd21Id = harness.get(THIRD_ROW_TRANSACTION_ID_KEY);
            checkForeignTransactionStatusBooked(harness, data.getCreditorAcc(), data.getAmountIcbs(), transactionId);

            PaymentEngineUtils.logResultOfMt103WithCreditStatementHd21(harness, transactionId, mt191TransactionId,
                    creditStatementHd21Id, data.getCreditorAcc(), data.getAmount(), mt191Amount);

        } catch (Exception e) {
            throw e;
        } finally {
            MT103File.delete();
            HD21File.delete();
        }
    }

    @JiraTestCase(id = "PAY-T2492")
    @Order(6)
    @TestCase(name = "Test priority MT103 with MT191 + HD21", environments = {Environment.TST1, Environment.PPE})
    void outgoingPriorityMT103WithMT191AndHD21(Harness harness, @Key(Keys.paymentEngine.firstUser) Credentials user1,
                                               @Key(Keys.paymentEngine.secondUser) Credentials user2) throws IOException {

        data.setDebtorIban(harness.getConfig("payments_cashless.foreignPayment.foreignIban"));
        data.setCreditorIban(harness.getConfig("payments_cashless.foreignPayment.MT191.creditorIban"));
        data.setCreditorName("Fifinka, s.r.o.");
        data.setCreditorBic("BGLLLULLXXX");
        data.setBankName("");
        data.setCreditorAcc("");
        data.setAmount1(ThreadLocalRandom.current().nextInt(1, 299) + "," + ThreadLocalRandom.current().nextInt(1, 99));

        logInToPae(harness, user1)
                .then(tasks.createForeignPriorityPayment(data, CURRENCY_CZK_LONG));
        harness.withPaymentEngine().closePaymentEngine();

        transactionId = StringUtils.substringBetween(harness.get("TRANSACTION_ID_KEY"), "ID ", ".");

        logInToPae(harness, user2)
                .then(tasks.verifyAndWaitForStatus(transactionId, DISTRIBUTION))
                .closeTab()
                .then(tasks.sendAndRunXCTDistribution())
                .then(tasks.searchTransactionAndWaitForStatus(ARCHIV, transactionId))
                .then(tasks.checkPriorityMT103AndHD21RecordDetail(data.getDistributionDate()))
                .then(tasks.storeLastMTId(filesTabName));
        harness.withPaymentEngine().closePaymentEngine();

        data.setTrxReference(harness.get(PaymentEngineSearchTransactionRecordDetail.REF_TRANSACTION_KEY));
        lastField = Integer.valueOf(harness.get(LAST_SEQUENCE_NUMBER_KEY));
        String MT103FileName = String.format("0106%04d.out", lastField + 1);
        File MT103File = prepareFileForInput(harness, MT103_WITH_MT191, MT103FileName, data);

        try {

            logInToPae(harness, user1)
                    .then(tasks.inputMTFromSAA(MT103File.getAbsolutePath()))
                    .then(tasks.checkStatusOfMTFromSAA(MT103FileName, ARCHIV))
                    .closeTab()
                    .then(tasks.checkStatusOfTransactionsFromSAA(MT103FileName, ARCHIV, data.getAmount1(), transactionTypeHD21));
            harness.withPaymentEngine().closePaymentEngine();

        } catch (Exception e) {
            throw e;
        } finally {
            MT103File.delete();
        }

        harness.store("reports.tmfj.execution.comment", "\nPriority xCT MT103 outgoing " + transactionId + " was successfully archived."
                + "\nxCT MTx91 ingoing " + harness.get(FEE_TRANSACTION_ID_KEY) + " was successfully archived."
                + "\nDebtor IBAN: " + data.getIban()
                + "\nCreditor IBAN: " + data.getCreditorIban()
                + "\nPriority xCT MT103 outgoing amount: " + data.getAmount()
                + "\nxCT MTx91 ingoing amount: " + data.getAmount1()
                + "\nMT103 file name is: " + MT103FileName);
    }

    PaymentEngineHomePage logInToPae(Harness harness, @Key("payment.engine") Credentials credentials) {
        return harness.withPaymentEngine()
                .openLoginPage()
                .login(credentials.getUsername(), credentials.getPassword())
                .clickOkButton();
    }

    void assumptionForTestExecution_IngoingPayment(Harness harness, @Key("payment.engine") Credentials credentials) {
        logInToPae(harness, credentials)
                .clickAdministrationAndChooseChannelParametersFromParameters()
                .fillParameterName("VALIDATE_CHECKSUM")
                .clickOnChannel()
                .selectChannel(ParameterChannels.MT)
                .clickApplyButton()
                .getParameterValue();
        harness.withPaymentEngine().closePaymentEngine();
        assumeTrue(harness.get(PARAMETER_VALUE_ID_KEY).equals("N"));
    }

    private PaymentEngineMonitoringInstanceFileRecords uploadFileAndCheckMtTransactionStatus(Harness harness, PaymentEngineRunInstance getId, TransactionReasonPAE reason, String filePath, String fileName) {

        return getId.clickOnUploadFileButton()
                .uploadFile(filePath)
                .clickSendPopupButton()
                .clickOkPopupButton()
                .clickOnFileTab("Soubory")
                .waitForFileAndClickOnIt(fileName)
                .clickOkButton()
                .closeTab()
                .clickMonitoringAndChooseChannelInstanceFromChanelMonitoring()
                .clickOnSelectStatus()
                .selectStatusSuccess()
                .clickOnApplyButton()
                .waitForChannelAndClickOnRecords(fileName)
                .storeTransactionId()
                .waitForStatus(harness, reason);

    }

    private PaymentEngineRunInstance getLastMTId(Harness harness, PaymentEngineHomePage page, PaymentEngineTasks tasks) {
        return page.then(tasks.checkQueForMTExistence(filesTabName))
                .clickOnInputMT()
                .clickOnRunButton()
                .storeLastNumberInSequence(harness);
    }

}
