package cz.moneta.test.dsl.util.task.dataprepare;

import cz.moneta.test.dsl.Harness;
import cz.moneta.test.dsl.util.DateUtils;
import cz.moneta.test.dsl.util.data.account.AccountDetail;
import cz.moneta.test.dsl.util.data.client.NewClient;
import cz.moneta.test.dsl.util.data.client.NewClientWithCurrentAccountInformation;
import cz.moneta.test.dsl.util.data.client.NonClient;
import cz.moneta.test.dsl.util.task.wso2.ClientTasks;
import cz.moneta.test.dsl.util.task.wso2.digitalchannels.IbTasks;
import cz.moneta.test.harness.endpoints.testautomationdb.TestAutomationDbEndpoint;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class DataPrepareTasks {

    private static final Logger logger = LogManager.getLogger(DataPrepareTasks.class);

    private final Harness harness;

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

    /**
     * This method defines sequence of APIs for creation of new customer - natural person - FO. This customer is not a client yet (checking unique birth number).
     * Customer is created via WSO2 and this method returns new customer CIF.
     * <p>
     * Called APIs:
     * <ol>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ClientTasks#createCifFo(NonClient)} - create new customer
     * </li>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ClientTasks#setGdprConsent(String)} - set GDPR consents
     * </li>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ClientTasks#setResidencyAddress(NonClient, String, String)} - set residency address
     * </li>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ClientTasks#setCrAsTaxResidency(String)} - set CZ as tax residency
     * </li>
     * </ol>
     * </p>
     * <p>
     * This method is not possible to use locally - it needs access to Wso2
     * </p>
     *
     * @param bankerUsername banker name to be set as sekundarniUrednik parameter
     * @return newFoCustomerCif
     */
    public String createNewFoCustomerViaWso2AndGetCif(String bankerUsername) {
        NonClient nonClient = harness.data().newNonClient();
        return createNewFoCustomerViaWso2AndGetCif(nonClient, bankerUsername);
    }

    public String createNewFoCustomerViaWso2AndGetCif(NonClient nonClient, String bankerUsername) {
        String createdDateTime = getStartDateTime();
        String newFoCustomerCif = createNewFoCustomerApiSequence(bankerUsername, nonClient);

        logger.info("New customer CIF: " + newFoCustomerCif);
        harness.getEndpoint(TestAutomationDbEndpoint.class)
                .insertCreatedClientInfo(newFoCustomerCif, nonClient.birthNumber(), null, createdDateTime, bankerUsername, "MWF", null);

        return newFoCustomerCif;
    }

    /**
     * This method defines sequence of APIs for creation of new customer - legal person - FOP. This customer is not a client yet (checking unique birth number).
     * Customer is created via WSO2 and this method returns new customer CIF.
     * Called APIs:
     * <p>
     * Called APIs:
     * <ol>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ClientTasks#createCifFop(NonClient, String)} - creates new fop customer
     * </li>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ClientTasks#createAccountAndGetAccountNumber(NewClient, AccountDetail, String)} - creates account
     * </li>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ClientTasks#subsidyAccount(String, double, String, int)} - subsides account
     * </li>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ClientTasks#findUnifiedClient(String)} - finds client unified id in ODS
     * </li>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ComodaTasks#createClientComoda(Long)} - creates client in Comoda
     * </li>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ComodaTasks#setEmployeeCount(Long, Long)}  - sets employee count in Comoda
     * </li>
     * <li>
     * {@link cz.moneta.test.dsl.util.task.wso2.ClientTasks#relationFoFop(String, String)} - creates relation between client and commercial banker
     * </li>
     * </ol>
     * </p>
     * <p>
     * This method is not possible to use locally - it needs access to Wso2
     * </p>
     *
     * @param bankerUsername banker name to be set as banker parameter
     * @return newFopCustomerCif
     */
    public String createNewFopCustomerViaWso2AndGetCif(String bankerUsername) {
        NonClient nonClient = harness.data().newNonClient();
        return createNewFopCustomerViaWso2AndGetCif(nonClient, bankerUsername);
    }

    public String createNewFopCustomerViaWso2AndGetCif(NonClient nonClient, String bankerUsername) {
        TestAutomationDbEndpoint ep = harness.getEndpoint(TestAutomationDbEndpoint.class);

        String newFoCustomerCif = createNewFoCustomerApiSequence(bankerUsername, nonClient);
        ep.insertCreatedClientInfo(newFoCustomerCif, nonClient.birthNumber(), null, getStartDateTime(), bankerUsername, "MWF", null);
        String newFopCustomerCif = createNewFopCustomerApiSequence(bankerUsername, nonClient);
        ep.insertCreatedClientInfo(newFopCustomerCif, nonClient.birthNumber(), nonClient.ico(), getStartDateTime(), bankerUsername, "MWF", null);
        harness.tasks().wso2().client().relationFoFop(newFoCustomerCif, newFopCustomerCif);
        createInternetBankFop(nonClient, newFopCustomerCif);

        logger.info("New FO customer CIF: " + newFoCustomerCif);
        logger.info("New FOP customer CIF: " + newFopCustomerCif);
        return newFopCustomerCif;
    }

    public NewClientWithCurrentAccountInformation createNewFoCustomerWithCurrentAccountAndIbViaWso2(String bankerUsername) {
        NonClient nonClient = harness.data().newNonClient();
        return createNewFoCustomerWithCurrentAccountAndIbViaWso2(nonClient, bankerUsername);
    }

    public NewClientWithCurrentAccountInformation createNewFoCustomerWithCurrentAccountAndIbViaWso2(NonClient nonClient, String bankerUsername) {
        NewClientWithCurrentAccountInformation newFoClientInformation = createCifWithCurrentAccountApiSequence(bankerUsername, nonClient);
        createInternetBankFo(nonClient, newFoClientInformation.getCif());
        newFoClientInformation.setCredentials(harness.tasks().wso2().idm().getIbCredentialsByRC(nonClient.birthNumber()));
        return newFoClientInformation;
    }

    public NewClientWithCurrentAccountInformation createNewFoCustomerWithCurrentAccountViaWso2(String bankerUsername) {
        NonClient nonClient = harness.data().newNonClient();
        return createCifWithCurrentAccountApiSequence(bankerUsername, nonClient);
    }

    public NewClientWithCurrentAccountInformation createCifWithCurrentAccountApiSequence(String bankerUsername, NonClient nonClient) {
        String newCustomerCif = createNewFoCustomerApiSequence(bankerUsername, nonClient);
        NewClient newCustomer = new NewClient(nonClient, newCustomerCif);
        String currentAccountNumber = createCurrentAccountFo(bankerUsername, newCustomer);
        TestAutomationDbEndpoint ep = harness.getEndpoint(TestAutomationDbEndpoint.class);
        ep.insertCreatedClientInfo(newCustomerCif, nonClient.birthNumber(), null, getStartDateTime(), bankerUsername, "MWF", null);
        return new NewClientWithCurrentAccountInformation(nonClient, newCustomerCif, currentAccountNumber);
    }

    public String createCurrentAccountFo(String bankerUsername, NewClient newCustomer) {
        ClientTasks clientTasks = harness.tasks().wso2().client();
        AccountDetail accountDetail = new AccountDetail("1201004", "413");
        String currentAccountNumber = clientTasks.createAccountAndGetAccountNumber(newCustomer, accountDetail, bankerUsername);

        logger.info("New current account: " + currentAccountNumber);

        return currentAccountNumber;
    }

    public void setClientIncome(String cif, NonClient client) {
        ClientTasks tasks = harness.tasks().wso2().client();
        String payerPtKey = tasks.tryToFindPayer(client.employer().getIco());
        harness.log("Employer PayerPtKey: " + payerPtKey);
        if (payerPtKey == null || payerPtKey.isEmpty())
            throw new RuntimeException("Employer ico: " + client.employer().getIco() + " doesn't exist");
        tasks.setIncome(cif, client.employer().getPhoneNumber(), payerPtKey, client.netMonthlyIncome(), client.occupationEmploymentFromRaw());
    }

    private void createInternetBankFo(NonClient nonClient, String cif) {
        IbTasks ibTasks = harness.tasks().wso2().ib();
        checkCustomerAndCreateInUdebs(nonClient, cif);
        ibTasks.createIb(nonClient, cif);
        //ibTasks.generateLoginPasswordIb(cif); // Fail on Commhub whitelist. API call seems unnecessary.
        harness.withIlods().setSegment("AML_VERIFIED", "STRONG", nonClient.birthNumber(), "");
        logger.info("Internet bank was created for the client CIF " + cif);
    }

    private void createInternetBankFop(NonClient nonClient, String cif) {
        IbTasks ibTasks = harness.tasks().wso2().ib();
        checkFopCustomerAndCreateInUdebs(nonClient, cif);
        ibTasks.createIb(nonClient, cif);
        harness.withIlods().setSegment("AML_VERIFIED", "STRONG", nonClient.birthNumber(), "");
        logger.info("Internet bank was created for the client CIF " + cif);
    }

    public void createSmartBankFo(String cif) {
        IbTasks ibTasks = harness.tasks().wso2().ib();
        ibTasks.createSb(cif);
        logger.info("Smart bank was created for the client CIF " + cif);
    }

    private void checkCustomerAndCreateInUdebs(NonClient nonClient, String cif) {
        IbTasks ibTasks = harness.tasks().wso2().ib();
        if (!ibTasks.existClientInUdebs(cif)) {
            ibTasks.createClientInUdebs(nonClient, cif);

            logger.info("Client CIF " + cif + " was added to UDEBS db");
        }
    }

    private void checkFopCustomerAndCreateInUdebs(NonClient nonClient, String cif) {
        IbTasks ibTasks = harness.tasks().wso2().ib();
        if (!ibTasks.existClientInUdebs(cif)) {
            ibTasks.createFopClientInUdebs(nonClient, cif);

            logger.info("Client CIF " + cif + " was added to UDEBS db");
        }
    }

    private String createNewFoCustomerApiSequence(String bankerUsername, NonClient nonClient) {
        ClientTasks clientTasks = harness.tasks().wso2().client();

        String newCustomerCif = clientTasks.createCifFo(nonClient);
        clientTasks.setGdprConsent(newCustomerCif);
        clientTasks.setResidencyAddress(nonClient, newCustomerCif, bankerUsername);
        clientTasks.setCrAsTaxResidency(newCustomerCif);
        return newCustomerCif;
    }

    private String createNewFopCustomerApiSequence(String bankerUsername, NonClient nonClient) {
        ClientTasks clientTasks = harness.tasks().wso2().client();
        AccountDetail czAccountDetail = new AccountDetail("1202015", "470");
        AccountDetail eurAccountDetail = new AccountDetail("1229004", "48");

        String newCustomerCif = clientTasks.createCifFop(nonClient, bankerUsername);
        NewClient newCustomer = new NewClient(nonClient, newCustomerCif);
        String czAccount = clientTasks.createAccountAndGetAccountNumber(newCustomer, czAccountDetail, bankerUsername);
        String eurAccount = clientTasks.createAccountAndGetAccountNumber(newCustomer, eurAccountDetail, bankerUsername);
       // clientTasks.subsidyCzkAccount(czAccount, 10000);
       // clientTasks.subsidyEurAccount(eurAccount, 500);

        harness.tasks().wso2().comoda().setComodaData(nonClient.ico());
        clientTasks.setCommercialBankerToClient(nonClient.ico());
        return newCustomerCif;
    }

    public String getStartDateTime() {
        return DateUtils.getFormattedTodayDateTime("yyyy-MM-dd hh:mm:ss");
    }
}
