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

import cz.moneta.test.dsl.Harness;
import cz.moneta.test.dsl.util.DateUtils;
import cz.moneta.test.dsl.util.TestUtils;
import cz.moneta.test.dsl.util.data.account.AccountDetail;
import cz.moneta.test.dsl.util.data.client.Address;
import cz.moneta.test.dsl.util.data.client.Gender;
import cz.moneta.test.dsl.util.data.client.NewClient;
import cz.moneta.test.dsl.util.data.client.NonClient;
import cz.moneta.test.harness.support.rest.RawRestRequest;
import org.jooq.Record;
import org.jooq.Result;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Date;

import static cz.moneta.test.dsl.util.data.ihub.IHubConstants.*;

public class ClientTasks {

    private final Harness harness;

    private final String GEBTHA1_SSO = "920181015";

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

    /**
     * Call CRT_PERSON_CIF to create client CIF.
     * <p>
     * Used as a part of create new customer process Exists class.
     * </p>
     * <p>
     * For local use it needs access to WSO2
     * </p>
     *
     * @param client - customer data - instance of NonClient
     */
    public String createCifFo(NonClient client) {
        return harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/customer.cluster/CRT_PERSON_CIF/001")
                .addField("RodneCislo", client.birthNumber())
                .addField("DatumNarozeni", DateUtils.convertRawDateForWso2(TestUtils.dateFromString(client.birthDate(), "d.M.yyyy"))) //YYYY-MM-DD
                .addField("DatumExpiraceKontaktnichUdaju", DateUtils.convertRawDateForWso2(DateUtils.getRawTodayDateIncrementedByDays(730)))
                .addField("PlatnostOPdo", DateUtils.convertRawDateForWso2(client.idCardExpiredRaw()))
                .addField("DatumPotvrzeniPrijmu", DateUtils.convertRawDateForWso2(client.dateOfIssueConfirmationOfReceipt()))
                .addField("DatumZalozeniCIFu", DateUtils.convertRawDateForWso2(DateUtils.getTodayRawDate()))
                .addField("SerieACisloOP", client.idCardNumber())
                .addField("CisloPasu", client.passportId())
                .addField("PlatnostPasuDo", DateUtils.convertRawDateForWso2(client.passportExpiryDateRaw()))
                .addField("PasStatVydal", CZECH_REPUBLIC_CODE)
                .addField("OPStatVydal", CZECH_REPUBLIC_CODE)
                .addField("PrvniJmeno", client.firstName())
                .addField("Prijmeni", client.lastName())
                .addField("CO", client.residencyAddress().getOrientationNumber())
                .addField("CP", client.residencyAddress().getDescriptiveNumber())
                .addField("Ulice", client.residencyAddress().getStreet())
                .addField("Obec", client.residencyAddress().getCity())
                .addField("KlasifikaceKlienta", "0")
                .addField("KodObchodnihoMista", MMB_BBC_OM)
                .addField("MistoNarozeni", client.placeOfBirth())
                .addField("PSC", client.residencyAddress().getZip())
                .addField("NazevZamestnavatele", client.employer().getName())
                .addField("ZAMICO", client.employer().getIco())
                .addField("ZAMUlice", client.employer().getAddress().getStreet())
                .addField("ZAMCO", client.employer().getAddress().getOrientationNumber())
                .addField("ZAMCP", client.employer().getAddress().getDescriptiveNumber())
                .addField("ZAMPSC", client.employer().getAddress().getZip())
                .addField("ZamObec", client.employer().getAddress().getCity())
                .addField("PlatnostKontaktnichUdaju", "1")
                .addField("TelefonMobilni", "420" + client.mobileNumber())
                .addField("DatumNastehovani", DateUtils.convertRawDateForWso2(client.currentAddressSinceRaw()))
                .addField("RodinnyStav", client.maritalStatus().getHCisValue())
                .addField("Pohlavi", client.gender() == Gender.MAN ? "1" : "2")
                .addField("ZamestnanOd", DateUtils.convertRawDateForWso2(client.occupationEmploymentFromRaw()))
                .addField("CistyMesicniPrijem", (double) client.netMonthlyIncomeInThousands())
                .addField("PocetVyzivovanychDeti", Long.valueOf(client.dependants()))
                .addField("TelefonDomu", "420" + client.fixPhoneNumberHome())
                .addField("TelefonZamestnani", "420" + client.employer().getPhoneNumber())
                .addField("NejvyssiDosazeneVzdelani", "4")
                .addField("EkonomickySektor", "44")
                .addField("DruhPrijmuKlienta", client.occupationStatus().getHCisValue())
                .addField("DruhBydleni", client.accommodationType().getHCisValue())
                .addField("PlatnostKontaktnichUdaju", "1")
                .addField("SocialneEkonomickaSkupina", "1")
                .addField("ZkraceneJmeno", "ZkrJm")
                .addField("TypKlienta", "1")
                .addField("Zeme", CZECH_REPUBLIC_CODE)
                .addField("ZemeNarozeni", CZECH_REPUBLIC_CODE)
                .addField("StatniPrislusnost", CZECH_REPUBLIC_CODE)
                .addField("VztahKBance", client.relationshipToTheBank().getMetaCodeValue())
                .addField("EMail", client.email())
                .addField("NoEmailFlag", 0)
                .addField("Povolani", client.occupationType().getHCisValue())
                .addField("ZuzeneSJM", "10")
                .post()
                .andAssertStatus(200)
                .extract("CIF")
                .asText();
    }

