package cz.moneta.test.regression.commercial.smallbusiness.digital.backendtests;

import cz.moneta.test.dsl.Harness;
import cz.moneta.test.dsl.util.DateUtils;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.CrtAccountIcbRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.CrtAccountIcbResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.DltJuridicaAccountRolesRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.DltJuridicaFundOwnersComplete;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.DoCancelCurrentAccountRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.DoPrepareJuridicaIdentificationRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.DoSmeDepositProductOfferResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.DoStartJuridicaIdentificationRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetCurrentAccountRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetCurrentAccountResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetDepositAccForLegalRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetDepositAccForLegalResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetJuridicaIdentificationStateRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetJuridicaIdentificationStateResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetJuridicaRelatedPersonsDataRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetJuridicaRelatedPersonsDataResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.MWFIS3Request;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.SetJuridicaRelatedPersionDetailRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.SetJuridicaTotalAmountsRequest;
import cz.moneta.test.harness.annotations.JiraTestCase;
import cz.moneta.test.harness.annotations.TestCase;
import cz.moneta.test.harness.annotations.TestScenarioWithOrder;
import org.junit.jupiter.api.Order;

import java.math.BigDecimal;

import static cz.moneta.test.harness.annotations.Environment.TST1;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

@TestScenarioWithOrder(name = "Juridica identification happy path test.")
public class JuridicaIdentificationTest {

    private static final String CIF = "9070230246";

    @TestCase(name = "Create juridica account", environments = {TST1})
    @JiraTestCase(id = "SBD-T1189")
    @Order(1)
    public void createJuridicaAccount(Harness harness) {
        String accountNumber = createAccount(harness);
        harness.storeGlobal("SBD_ACC_JURIDICA", accountNumber);
        blockAccount(harness, accountNumber);
        checkAccount(harness, accountNumber);

        harness.log("SBD-T1189: Created juridica account: " + accountNumber);
    }

    @TestCase(name = "Juridica identification process", environments = {TST1})
    @JiraTestCase(id = "SBD-T1188")
    @Order(2)
    public void juridicaIdentificationAndUnidentification(Harness harness) throws InterruptedException {
        String accountNumber = harness.getGlobal("SBD_ACC_JURIDICA");
        harness.log("SBD-T1188: Running test on account: " + accountNumber);

        juridicaIdentificationHappyPath(harness, accountNumber);
    }

    @TestCase(name = "Juridica cancel account", environments = {TST1})
    @JiraTestCase(id = "SBD-T1191")
    @Order(3)
    public void cancelAccount(Harness harness) {
        String accountNumber = harness.getGlobal("SBD_ACC_JURIDICA");
        harness.log("SBD-T1191: Running test on account: " + accountNumber);

        cancelAccount(harness, accountNumber);
        checkAccountIsCanceled(harness, accountNumber);
    }

    private void juridicaIdentificationHappyPath(Harness harness, String accountNumber) throws InterruptedException {
        /*
        Udebs tables used in juridica process:
        UDEBSGE.ACCOUNTFUNDOWNER_SUGG_IDENT = AFOSI
        UDEBSGE.ACCOUNTFUNDOWNER = AFO
        UDEBSGE.ACCOUNTFUNDOWNER_SUGGESTION = AFOS
        */

        // identification
        doPrepareJuridicaIdentification(harness, accountNumber); // If AFO has records → create AFOSI records; else → create an empty AFOSI record.
        setJuridicaTotalAmountsDepositAmount(harness, accountNumber); // Save deposit amount do AFOSI
        setJuridicaRelatedPersonDetailShareOwner(harness, accountNumber); // Saves person shareholder as AFOS record
        setJuridicaTotalAmountsPaidAmount(harness, accountNumber); // Save paid amount do AFOSI
        setJuridicaRelatedPersonDetailShareCompetent(harness, accountNumber); // Saves person competent (authorized person) as AFOS record
        doStartWpsJuridicaIdentification(harness, accountNumber); // Starts identification workflow in WPS

        // check identification
        checkIfIdentificationFinishedSuccessfully(harness, accountNumber);

        // unidentification
        deleteJuridicaAccountRoles(harness, accountNumber); // Remove AFOS record or set action to DEL
        deleteJuridicaFundOwners(harness, accountNumber); // Remove AFOSI record and AFOS records

        // check unidentification
        checkIfDeletedInUdebs(harness, accountNumber);
    }

