package cz.moneta.test.dsl.util.task.wso2.payments;

import com.google.gson.JsonObject;
import cz.moneta.test.dsl.Harness;
import cz.moneta.test.dsl.payment_engine.enums.AccountStates;
import cz.moneta.test.dsl.payment_engine.enums.CurrencyPAE;
import cz.moneta.test.dsl.payment_engine.model.IcbsReservationListSuccessResponse;
import cz.moneta.test.dsl.util.DateUtils;
import cz.moneta.test.dsl.util.data.client.NonClient;
import cz.moneta.test.dsl.util.data.payment.PaymentData;
import cz.moneta.test.harness.exception.HarnessException;
import cz.moneta.test.harness.support.rest.RawRestRequest;

import java.time.LocalDateTime;

public class PaymentsTasks {

    private final Harness harness;
    public static String TRANSACTION_ID_KEY = "TRANSACTION_ID_KEY";

    public PaymentsTasks(Harness harness) {
        this.harness = harness;
    }

    public ListOfTransactionsSuccessResponse getTransactionStatus(String token, String request) {
        return harness.withWso2()
                .prepareRequest()
                .withPath("/t/payments.cluster/GET_HISTORY_TRXS/001/")
                .withHeader("Content-Type", "application/json")
                .withHeader("Accept", "application/json")
                .withHeader("Authorization", token)
                .withHeader("cache-control", "no-cache,no-cache")
                .withHeader("USERID_L2", "800001701")
                .withPayload(request)
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(ListOfTransactionsSuccessResponse.class);
    }

    public void checkTransactionStatusBooked(String token, String request, String transactionId) {
        //1 API call each 10 seconds for 30 seconds
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new HarnessException("Error during Thread.sleep: " + e.getMessage());
            }

            ListOfTransactionsSuccessResponse responseData = getTransactionStatus(token, request);