    /**
     * Call SET_CUST_CONSENTS to set GDPR consent for client.
     * <p>
     * Used as a part of create new customer process Exists class.
     * </p>
     * <p>
     * For local use it needs access to WSO2
     * </p>
     *
     * @param cif - customer CIF
     */
    public void setGdprConsent(String cif) {
        harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/customer.cluster/SET_CUST_CONSENTS/001")
                .addField("ClientInstId", cif)
                .addField("ConsentSignTime", DateUtils.convertRawDateForWso2(new Date()))
                .addField("ConsentEmployeeId", GEBTHA1_SSO)
                .addField("ConsentBranchId", MMB_BBC_OM)
                .addField("ConsentSetId", "SET_CONCERN_CONSENTS")
                .addField("ConsType_MarketingByAllChannels", "1")
                .addField("ConsType_IdentityPapersCopy", "1")
                .addField("ConsType_CommBankSecretByUnsecured", "1")
                .addField("ClientType", "1")
                .addField("BusinessType", "GEMCB")
                .addField("ClientInstSysId", "ICB0")
                .addField("ConsentChannelId", "POS")
                .addField("ConsentMode", "SET")
                .post()
                .andAssertStatus(200);
    }

    /**
     * Call DO_SAVE_ADDRESS_ALL_SYSTEMS to set residency address for client.
     * <p>
     * Used as a part of create new customer process Exists class.
     * </p>
     * <p>
     * For local use it needs access to WSO2
     * </p>
     *
     * @param nonClient      - customer information (contains residencyAddress)
     * @param cif            - customer cif
     * @param bankerUsername - banker name to be set as sekundarniUrednik parameter
     */
    public void setResidencyAddress(NonClient nonClient, String cif, String bankerUsername) {
        Address residencyAddress = nonClient.residencyAddress();

        harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/customer.cluster/DO_SAVE_ADDRESS_ALL_SYSTEMS/001")
                .addField("CIF", cif)
                .addField("PSC", residencyAddress.getZip())
                .addField("Ulice", residencyAddress.getStreet())
                .addField("SekundarniUrednik", bankerUsername)
                .addField("Zeme", CZECH_REPUBLIC_CODE)
                .addField("Mesto", residencyAddress.getCity())
                .addField("SuperkontaktniAdresa_Flag", "1")
                .addField("RC", nonClient.birthNumber())
                .addField("Adresat", nonClient.firstName() + " " + nonClient.lastName())
                .addField("DistribucniKanal", "UFOBNK")
                .addField("BusinessUpdateDate", DateUtils.convertRawDateTimeForWso2(LocalDateTime.now()))
                .addField("CisloOrientacni", residencyAddress.getOrientationNumber())
                .addField("CisloPopisne", residencyAddress.getDescriptiveNumber())
                .post();
    }

    /**
     * Call SET_CUST_CRS_DATA to set Czech Republic as tax residency for client.
     * <p>
     * Used as a part of create new customer process Exists class.
     * </p>
     * <p>
     * For local use it needs access to WSO2
     * </p>
     *
     * @param cif - customer CIF
     */
    public void setCrAsTaxResidency(String cif) {
        harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/customer.cluster/SET_CUST_CRS_DATA/001")
                .addField("CIF", cif)
                .addField("ZakladniAtributyFlag", "0")
                .addField("ZemePobocekFlag", "0")
                .addField("ZemeDanoveRegistraceFlag", "1")
                .addField("ZemeCRSFlag", "0")
                .addField("Data", Arrays.asList(new Object()))
                .addField("Data[0]", "ITAX_RSDNC_CNTRY_CODE", CZECH_REPUBLIC_CODE)
                .post();
    }