    private void checkAccountIsCanceled(Harness harness, String accountNumber) {
        GetDepositAccForLegalResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/payments.cluster/IPE/GET_DEPOSIT_ACC_FOR_LEGAL/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetDepositAccForLegalRequest.builder()
                        .cif(CIF)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetDepositAccForLegalResponse.class);

        // account is not held under CIF
        assertFalse(response.getData().stream()
                .anyMatch(acc -> accountNumber.equals(acc.getCisloUctu())));
    }

    private void cancelAccount(Harness harness, String accountNumber) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/payments.cluster/IPE/DO_CANCEL_CURRENT_ACCOUNT/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(DoCancelCurrentAccountRequest.builder()
                        .cisloUctu(accountNumber)
                        .cisloUctuPrijemceKodBanky("0800")
                        .branchId("86007040")
                        .cisloCostCentra(3704L)
                        .produktKod("4401001")
                        .cisloUctuPrijemceVS("236634202")
                        .sdeleniID(10L)
                        .sso("543829528")
                        .poplatekZaZruseni((double) 0)
                        .sdeleniText("Doplacení úvěru")
                        .channelId("UFO")
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void checkAccount(Harness harness, String accountNumber) {
        GetCurrentAccountResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/payments.cluster/GET_CURRENT_ACCOUNT/001")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetCurrentAccountRequest.builder()
                        .cisloUctu(accountNumber)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetCurrentAccountResponse.class);

        assertEquals("3", response.getStavUctu()); // 3 - Uzavřený pro zápis podle HCisStavUctu
    }

    private void blockAccount(Harness harness, String accountNumber) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/mwf.legacy/HUB/MWFIS3/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(MWFIS3Request.builder()
                        .currentAccount(accountNumber)
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private String createAccount(Harness harness) {
        CrtAccountIcbResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/deposit.cluster/IPE/CRT_ACCOUNT_ICB/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(CrtAccountIcbRequest.builder()
                        .cif(CIF)
                        .produktKod("4401004")
                        .poplatkovyPlan("148")
                        .obchodniJmeno("ADVOKÁTNÍ KANCELÁŘ Kříženecký & partneři")
                        .aaAdresat("Advokátní úschova")
                        .pouzitaAA("1")
                        .primarniUrednik("GEBTSBM")
                        .postovniPoukazka("0")
                        .ulozPSCBezKontroly("Y")
                        .nuloveUroceni("0")
                        .distribuceVypisu("4")
                        .periodaVypisu("1")
                        .obchodniMistoKod("86007040")
                        .vypisNaKonciMesice(true)
                        .datumOtevreni(DateUtils.getTodayRawDateForWso2())
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(CrtAccountIcbResponse.class);

        return response.getCisloUctu();
    }

    private void doPrepareJuridicaIdentification(Harness harness, String accountNumber) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/CBL/DO_PREPARE_JURIDICA_IDENTIFICATION/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(DoPrepareJuridicaIdentificationRequest.builder()
                        .accountNumber(accountNumber)
                        .channelId("21")
                        .sso("212622644")
                        .clientIdentificationNumber("26033755")
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void setJuridicaRelatedPersonDetailShareOwner(Harness harness, String accountNumber) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/CBL/SET_JURIDICA_RELATED_PERSON_DETAIL/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(SetJuridicaRelatedPersionDetailRequest.builder()
                        .country("52")
                        .companyName(null)
                        .bankIban(null)
                        .addressHouseNumber("827")
                        .clientType("1")
                        .addressLandRegistryNumber("11")
                        .surname("Borec")
                        .action("ADD")
                        .bankAccountNumber(null)
                        .birthNumber("7807147590")
                        .instPtKey(null)
                        .email("michal.seibert@moneta.cz")
                        .addressCity("Praha")
                        .sharePercentage(null)
                        .addressCountry("52")
                        .addressZipCode("14800")
                        .companyIdentificationNumber(null)
                        .bankCode(null)
                        .suggestionId(null)
                        .accountNumber(accountNumber)
                        .birthDate("1978-07-14")
                        .shareAmount(BigDecimal.valueOf(222))
                        .addressStreet("Klatovská")
                        .phone("725005644")
                        .partyRole("SHARE_OWNER")
                        .name("Vasek")
                        .bankIdCode(null)
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void setJuridicaTotalAmountsDepositAmount(Harness harness, String accountNumber) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/CBL/SET_JURIDICA_TOTAL_AMOUNTS/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(SetJuridicaTotalAmountsRequest.builder()
                        .depositAmount(BigDecimal.valueOf(222))
                        .accountNumber(accountNumber)
                        .paidAmount(null)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(DoSmeDepositProductOfferResponse.class);
    }

    private void setJuridicaTotalAmountsPaidAmount(Harness harness, String accountNumber) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/CBL/SET_JURIDICA_TOTAL_AMOUNTS/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(SetJuridicaTotalAmountsRequest.builder()
                        .depositAmount(BigDecimal.valueOf(222))
                        .accountNumber(accountNumber)
                        .paidAmount(BigDecimal.valueOf(111))
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(DoSmeDepositProductOfferResponse.class);
    }

    private void setJuridicaRelatedPersonDetailShareCompetent(Harness harness, String accountNumber) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/CBL/SET_JURIDICA_RELATED_PERSON_DETAIL/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(SetJuridicaRelatedPersionDetailRequest.builder()
                        .country("52")
                        .companyName(null)
                        .bankIban(null)
                        .addressHouseNumber("187")
                        .clientType("1")
                        .addressLandRegistryNumber("7")
                        .surname("Filtros")
                        .action("ADD")
                        .bankAccountNumber("222-1111")
                        .birthNumber("7807147634")
                        .instPtKey(null)
                        .email("michal.seibert@moneta.cz")
                        .addressCity("Cheb")
                        .sharePercentage(null)
                        .addressCountry("52")
                        .addressZipCode("35002")
                        .companyIdentificationNumber(null)
                        .bankCode("0710")
                        .suggestionId(null)
                        .accountNumber(accountNumber)
                        .birthDate("1978-07-14")
                        .shareAmount(BigDecimal.valueOf(111))
                        .addressStreet("Šumavská")
                        .phone("725005644")
                        .partyRole("COMPETENT")
                        .name("Uwe")
                        .bankIdCode(null)
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void doStartWpsJuridicaIdentification(Harness harness, String accountNumber) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/CBL/DO_START_WPS_JURIDICA_IDENTIFICATION/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(DoStartJuridicaIdentificationRequest.builder()
                        .clientIdentificationFile(CIF)
                        .productClass(44)
                        .emptyClientEmailConfirmedFlag(0)
                        .accountNumber(accountNumber)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(DoSmeDepositProductOfferResponse.class);
    }

    private void checkIfIdentificationFinishedSuccessfully(Harness harness, String accountNumber) throws InterruptedException {
        Thread.sleep(30000); // waiting for WPS workflow finish
        GetJuridicaIdentificationStateResponse response = getJuridicaIdentificationState(harness, accountNumber);
        assertEquals("Identified", response.getIdentificationState());
    }

    private GetJuridicaIdentificationStateResponse getJuridicaIdentificationState(Harness harness, String accountNumber) {
        return harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/CBL/GET_JURIDICA_IDENTIFICATION_STATE/001")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetJuridicaIdentificationStateRequest.builder()
                        .accountNumber(accountNumber)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetJuridicaIdentificationStateResponse.class);
    }

    private void deleteJuridicaAccountRoles(Harness harness, String accountNumber) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/CBL/DLT_JURIDICA_ACCOUNT_ROLES/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(DltJuridicaAccountRolesRequest.builder()
                        .accountNumber(accountNumber)
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void deleteJuridicaFundOwners(Harness harness, String accountNumber) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/CBL/DLT_JURIDICA_FUND_OWNERS_COMPLETE/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(DltJuridicaFundOwnersComplete.builder()
                        .accountNumber(accountNumber)
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void checkIfDeletedInUdebs(Harness harness, String accountNumber) {
        GetJuridicaRelatedPersonsDataResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/CBL/GET_JURIDICA_RELATED_PERSONS_DATA/001")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetJuridicaRelatedPersonsDataRequest.builder()
                        .accountNumber(accountNumber)
                        .confirmFlag(1L)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetJuridicaRelatedPersonsDataResponse.class);

        assertTrue(response.getData().isEmpty());
    }
}
