package cz.moneta.test.regression.transactional.payments.cashless.payment_engine.analytical;

import cz.moneta.test.dsl.Harness;
import cz.moneta.test.dsl.newib.mainpage.AccountsPage;
import cz.moneta.test.dsl.payment_engine.PaymentEngineReservationPage;
import cz.moneta.test.dsl.payment_engine.enums.PaymentDirection;
import cz.moneta.test.dsl.payment_engine.enums.PaymentType;
import cz.moneta.test.dsl.payment_engine.model.ReservationListSuccessResponse;
import cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_cache24_7.PaymentsEngineCache24SearchAccountsNumber;
import cz.moneta.test.dsl.util.DateUtils;
import cz.moneta.test.dsl.util.data.payment.PaymentData;
import cz.moneta.test.harness.annotations.Environment;
import cz.moneta.test.harness.annotations.JiraTestCase;
import cz.moneta.test.harness.annotations.TestCase;
import cz.moneta.test.harness.annotations.TestScenarioWithOrder;
import cz.moneta.test.harness.endpoints.payment_engine.PaymentEngineEndpoint;
import cz.moneta.test.harness.support.auth.Credentials;
import cz.moneta.test.harness.support.auth.Key;
import net.bytebuddy.utility.RandomString;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.ThreadLocalRandom;

import static cz.moneta.test.dsl.payment_engine.PaymentEngineReservationPage.LAST_RESERVATION_DATE_KEY;
import static cz.moneta.test.dsl.payment_engine.PaymentEngineReservationPage.SELECTED_RESERVATION_ID_KEY;
import static org.apache.commons.lang3.StringUtils.replace;


@TestScenarioWithOrder(name = "Create manual reservation and check reservation in IB")
public class ReservationsController {
    private String TOKEN_CBL;
    private String TOKEN_PAE;
    private PaymentData data;

    @BeforeAll
    void testSetUp(Harness harness) {
        data = PaymentData.builder()
                .accountNumberClient(harness.getConfig("payments_cashless.reservationController.account"))
                .clientBirthNum(harness.getConfig("payments_cashless.reservationController.rc"))
                .todayDate(DateUtils.getFormattedTodayDate("yyyy-MM-dd"))
                .description("Automated test")
                .smsCode("12341234")
                .build();
        TOKEN_CBL = harness.tasks().wso2().authorization().getToken("DigitalchannelsSB_CBL");
        TOKEN_PAE = harness.tasks().wso2().authorization().getToken("PAYMENTS_PAE");
    }

    @BeforeEach
    void setUpBeforeEach() {
        generateUniqueAmount();
    }

    @Disabled("Not currently maintained")
    @JiraTestCase(id = "PAY-T1646")
    @Order(1)
    @TestCase(name = "Log into PE and create reservation", environments = {Environment.TST1, Environment.PPE})
    void createManualReservationAndCheckInIB(Harness harness, @Key("payment.engine") Credentials credentials) {
        searchAccountNumber(harness, credentials)
                .clickOnReservationButton()
                .clickCreateOnButton()
                .clickOnSelectType()
                .selectType(PaymentType.MANUAL)
                .clickOnDirection()
                .selectDirection(PaymentDirection.DEBET)
                .fillManualData(data.getAmount(), data.getDescription(), data.getDescription())
                .clickSubmit()
                .getLastReservationDate();
        harness.closeEndpoint(harness.getEndpoint(PaymentEngineEndpoint.class));

        data.setReservationDate(harness.get(LAST_RESERVATION_DATE_KEY));

        harness.log("New reservation was created with amount: " + data.getAmount() + " with date: " + data.getReservationDate());

        logIndIBAndGoToPendingTransactionPage(harness)
                .selectAccountNumber(data.getAccountNumberClient() + "/0600")
                .searchAmount(data.getAmount1())
                .checkReservationDate(data.getReservationDate())
                .checkReservationAmount("-" + data.getAmount())
                .checkReservationDescription("Ostatní blokace");

        harness.log("Reservation was found");
    }