    public String createCifFop(NonClient fop, String bankerUsername) {
        String shortenName = fop.fullName().substring(0, Math.min(fop.fullName().length(), 18));

        return harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/customer.cluster/CRT_COMMERCIAL_CUST/001")
                .addField("CP", fop.residencyAddress().getDescriptiveNumber())
                .addField("DatumExpiraceKontaktnichUdaju", DateUtils.convertRawDateForWso2(DateUtils.getRawTodayDateIncrementedByDays(730)))
                .addField("DatumPlatnostiOP", DateUtils.convertRawDateForWso2(fop.idCardExpiredRaw()))
                .addField("DatumPodnikaniOd", DateUtils.convertRawDateForWso2(fop.occupationEmploymentFromRaw()))
                .addField("DatumZalozeniCIFu", DateUtils.convertRawDateForWso2(TestUtils.getTodayAsDate()))
                .addField("EMail", fop.email())
                .addField("EkonomickySektor", "25")
                .addField("ICO", fop.ico())
                .addField("Jmeno", fop.firstName())
                .addField("KodObchodnihoMista", MMB_BUDEJOVICE_OM)
                .addField("OKEC", "022000")
                .addField("OROddil", "123")
                .addField("ORSoud", "1")
                .addField("ORVlozka", "123")
                .addField("ObchodniJmeno", fop.fullName())
                .addField("Obec", fop.residencyAddress().getCity())
                .addField("PSC", fop.residencyAddress().getZip())
                .addField("PobytCR", "1")
                .addField("Posta", fop.residencyAddress().getCity())
                .addField("PravniForma", "101")
                .addField("Prijmeni", fop.lastName())
                .addField("Rezidence", "1")
                .addField("RodneCislo", fop.birthNumber())
                .addField("SerieACisloOP", fop.idCardNumber())
                .addField("Ulice", fop.residencyAddress().getStreet())
                .addField("UlozPSCBezKontroly", "Y")
                .addField("Urednik", bankerUsername)
                .addField("Zeme", CZECH_REPUBLIC_CODE)
                .addField("ZkraceneJmeno", shortenName)
                .post()
                .andAssertStatus(200)
                .extract("CIF")
                .asText();
    }

    public String createAccountAndGetAccountNumber(NewClient newCustomer, AccountDetail accountDetail, String bankerUsername) {
        return createAccountAndGetAccountNumber(newCustomer.getCif(), newCustomer.getClientData().fullName(), accountDetail, bankerUsername);
    }

    public String createAccountAndGetAccountNumber(String cif, String name, AccountDetail accountDetail, String bankerUsername) {
        return harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/deposit.cluster/IPE/CRT_ACCOUNT_ICB/001")
                .addField("AAZeme", CZECH_REPUBLIC_CODE)
                .addField("CIF", cif)
                .addField("DatumOtevreni", DateUtils.convertRawDateForWso2(DateUtils.getTodayRawDate()))
                .addField("DistribuceVypisu", "3")
                .addField("ObchodniJmeno", name)
                .addField("ObchodniMistoAlternativni", MMB_BBC_OM)
                .addField("ObchodniMistoKod", MMB_BBC_OM)
                .addField("PeriodaVypisu", "2")
                .addField("PoplatkovyPlan", accountDetail.getFeePlan())
                .addField("PostovniPoukazka", "0")
                .addField("PouzitaAA", "1")
                .addField("PrimarniUrednik", bankerUsername)
                .addField("ProduktKod", accountDetail.getProductCode())
                .addField("VypisNaKonciMesice", false)
                .post()
                .andAssertStatus(200)
                .extract("CisloUctu")
                .asText();
    }

    public void subsidyCzkAccount(String accountNumber, double amount) {
        subsidyAccount(accountNumber, amount, "16621848", 0);
    }

    public void subsidyEurAccount(String accountNumber, double amount) {
        subsidyAccount(accountNumber, amount, "16621848", 23);
    }