            for (ListOfTransactionsSuccessResponse.RS_DATA rs_data : responseData.RS_DATA) {
                String transactionIdFromResponse = rs_data.OUDCID.substring(rs_data.OUDCID.length() - 7);
                if (transactionId.substring(transactionId.length() - 7).equals(transactionIdFromResponse)) {
                    harness.log("Transaction " + transactionId + " was found in ICBS." + responseData);
                    return;
                }
            }
            harness.log("Transaction " + transactionId + " was NOT found in ICBS. Cycle number: " + i);
        }
        throw new HarnessException("Transaction " + transactionId + " was NOT found in ICBS.");
    }

    public void checkTransactionTypeStatusBooked(String token, String request, String transactionId, PaymentData data) {
        //1 API call each 10 seconds for 30 seconds
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new HarnessException("Error during Thread.sleep: " + e.getMessage());
            }

            ListOfTransactionsSuccessResponse responseData = getTransactionStatus(token, request);

            for (ListOfTransactionsSuccessResponse.RS_DATA rs_data : responseData.RS_DATA) {
                String transactionIdFromResponse = rs_data.OUDCID.substring(rs_data.OUDCID.length() - 7);
                String transactionTypeFromResponse = rs_data.OUOTC;
                if (transactionId.substring(transactionId.length() - 7).equals(transactionIdFromResponse)
                        && data.getHdType().equals(transactionTypeFromResponse)) {
                    harness.log("Transaction " + transactionId + " was found in ICBS.");
                    return;
                }
            }
            harness.log("Transaction " + transactionId + " was NOT found in ICBS. Cycle number: " + i);
        }
        throw new HarnessException("Transaction " + transactionId + " was NOT found in ICBS.");
    }

    public void checkForeignTransactionStatusBooked(String token, String request, String transactionId) {
        //1 API call each 10 seconds for 30 seconds
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new HarnessException("Error during Thread.sleep: " + e.getMessage());
            }

            ListOfTransactionsSuccessResponse responseData = getTransactionStatus(token, request);

            for (ListOfTransactionsSuccessResponse.RS_DATA rs_data : responseData.RS_DATA) {
                String transactionIdFromResponse = rs_data.OUDSC1.substring(rs_data.OUDSC1.length() - 16);
                if (transactionId.substring(transactionId.length() - 16).equals(transactionIdFromResponse)) {
                    harness.log("Transaction " + transactionId + " was found in ICBS.");
                    return;
                }
            }
            harness.log("Transaction " + transactionId + " was NOT found in ICBS. Cycle number: " + i);
        }
        throw new HarnessException("Transaction " + transactionId + " was NOT found in ICBS.");
    }

    public static String createRequestForTransactionCheck(String debtorAccount, String todayDate, String amount) {
        JsonObject json = new JsonObject();
        json.addProperty("INBANK", 1);
        json.addProperty("INACCT", debtorAccount);
        json.addProperty("INDATEF", todayDate);
        json.addProperty("INDATET", todayDate);
        json.addProperty("INAMTF", amount);
        json.addProperty("INAMTT", amount);
        json.addProperty("INCURSOR", 1);
        json.addProperty("INROWS", 999999);
        return json.toString();
    }

    public void changeClientName(String token, String request) {
        harness.withWso2()
                .prepareRequest()
                .withPath("/t/payments.cluster/CHG_CUST/001/")
                .withHeader("Content-Type", "application/json")
                .withHeader("Accept", "application/json")
                .withHeader("Authorization", token)
                .withHeader("cache-control", "no-cache,no-cache")
                .withHeader("USERID_L2", "800001701")
                .withPayload(request)
                .post()
                .andAssertFieldValue("RT1CNT", "0");
    }

    public static String createRequestForClientNameChange(String clientId, NonClient nonClient) {
        JsonObject json = new JsonObject();
        json.addProperty("INCNBR", clientId);
        json.addProperty("INCFF1", "YYYYYYYYYYY      YYYYY");
        json.addProperty("INCFNM", nonClient.firstName());
        json.addProperty("INCLNM", nonClient.lastName());
        json.addProperty("INCSTR", nonClient.residencyAddress().getStreet());
        json.addProperty("INCDIS", nonClient.residencyAddress().getCity());
        json.addProperty("INCTWN", "Praha 011");
        json.addProperty("INCNTY", nonClient.residencyAddress().getCountry());
        json.addProperty("INPSTL", nonClient.residencyAddress().getZip());
        json.addProperty("INCFNO", "208");
        json.addProperty("INCHNO", nonClient.residencyAddress().getOrientationNumber());
        json.addProperty("INCCTY", nonClient.residencyAddress().getCityPart());
        json.addProperty("INCSTA", "52");
        json.addProperty("INOVFG", "1");
        json.addProperty("INDACI", "Y");
        json.addProperty("INSTFG", "2");
        json.addProperty("INCFF7", "  Y");
        return json.toString();
    }

    public void changeClientsAccountState(String token, String request) {
        harness.withWso2()
                .prepareRequest()
                .withPath("/t/payments.cluster/CHG_CAACCT/001/")
                .withHeader("Content-Type", "application/json")
                .withHeader("Accept", "application/json")
                .withHeader("Authorization", token)
                .withHeader("cache-control", "no-cache,no-cache")
                .withHeader("USERID_L2", "800001701")
                .withPayload(request)
                .post()
                .andAssertFieldValue("RT1CNT", "0");
    }

    public static String createRequestForClientsAccountStateChange(String clientsAccount, AccountStates clientsAccountState) {
        JsonObject json = new JsonObject();
        json.addProperty("INBK", 1);
        json.addProperty("INTYP", "6");
        json.addProperty("INACC1", "0");
        json.addProperty("INACCT", clientsAccount);
        json.addProperty("INCFFA", "Y");
        json.addProperty("INSTAT", clientsAccountState.getState());
        json.addProperty("INDACI", "N");
        return json.toString();
    }

    public void changeClientsTimeAccountState(String token, String request) {
        harness.withWso2()
                .prepareRequest()
                .withPath("/t/payments.cluster/CHG_TMACCT/001/")
                .withHeader("Content-Type", "application/json")
                .withHeader("Accept", "application/json")
                .withHeader("Authorization", token)
                .withHeader("cache-control", "no-cache,no-cache")
                .withHeader("USERID_L2", "800001701")
                .withPayload(request)
                .post()
                .andAssertFieldValue("RT1CNT", "0");
    }

    public static String createRequestForClientsTimeAccountStateChange(String clientsAccount, AccountStates clientsAccountState) {
        JsonObject json = new JsonObject();
        json.addProperty("INCFFA", "                                       Y");
        json.addProperty("INACCT", clientsAccount);
        json.addProperty("INSTAT", clientsAccountState.getState());
        json.addProperty("INDACI", "Y");
        return json.toString();
    }

    public void changeClientsLoanAccountBranchCode(String token, String request) {
        harness.withWso2()
                .prepareRequest()
                .withPath("/t/payments.cluster/ICB/CHG_LN_INSUREXP/001/")
                .withHeader("Content-Type", "application/json")
                .withHeader("Accept", "application/json")
                .withHeader("Authorization", "Bearer " + token)
                .withHeader("cache-control", "no-cache,no-cache")
                .withHeader("USERID_L2", "800001701")
                .withPayload(request)
                .post()
                .andAssertFieldValue("RT1CNT", "0");
    }

    public static String createRequestForClientsLoanAccountBranchCodeChange(String clientsAccount, String branchCode) {
        JsonObject json = new JsonObject();
        json.addProperty("InBank", 1);
        json.addProperty("InNote", clientsAccount);
        json.addProperty("InBrch", branchCode);
        return json.toString();
    }

    public static String createRequestForIFCYTransactionCreating(PaymentData data, CurrencyPAE currencyPAE) {
        JsonObject json = new JsonObject();
        json.addProperty("clrMsgType", data.getTypeOfMessage());
        json.addProperty("reqdExctnDt", DateUtils.convertRawDateForWso2(DateUtils.getTodayRawDate()));

        JsonObject instdAmt = new JsonObject();
        instdAmt.addProperty("amt", data.getAmount());
        instdAmt.addProperty("ccy", currencyPAE.getCurrency());
        json.add("instdAmt", instdAmt);

        JsonObject xchgRateInf = new JsonObject();
        xchgRateInf.addProperty("rateTp", data.getRateType());
        xchgRateInf.addProperty("xchgRate", data.getExchangeRate());
        xchgRateInf.addProperty("xchgRateDtTm", DateUtils.convertShortDateTimeForWso2(LocalDateTime.now()));
        json.add("xchgRateInf", xchgRateInf);

        JsonObject dbtrAcct = new JsonObject();
        dbtrAcct.addProperty("accNum", data.getDebtorAcc());
        json.add("dbtrAcct", dbtrAcct);

        JsonObject dbtrAgt = new JsonObject();
        dbtrAgt.addProperty("mmbId", "0600");
        json.add("dbtrAgt", dbtrAgt);

        JsonObject cdtrAcct = new JsonObject();
        cdtrAcct.addProperty("accLed", false);
        cdtrAcct.addProperty("accNum", data.getCreditorAcc());
        json.add("cdtrAcct", cdtrAcct);

        JsonObject cdtrAgt = new JsonObject();
        cdtrAgt.addProperty("mmbId", "0600");
        json.add("cdtrAgt", cdtrAgt);

        JsonObject cdtrRefInf = new JsonObject();
        cdtrRefInf.addProperty("refSymbolVS", "1234567890");
        cdtrRefInf.addProperty("refSymbolSS", "9876543210");
        cdtrRefInf.addProperty("refSymbolKS", "0123456789");
        json.add("cdtrRefInf", cdtrRefInf);

        JsonObject splmtryData = new JsonObject();
        splmtryData.addProperty("ICBS_TranServerProfile", data.getIcbsProfile());
        splmtryData.addProperty("channelID", "SB");
        splmtryData.addProperty("forceDeb", false);
        splmtryData.addProperty("initPay", "C");
        splmtryData.addProperty("payScheme", data.getPayScheme());
        splmtryData.addProperty("userID", "800001701");
        json.add("SplmtryData", splmtryData);

        return json.toString();
    }

    public void createIFCYTransaction(String token, String request) {
        RawRestRequest.Response response = harness.withWso2()
                .prepareRequest()
                .withPath("/t/payments.cluster/domestic-payment-controller/v1/paymentorders/async")
                .withHeader("Content-Type", "application/json")
                .withHeader("Accept", "application/json")
                .withHeader("Authorization", token)
                .withHeader("cache-control", "no-cache,no-cache")
                .withHeader("USERID_L2", "800001701")
                .withPayload(request).post().andAssertStatus(201)
                .andAssertFieldValue("txSts", "ACTC")
                .andAssertPresent("txId");

        String transactionId = response.extract("txId").asText();

        harness.store("TRANSACTION_ID_KEY", transactionId);
    }

    public static String createRequestForForeignTransactionCreating(PaymentData data) {
        JsonObject json = new JsonObject();
        json.addProperty("CHANNEL_ID", data.getChannelId());
        json.addProperty("PAYMENT_METHOD", "TRF");
        json.addProperty("REQUESTED_EXEC_DATE", data.getTodayDate());
        json.addProperty("DBTR_ACC_NUM", data.getDebtorAcc());
        json.addProperty("INSTR_AMT", data.getAmount());
        json.addProperty("INSTR_AMT_CURR", data.getCurrencyCode());
        json.addProperty("CHARGE_BEARER", data.getFeeType());
        json.addProperty("AUTHORIZATION_REQUESTED", false);
        json.addProperty("CDTR_ACC_OTHER_ID", data.getCreditorIban());
        json.addProperty("CDTR_NAME", data.getCreditorName());
        json.addProperty("CDTR_ADR_LINE_1", data.getCreditorAdressLine1());
        json.addProperty("CDTR_ADR_LINE_2", data.getCreditorAdressLine2());
        json.addProperty("END_TO_END_ID", data.getE2eRefDb());
        json.addProperty("REMITTANCE_INF_UNSTRUCTURED", data.getMessage());
        return json.toString();
    }

    public void createForeignTransaction(String token, String request) {
        RawRestRequest.Response response = harness.withWso2()
                .prepareRequest()
                .withPath("/t/payments.cluster/CRT_PAYMENT_ORDER/001")
                .withHeader("Content-Type", "application/json")
                .withHeader("Accept", "application/json")
                .withHeader("Authorization", token)
                .withHeader("cache-control", "no-cache,no-cache")
                .withHeader("USERID_L2", "800001701")
                .withPayload(request)
                .post()
                .andAssertStatus(200)
                .andAssertPresent("ID_PE");

        String transactionId = response.extract("ID_PE").asText();

        harness.store("TRANSACTION_ID_KEY", transactionId);
    }

    public void checkReservationPresence(String token, String request, String formattedAmount,
                                         PaymentData data) {
        //1 API call each 10 seconds for 30 seconds
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new HarnessException("Error during Thread.sleep: " + e.getMessage());
            }

            IcbsReservationListSuccessResponse response = harness.withWso2()
                    .prepareRequest()
                    .withPath("/t/payments.cluster/GET_HOLDS/001/")
                    .withHeader("Content-Type", "application/json")
                    .withHeader("Accept", "application/json")
                    .withHeader("Authorization", token)
                    .withHeader("cache-control", "no-cache,no-cache")
                    .withHeader("USERID_L2", "800001701")
                    .withPayload(request)
                    .post()
                    .mapResponseIntoObject(IcbsReservationListSuccessResponse.class);

            for (IcbsReservationListSuccessResponse.RS_DATA rs_data : response.RS_DATA) {
                String amountFromResponse = String.valueOf(rs_data.OUAMT);
                String dateFromResponse = String.valueOf(rs_data.OUEDT);
                if (formattedAmount.equals(amountFromResponse) && data.getTodayDate().equals(dateFromResponse)) {
                    harness.log("Reservation was found in ICBS.");
                    return;
                }
            }
            harness.log("Reservation was NOT found in ICBS. Cycle number: " + i);
        }
        throw new HarnessException("Account number: " + data.getAccountNumberClient()
                + "\n" +
                "New card reservation was created with amount: " + data.getAmount() + " with date: " + data.getReservationDate()
                + "\n" +
                "Reservation was NOT found in ICBS.");
    }

    public String createRequestForListOfReservationsInICBS(Integer clientsAccount) {
        JsonObject json = new JsonObject();
        json.addProperty("INBK", 1);
        json.addProperty("INTYP", 6);
        json.addProperty("INACCT", clientsAccount);
        json.addProperty("INCURSOR", 1);
        json.addProperty("INROWS", 99999999);
        return json.toString();
    }

    public void pennyPayment(String amount, String paymentDate, String accountNumber, String againstPartyAccountNumber, String againstPartyBankNumber, String againstPartyName, String description) {
        harness.tasks().wso2()
                .restRequest()
                .prepareEmptyRequestFromCbl("/t/payments.cluster/CRT_FROM_CNB_TRX/001/")
                .addField("INTRCD", "11")
                .addField("INAMNT", amount)
                .addField("INIDDATE", paymentDate)
                .addField("INID", accountNumber)
                .addField("INDAC2", againstPartyAccountNumber)
                .addField("INDBNK", againstPartyBankNumber)
                .addField("INDACNAME", againstPartyName)
                .addField("INAVM", description)
                .addField("INCAC2", accountNumber)
                .post();
    }
}