    @JiraTestCase(id = "PAY-T1648")
    @Order(2)
    @TestCase(name = "Update reservation", environments = {Environment.TST1, Environment.PPE})
    void updateManualReservation(Harness harness, @Key("payment.engine") Credentials credentials) {
        searchAccountNumber(harness, credentials)
                .clickOnReservationButton()
                .clickOnFirstManualReservation()
                .clickOnEditButton()
                .fillManualData(
                        data.getAmount(), "Update Automated test",
                        "Update Automated test")
                .clickSubmit()
                .clickOnFirstManualReservation()
                .checkSelectedReservationAmount(data.getAmount());

        harness.log("Manual reservation amount was successfully changed to " + data.getAmount());
        harness.store("reports.tmfj.execution.comment", "Manual reservation amount was successfully changed to " + data.getAmount()
                + "\n" + "Account number: " + data.getAccountNumberClient());
    }

    @JiraTestCase(id = "PAY-T1649")
    @Order(3)
    @TestCase(name = "Delete reservation", environments = {Environment.TST1, Environment.PPE})
    void deleteManualReservation(Harness harness, @Key("payment.engine") Credentials credentials) {
        PaymentEngineReservationPage saveSelectedReservationId = searchAccountNumber(harness, credentials)
                .clickOnReservationButton()
                .getSelectedReservationId();

        String reservationToBeDeleted = harness.get(SELECTED_RESERVATION_ID_KEY);

        saveSelectedReservationId
                .clickOnDeleteButton()
                .clickSubmit()
                .getSelectedReservationId();

        Assertions.assertNotEquals(reservationToBeDeleted, harness.get(SELECTED_RESERVATION_ID_KEY));
        harness.log("Manual reservation " + reservationToBeDeleted + " was successfully deleted.");
        harness.store("reports.tmfj.execution.comment", "Manual reservation " + reservationToBeDeleted + " was successfully deleted."
                + "\n" + "Account number: " + data.getAccountNumberClient());
    }

    @JiraTestCase(id = "PAY-T1655")
    @Order(4)
    @TestCase(name = "Create Card Reservation in PAE and check in ICBS", environments = {Environment.TST1, Environment.PPE})
    void createCardReservationInPAEAndCheckInICBS(Harness harness, @Key("payment.engine") Credentials credentials) {
        String cardId = "4417123456789113";
        String createDate = DateUtils.getFormattedTodayDateTime("dd.MM.yyyy HH:mm:ss");
        String accountDay = DateUtils.getFormattedTodayDate("dd.MM.yyyy");
        String generatedId = generateId();

        searchAccountNumber(harness, credentials)
                .clickOnReservationButton()
                .clickCreateOnButton()
                .clickOnSelectType()
                .selectType(PaymentType.CARD)
                .clickOnDirection()
                .selectDirection(PaymentDirection.DEBET)
                .fillCardData(
                        generatedId, data.getAmount(),
                        createDate,
                        accountDay,
                        data.getDescription(),
                        data.getDescription(),
                        cardId,
                        generatedId)
                .clickSubmit()
                .getLastReservationDate();
        harness.closeEndpoint(harness.getEndpoint(PaymentEngineEndpoint.class));

        data.setReservationDate(formatDate(harness.get(LAST_RESERVATION_DATE_KEY)));
        String request = harness.tasks().wso2().payments().createRequestForListOfReservationsInICBS(Integer.valueOf(data.getAccountNumberClient()));

        harness.tasks()
                .wso2()
                .payments()
                .checkReservationPresence(TOKEN_CBL, request, data.getAmount1(), data);

        harness.log("New card reservation was created with amount: " + data.getAmount() + " with date: " + data.getReservationDate());
        harness.store("reports.tmfj.execution.comment", "Account number: " + data.getAccountNumberClient()
                + "\n" +
                "Card number: " + cardId
                + "\n" +
                "New card reservation was created with amount: " + data.getAmount() + " with date: " + data.getReservationDate()
                + "\n" +
                "Card reservation was successfully found in ICBS.");
    }