    public void subsidyUsdAccount(String accountNumber, double amount) {
        subsidyAccount(accountNumber, amount, "16621848", 1);
    }

    public void subsidyAccount(String accountNumber, double amount, String internalAccNum, int currencyCode) {
        harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/payments.cluster/IPE/CRT_VERIFIED_TRANSACTION/001")
                .addField("CisloUctuInterni", internalAccNum)
                .addField("CastkaTransakce", amount)
                .addField("CisloUctuPrijemceInterni", accountNumber)
                .addField("KodMenyTransakce", currencyCode)
                .addField("SSO", GEBTHA1_SSO)
                .addField("branchId", MMB_BBC_OM)
                .addField("channelId", "UFO")
                .addField("KodBanky", "0600")
                .post()
                .andAssertStatus(201);
    }

    public RawRestRequest.Response findUnifiedClient(String ico) {
        return harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/customer.cluster/GET_CUST_UNIFIED/001")
                .addField("BusinessRequestor", "GEM")
                .addField("ICO", ico)
                .addField("IDZdrojovehoSystemu", "CMD")
                .addField("UcelDotazu", "1")
                .post()
                .andAssertStatus(200);
    }

    public void setCommercialBankerToClient(String ico) {
        Result<Record> records = harness.tasks().ods().findInstPt(ico, "CMD0");
        if (records.isNotEmpty()) {
            String instPtKey = records.getValue(0, "INST_PT_KEY").toString();
            harness.log("INST_PT_KEY: {}", instPtKey);
            harness.tasks().wso2().restRequest()
                    .prepareEmptyRequestFromUfo("/t/customer.cluster/customer-set-vip-relation-banker/v1")
                    .addField("DEL_FLAG", "0")
                    .addField("INST_PT_KEY", instPtKey)
                    .addField("PrivatniBankerSSO", "123060132")
                    .addField("SRC_SYS_ID", "SFC01")
                    .addField("TypVazby", "3")
                    .post()
                    .andAssertStatus(200);
        }
    }


    public void relationFoFop(String cifFo, String cifFop) {
        harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/payments.cluster/CRT_LNK_CUS_CUST/001")
                .addField("INCUST1", cifFo)
                .addField("INCUST2", cifFop)
                .addField("INREL1", "KLO")
                .addField("INREL2", "KLP")
                .post()
                .andAssertStatus(200);
    }

    public boolean existInOds(String birthNumber) {
        return 0 != harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/customer.cluster/GET_CUST_UNIFIED/001")
                .addField("Adresy_OutputAktualniFlag", "1")
                .addField("Adresy_OutputSysIDs", "ICB|VIS|HYP|CMD")
                .addField("BusinessRequestor", "GEMCB")
                .addField("IDZdrojovehoSystemu_OUTPUT", "ICB0")
                .addField("MaximalniPocetZaznamu", 50L)
                .addField("Priznak_BankovniTajemstvi", "1")
                .addField("Priznak_RozsirenyVystup", "1")
                .addField("RC", birthNumber)//8111117399 / 8703234815
                .addField("TypyOsobyFiltr", "1|2|5")
                .addField("UcelDotazu", "9")
                .post()
                .andAssertStatus(200)
                .extract("PocetNalezenychZaznamu").intValue();
    }

    public void calculateTotalExposurePerson(Long personId) {
        harness.tasks().wso2()
                .restRequest()
                .prepareEmptyRequestFromUfo("/t/risk.cluster/NAS/CALCULATE_TOT_EXP_006/001")
                .addField("ID_KLIENT", personId)
                .post()
                .andAssertStatus(200);
    }