    @JiraTestCase(id = "PAY-T2936")
    @Order(5)
    @TestCase(name = "Create manual reservation in PAE and check in ICBS", environments = {Environment.TST1, Environment.PPE})
    void createManualReservationInPAEAndCheckInICBS(Harness harness, @Key("payment.engine") Credentials credentials) {
        searchAccountNumber(harness, credentials)
                .clickOnReservationButton()
                .clickCreateOnButton()
                .clickOnSelectType()
                .selectType(PaymentType.MANUAL)
                .clickOnDirection()
                .selectDirection(PaymentDirection.DEBET)
                .fillManualData(data.getAmount(), data.getDescription(), data.getDescription())
                .clickSubmit()
                .getLastReservationDate();
        harness.closeEndpoint(harness.getEndpoint(PaymentEngineEndpoint.class));

        data.setReservationDate(formatDate(harness.get(LAST_RESERVATION_DATE_KEY)));
        String request = harness.tasks().wso2().payments().createRequestForListOfReservationsInICBS(Integer.valueOf(data.getAccountNumberClient()));

        harness.tasks()
                .wso2()
                .payments()
                .checkReservationPresence(TOKEN_CBL, request, data.getAmount1(), data);

        harness.log("New manual reservation was created with amount: " + data.getAmount() + " with date: " + data.getReservationDate());
        harness.store("reports.tmfj.execution.comment", "Account number: " + data.getAccountNumberClient()
                + "\n" +
                "New manual reservation was created with amount: " + data.getAmount() + " with date: " + data.getReservationDate()
                + "\n" +
                "Manual reservation was successfully found in ICBS.");
    }

    @AfterAll
    void refreshTestDataAndDeleteReservations(Harness harness, @Key("payment.engine") Credentials credentials) {
        String path;
        //get active reservations via FE API
        ReservationListSuccessResponse res = harness.withWso2()
                .prepareRequest()
                .withPath("/t/payments.cluster/frontend-reservation-controller/v1/frontend/reservations/" + data.getAccountNumberClient())
                .withHeader("Content-Type", "application/json")
                .withHeader("Accept", "application/json")
                .withHeader("Authorization", TOKEN_CBL)
                .withHeader("cache-control", "no-cache,no-cache")
                .get()
                .mapResponseIntoObject(ReservationListSuccessResponse.class);

        if (res.reservations.size() > 70) {
            for (int i = 0; i < 50; i++) {
                path = data.getAccountNumberClient() + "/" + res.reservations.get(i).cacheId + "/" + res.reservations.get(i).version;
                //delete active reservations via API for PE GUI
                harness.withWso2()
                        .prepareRequest()
                        .withPath("/t/payments.cluster/gui-reservation-controller/v1/gui/reservation/" + path)
                        .withHeader("Content-Type", "application/json;charset=UTF-8")
                        .withHeader("Accept", "application/json")
                        .withHeader("Authorization", TOKEN_PAE)
                        .withHeader("cache-control", "no-cache,no-cache")
                        .withHeader("userSsoId", credentials.getUsername())
                        .delete();
            }
        }
    }

    PaymentsEngineCache24SearchAccountsNumber searchAccountNumber(Harness harness, @Key("payment.engine") Credentials credentials) {
        return harness.withPaymentEngine()
                .openLoginPage()
                .login(credentials.getUsername(), credentials.getPassword())
                .clickOkButton()
                .clickOnCache24_7()
                .clickOnAccountAndReservation()
                .typeInternalAccountNumberAndClickApply(data.getAccountNumberClient());
    }

    AccountsPage logIndIBAndGoToPendingTransactionPage(Harness harness) {
        Credentials ibCredentials = harness.withUdebs()
                .ib()
                .usernameAndPassword()
                .getUsernameAndPasswordByRc(data.getClientBirthNum());

        return harness.withNewIb()
                .openLoginPage()
                .closeCookiesPanelIfVisible()
                .clickLoginWithIdAndPassword()
                .typeUsername(ibCredentials.getUsername())
                .clickContinue()
                .typePassword(ibCredentials.getPassword())
                .clickToLogin()
                .onAuthMobileKeyPage()
                .typeSmsKey(data.getSmsCode())
                .clickSend()
                .onDashboardPage()
                .goToAccounts();
    }

    void generateUniqueAmount() {
        double generatedNumber = ThreadLocalRandom.current().nextDouble(1.00, 5.00);
        BigDecimal decimal = new BigDecimal(Double.toString(generatedNumber));
        data.setAmount(replace(String.valueOf(decimal.setScale(2, RoundingMode.HALF_UP).doubleValue()), ".", ","));
        data.setAmount(data.getAmount().length() == 3 ? data.getAmount() + "0" : data.getAmount());
        data.setAmount1(data.getAmount().replace(",", "."));
    }

    String generateId() {
        return new RandomString(6).nextString();
    }

    private String formatDate(String date) {
        date = date.replaceFirst("(\\d{2}).(\\d{2}).(\\d{4})", "$1. $2. $3");
        date = date.replaceFirst("^0", "");
        date = date.replaceFirst(". 0", ". ");
        return StringUtils.substringBeforeLast(date, " ");
    }
}