    public void doClientEgovIdentityComplete(NonClient client, String cif, String addressRuianCode, String sso, String SrcSysId, String posId, String busCode) {
        String birthDate = DateUtils.convertRawDateForWso2(TestUtils.dateFromString(client.birthDate(), "d.M.yyyy"));
        harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/financial.crime/IPE/DO_CLIENT_EGOV_IDENTITY_COMPLETE/001")
                .addField("ADDRESS_RUIAN_CODE", addressRuianCode)
                .addField("BUS_CODE", busCode)
                .addField("CONTEXT", "ONLINE")
                .addField("POS_ID", posId)
                .addField("PROCESS", "FON")
                .addField("SEARCHED_BY_BIRTH_NO", "")
                .addField("SKIP_NAME_CONTROL_FLAG", "1")
                .addField("SRC_SYS_ID", SrcSysId)
                .addField("SSO", sso)
                .addField("UDEBS_ID", "")
                .addField("DOCUMENT_NUMBER", client.idCardNumber())
                .addField("DOCUMENT_TYPE", "98")
                .addField("DOC_PASSPORT_ISSUER", "")
                .addField("CLIENT_NATIONALITY", "52")
                .addField("CLIENT_FIRST_NAME", client.firstName())
                .addField("CLIENT_LAST_NAME", client.lastName())
                .addField("CLIENT_BIRTH_DATE", birthDate)
                .addField("CLIENT_BIRTH_NUMBER", client.birthNumber())
                .addField("CLIENT_BIRTH_PLACE", "")
                .addField("CLIENT_ID", cif)
                .post()
                .andAssertStatus(200)
                .andAssertPresent("STATUS")
                .andAssertFieldValue("STATUS", "SUCCESS");
    }

    public void setIncome(String cif, String payerPhoneNumber, String PayerPtKey, Integer clientMonthlyIncome, java.util.Date occupationEmploymentFromRaw) {
        harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/risk.cluster/PIM/SET_PRSN_INCOME_DATA_004/001/")
                .addField("PRSN_INST_SYS_ID", "ICB0")
                .addField("PAYEE_OCCUP_TP_ID", "22")
                .addField("PAYEE_EMPLMT_NOTICE_PER_FLAG", "0")
                .addField("INCOME_REL_KEY", -1)
                .addField("PAYEE_INCOME_TP_ID", "EMPLOYMENT_INCOME")
                .addField("PAYEE_INCOME_START_DATE", DateUtils.convertRawDateForWso2(occupationEmploymentFromRaw))
                .addField("PAYEE_INCOME_STAT_ID", "ACPTD_BY_CLNT")
                .addField("PAYEE_EMPLMT_TRIAL_PER_FLAG", "0")
                .addField("RS_INCOME_VALS", Arrays.asList(new Object(), new Object()))
                .addField("RS_INCOME_VALS[0]", "INCOME_CALCD_CURR_ID", "0")
                .addField("RS_INCOME_VALS[0]", "INCOME_CALCD_TP_ID", "SALARY_DEDUCTION_MNTHLY_AMT")
                .addField("RS_INCOME_VALS[0]", "INCOME_CALCD_VAL", "0")
                .addField("RS_INCOME_VALS[0]", "REASON_TEXT", null)
                .addField("RS_INCOME_VALS[1]", "INCOME_CALCD_CURR_ID", "0")
                .addField("RS_INCOME_VALS[1]", "INCOME_CALCD_TP_ID", "AVG_3_MNTH")
                .addField("RS_INCOME_VALS[1]", "INCOME_CALCD_VAL", clientMonthlyIncome)
                .addField("RS_INCOME_VALS[1]", "REASON_TEXT", null)
                .addField("PAYER_PT_KEY", PayerPtKey)
                .addField("INCOME_VALDN_TP_ID", "DECLARATION")
                .addField("PRSN_INST_ID", cif)
                .addField("PAYEE_INCOME_SUBTP_ID", "EMPLOYMENT_PER_INDEFINITE")
                .addField("INCOME_CHANNEL_ID", "POS")
                .addField("PAYER_BUS_PHONE_NUM", "420" + payerPhoneNumber)
                .addField("PAYEE_INCOME_CASH_FLAG", "0")
                .addField("INCOME_VALDN_LVL_ID", "BANKER")
                .post()
                .andAssertStatus(200);
    }

    public String tryToFindPayer(String ico) {
        return harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/risk.cluster/PIM/TRY_SEARCH_PAYER_LIST/001/")
                .addField("PAYER_BUS_IDENT_NUM", ico)
                .post()
                .andAssertStatus(200)
                .extract("RS_LIST[0].PAYER_PT_KEY")
                .asText();
    }

    public void setSecondBankerVerificationStateOk(String appleKey) {
        harness.tasks().wso2().restRequest()
                .prepareEmptyRequestFromUfo("/t/loans.cluster/NAS/SET_SECOND_BANKER_VERIF_STATE_RESULT_004/001")
                .addField("APP_KEY", appleKey)
                .addField("SECOND_BANKER_VERIF_REASON", "OK_DOC")
                .addField("SUBTASK_TYPE", "50")
                .post();
    }
}