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

import cz.moneta.test.dsl.Harness;
import cz.moneta.test.dsl.util.wso2.WaitForApiRequest;
import cz.moneta.test.dsl.util.wso2.WaitForApiUtils;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.AddEmContextRoleRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.ChgEmChnLimRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.CrtEmployeeRoleRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.CrtEmployeeRoleResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.CrtIbDispoAppRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.CrtIbDispoAppResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.DltEmCliContextsRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.DoStartPckgOpeningRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetAppIbDataRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetAppIbDataResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetDigiEdisponentListRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetDigiEdisponentListResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetEmCliContextsListRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetEmCliContextsListResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetProcessTasksRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetProcessTasksResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetProdOpenTasksRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetProdOpenTasksResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetSmePckgAppStateRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.GetSmePckgAppStateResponse;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.LockTaskRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.MWF9C6Request;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.MWF9C6Response;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.MWFEW4Request;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.MWFIT4Request;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.MWFIT4Response;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.MWFIU6Request;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.MWFIU6Response;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.SetEmContextRightsSimpleRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.SetEmContextStatusRequest;
import cz.moneta.test.dsl.wso2.objects.smallbusiness.SetProdOpenTaskRequest;
import cz.moneta.test.dsl.wso2.objects.traininggov.DoDepersCustTestRequest;
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.exception.HarnessException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Order;

import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static cz.moneta.test.harness.annotations.Environment.TST1;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@TestScenarioWithOrder(name = "Edisponent onboarding happy path test.")
public class EdisponentOnboardingTest {

    private static final String CIF = "9070230381";
    private static final List<String> DISPO_NON_ACTIVE_STATES = List.of("CANCELED", "INACTIVE");
    private static final String BIRTH_NUMBER = "7801017708";
    private static final List<String> DEPERSONALISATION_SYSTEMS = List.of("DGE0", "NAS0", "UDB0");

    @TestCase(name = "Onboard edisponent", environments = {TST1})
    @JiraTestCase(id = "SBD-T1193")
    @Order(1)
    public void edisponentOnboarding(Harness harness) throws InterruptedException {
        // prepare
        cleanDisponentsOnCif(harness);

        // onboarding
        Long appKey = createDisponentApplication(harness); // creating application in NAS
        Long prodPackageKey = createProdPackage(harness, appKey); // creating product package in ODS
        moveWpsToApproval(harness, appKey); // start risk approving and approval workflow in WPS
        waitUntilApplicationApproved(harness, prodPackageKey); //  waiting until the approving workflow in WPS reaches the approved state
        createBankerSignRole(harness, appKey); // create banker sing role in application
        startPackageOpening(harness, prodPackageKey); // start product opening workflow in WPS
        String wfId = getOpeningWorkFlowId(harness, appKey);
        Thread.sleep(5000L);
        continueOpening(harness, prodPackageKey); // notify WPS to continue opening (WPS waiting for human task)
        waitUntilContractPrinted(harness, prodPackageKey); // waiting until the opening workflow in WPS reaches the contract printed state
        startDisbursing(harness, wfId); // notify WPS to start disbursing - DO_MOVE_STATE
        waitUntilDisbursed(harness, prodPackageKey); // waiting until the opening workflow in WPS reaches the contract disbursed state
        GetAppIbDataResponse ibData = getAppIbData(harness, appKey);
        setEdisponentContextStatus(harness, ibData); // setting active statues on edisponent rights to entitlement model
        setEdisponentContextRole(harness, ibData); // setting edisponent role to entitlement model
        setEdisponentContextRights(harness, ibData); // setting set of rights to entitlement model
        Long userId = getDispomodelUserId(harness, ibData);
        setEdisponentLimits(harness, ibData, userId); // setting payment limits to entitlement model

        // check
        checkEdisponentContext(harness);
        harness.log("SBD-T1193: Edisponent onboarding flow finished successfully. appKey=" + appKey + ", prodPackageKey=" + prodPackageKey);
    }

    @TestCase(name = "Cancel edisponent rights", environments = {TST1})
    @JiraTestCase(id = "SBD-T1194")
    @Order(2)
    public void cancelEdisponentRights(Harness harness) {
        List<Long> contextIds = getClientContexts(harness);
        assertEquals(1L, contextIds.size()); // only one edisponent should exist

        deleteEdisponents(harness, contextIds);
        noEdisponentShouldExist(harness);
        harness.log("SBD-T1194: Edisponent cancel flow finished successfully.");
    }

    @AfterAll
    public void depersonalizeEdisponent(Harness harness) {
        DoDepersCustTestRequest request = DoDepersCustTestRequest.builder()
                .rcNum(BIRTH_NUMBER)
                .rsData(DEPERSONALISATION_SYSTEMS.stream()
                        .map(id -> DoDepersCustTestRequest.Rs1.builder()
                                .srcSysIdIn(id)
                                .build())
                        .collect(Collectors.toList()))
                .build();

        harness.tasks().wso2().depersonalization().depersonalizeClient(request);
    }

    private void checkEdisponentContext(Harness harness) {
        GetDigiEdisponentListResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/get-digi-edisponent-list/v1/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetDigiEdisponentListRequest.builder()
                        .cif(CIF)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetDigiEdisponentListResponse.class);

        Integer countOfContexts = countOfActiveContexts(response);

        assertEquals(1, countOfContexts);

        GetDigiEdisponentListResponse.Person activeContext = response.getPersons()
                .stream()
                .filter(p -> !DISPO_NON_ACTIVE_STATES.contains(p.getDispoEmStatus()))
                .findFirst()
                .orElseThrow(() -> new NoSuchElementException("No active context"));

        assertEquals("ACTIVE", activeContext.getDispoEmStatus());
        assertEquals("Lumír", activeContext.getDispoFirstName());
        assertEquals("Mika", activeContext.getDispoLastName());
    }

    private Integer countOfActiveContexts(GetDigiEdisponentListResponse contexts) {
        return contexts.getPersons().stream()
                .filter(p -> !DISPO_NON_ACTIVE_STATES.contains(p.getDispoEmStatus()))
                .toList().size();
    }

    private Long getDispomodelUserId(Harness harness, GetAppIbDataResponse ibData) {
        GetEmCliContextsListResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/digitalchannels.sb/GET_EM_CLI_CONTEXTS_LIST/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetEmCliContextsListRequest.builder()
                        .cif(CIF)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetEmCliContextsListResponse.class);

        return response.getRsData().stream()
                .filter(d -> d.getContextId().equals(ibData.getDigiContextId()))
                .map(GetEmCliContextsListResponse.RsData::getUserId)
                .findFirst()
                .orElseThrow(() -> new HarnessException("UserId not found."));
    }

    private void setEdisponentLimits(Harness harness, GetAppIbDataResponse ibData, Long userId) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/digitalchannels.sb/CHG_EM_CHN_LIM/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(ChgEmChnLimRequest.builder()
                        .contextId(ibData.getDigiContextId())
                        .entityId(ibData.getDigiEntityId())
                        .cif(CIF)
                        .monthLimit("0")
                        .channel("3401001")
                        .dayLimit("1")
                        .weekLimit("0")
                        .dayLimitValue(1111D)
                        .userId(userId)
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void setEdisponentContextRights(Harness harness, GetAppIbDataResponse ibData) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/digitalchannels.sb/SET_EM_CONTEXT_RIGHTS_SIMPLE/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(SetEmContextRightsSimpleRequest.builder()
                        .contextId(ibData.getDigiContextId())
                        .templateId(2L)
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void setEdisponentContextRole(Harness harness, GetAppIbDataResponse ibData) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/digitalchannels.sb/CBL/ADD_EM_CONTEXT_ROLE/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(AddEmContextRoleRequest.builder()
                        .contextId(ibData.getDigiContextId())
                        .roleId(20001L)
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void setEdisponentContextStatus(Harness harness, GetAppIbDataResponse ibData) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/digitalchannels.sb/SET_EM_CONTEXT_STATUS/001")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(SetEmContextStatusRequest.builder()
                        .contextId(ibData.getDigiContextId())
                        .status("ACTIVE")
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private GetAppIbDataResponse getAppIbData(Harness harness, Long appKey) {
        return harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/digitalchannels.ib/NAS/GET_APP_IB_DATA/001")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetAppIbDataRequest.builder()
                        .appKey(appKey)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetAppIbDataResponse.class);
    }

    private void noEdisponentShouldExist(Harness harness) {
        GetDigiEdisponentListResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/get-digi-edisponent-list/v1/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetDigiEdisponentListRequest.builder()
                        .cif(CIF)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetDigiEdisponentListResponse.class);

        Long countOfUncancelledAccounts = response.getPersons().stream()
                .map(GetDigiEdisponentListResponse.Person::getDispoEmStatus)
                .filter(Objects::nonNull)
                .filter(status -> !DISPO_NON_ACTIVE_STATES.contains((status)))
                .count();

        assertEquals(0, countOfUncancelledAccounts);
    }

    private List<Long> getClientContexts(Harness harness) {
        GetDigiEdisponentListResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/get-digi-edisponent-list/v1/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetDigiEdisponentListRequest.builder()
                        .cif(CIF)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetDigiEdisponentListResponse.class);

        return response.getPersons().stream()
                .filter(c -> !DISPO_NON_ACTIVE_STATES.contains(c.getDispoEmStatus()))
                .map(GetDigiEdisponentListResponse.Person::getDispoEmContextId)
                .filter(Objects::nonNull)
                .toList();
    }

    private void cleanDisponentsOnCif(Harness harness) {
        List<Long> contextIds = getClientContexts(harness);
        if (!contextIds.isEmpty()) {
            deleteEdisponents(harness, contextIds);
        }
    }

    private void deleteEdisponents(Harness harness, List<Long> contextIds) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/digitalchannels.sb/DLT_EM_CLI_CONTEXTS/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(DltEmCliContextsRequest.builder()
                        .cif(CIF)
                        .fee("0")
                        .rsData(contextIds.stream()
                                .map(c -> DltEmCliContextsRequest.RsData.builder()
                                        .contextId(c)
                                        .build())
                                .toList())
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void createBankerSignRole(Harness harness, Long appKey) {
        CrtEmployeeRoleResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/risk.cluster/NAS/CRT_EMPLOYEE_ROLE_004/001")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(CrtEmployeeRoleRequest.builder()
                        .appKey(appKey)
                        .ssoId("543829528")
                        .empProcessRoleId("17")
                        .empRoleId("3")
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(CrtEmployeeRoleResponse.class);

        assertNotNull(response.getEmpRoleKey());
        harness.log("SBD-T1193: CRT_EMPLOYEE_ROLE_004 returned employee sign role key=" + response.getEmpRoleKey());
    }

    private void waitUntilDisbursed(Harness harness, Long prodPackageKey) throws InterruptedException {
        Long disbursedStateId = 6L;
        Long failureStateId = 4L;

        Predicate<MWF9C6Response> isPrintedPredicate = resp -> resp != null && disbursedStateId.equals(resp.getWorkFlowState());
        Predicate<MWF9C6Response> isErrorPredicate = resp -> resp != null && failureStateId.equals(resp.getWorkFlowState());

        WaitForApiRequest<MWF9C6Response> req = WaitForApiRequest.<MWF9C6Response>builder()
                .responseClass(MWF9C6Response.class)
                .path("/t/mwf.legacy/HUB/MWF9C6/001/")
                .requestPojo(MWF9C6Request.builder()
                        .prodPackageKey(prodPackageKey)
                        .build())
                .successPredicate(isPrintedPredicate)
                .failurePredicate(isErrorPredicate)
                .timeoutSeconds(300)
                .intervalSeconds(30)
                .testCaseId("SBD-T1193")
                .build();

        WaitForApiUtils.waitForApi(harness, req);
    }

    // This method replicates /t/integration.gov/IPE/DO_MOVE_STATE/001/ but with faster response time. Originally UFO calls DO_MOVE_STATE.
    // Harness can't call this API due to hardcoded 10 second timeout limit.
    // Original request should be: DoMoveStateRequest.builder()
    //    .wfid(wfId)
    //    .bankersProfile("GEBTSBM")
    //    .contractSigningDate("2025-12-02T12:00:00.000+01:00")
    //    .build()
    private void startDisbursing(Harness harness, String wfId) throws InterruptedException {
        Thread.sleep(15000L);
        String tkiId = getTkiId(harness, wfId);
        lockTask(harness, tkiId);
        setProdOpenTask(harness, tkiId);
        Thread.sleep(15000L); // simulates MWFHH8 15s wait
    }

    private void setProdOpenTask(Harness harness, String tkiId) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromHub("/t/integration.gov/SET_PRODOPEN_TASK/001")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(SetProdOpenTaskRequest.builder()
                        .tkiid(tkiId)
                        .contractsigningdate("2025-12-02T12:00:00.000+01:00")
                        .bankersprofile("GEBTSBM")
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void lockTask(Harness harness, String tkiId) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromHub("/t/backoffice.cluster/LOCK_TASK/001")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(LockTaskRequest.builder()
                        .tkiid(tkiId)
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private String getTkiId(Harness harness, String wfId) {
        GetProdOpenTasksResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromHub("/t/integration.gov/GET_PRODOPEN_TASKS/001")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetProdOpenTasksRequest.builder()
                        .dataType1("STRING")
                        .itemFirst(0L)
                        .itemLast(5L)
                        .operator1("=")
                        .value1(wfId)
                        .globalOperator("AND")
                        .operand1("WFID")
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetProdOpenTasksResponse.class);

        String tkiId = response.getRsData().stream()
                .findFirst()
                .map(GetProdOpenTasksResponse.RsData::getTkiid)
                .orElseThrow(() -> new HarnessException("tkiId not found in GET_PRODOPEN_TASKS response."));

        assertNotNull(tkiId);
        harness.log("SBD-T1193: GET_PRODOPEN_TASKS returned tkiId=" + tkiId);
        return tkiId;
    }

    private String getOpeningWorkFlowId(Harness harness, Long appKey) {
        GetProcessTasksResponse response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/integration.gov/GET_PROCESS_TASKS/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(GetProcessTasksRequest.builder()
                        .applicationKey(appKey)
                        .cycleContext(1L)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetProcessTasksResponse.class);

        String wfId = response.getWfid();

        assertNotNull(wfId);
        harness.log("SBD-T1193: GET_PROCESS_TASKS returned wfId=" + wfId);
        return wfId;
    }

    private void waitUntilContractPrinted(Harness harness, Long prodPackageKey) throws InterruptedException {
        Long printedStateId = 3L;
        Long failureStateId = 4L;

        Predicate<MWF9C6Response> isPrintedPredicate = resp -> resp != null && printedStateId.equals(resp.getWorkFlowState());
        Predicate<MWF9C6Response> isFailurePredicate = resp -> resp != null && failureStateId.equals(resp.getWorkFlowState());

        WaitForApiRequest<MWF9C6Response> req = WaitForApiRequest.<MWF9C6Response>builder()
                .responseClass(MWF9C6Response.class)
                .path("/t/mwf.legacy/HUB/MWF9C6/001/")
                .requestPojo(MWF9C6Request.builder()
                        .prodPackageKey(prodPackageKey)
                        .build())
                .successPredicate(isPrintedPredicate)
                .failurePredicate(isFailurePredicate)
                .timeoutSeconds(300)
                .intervalSeconds(30)
                .testCaseId("SBD-T1193")
                .build();

        WaitForApiUtils.waitForApi(harness, req);
    }

    private void continueOpening(Harness harness, Long prodPackageKey) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/mwf.legacy/HUB/MWFIU6/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(MWFIU6Request.builder()
                        .branchId("86007040")
                        .cif(CIF)
                        .prodPackageKey(prodPackageKey)
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(MWFIU6Response.class);
    }

    private void startPackageOpening(Harness harness, Long prodPackageKey) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/integration.gov/IPE/DO_START_PCKG_OPENING/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(DoStartPckgOpeningRequest.builder()
                        .branchId("86007040")
                        .cif(CIF)
                        .completationChannel("POS")
                        .prodPackageKey(prodPackageKey)
                        .build()
                )
                .post()
                .andAssertStatus(200);
    }

    private Long createDisponentApplication(Harness harness) {
        CrtIbDispoAppResponse crtResponse = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/small.business/NAS/CRT_IB_DISPO_APP_002/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(CrtIbDispoAppRequest.builder()
                        .posId("86001340")
                        .channelId("POS")
                        .bankerSso("212626884")
                        .applicantCif(CIF)
                        .dispoBirthPlace("Praha")
                        .dispoRcNumber(BIRTH_NUMBER)
                        .dispoBirthCountryId("52")
                        .dispoBirthDate("1978-01-01")
                        .dispoResAddrStreetDescNo("2")
                        .dispoResAddrStreet("Na Kleovce")
                        .dispoResAddrCity("Praha 2")
                        .dispoResAddrZipcode("12000")
                        .dispoResAddrCountry("52")
                        .dispoResAddrPostOffice("Praha 2")
                        .dispoName("Lumír")
                        .dispoSurname("Mika")
                        .dispoIdCardNr("210354736")
                        .dispoGenderId("1")
                        .dispoIdCardCntryId("52")
                        .dispoIdCardExpDate("2028-11-20")
                        .dispoIdCardType("98")
                        .dispoPhonePin("420724612248")
                        .dispoEmail("ilods@moneta.cz")
                        .dispoCitizenship("52")
                        .dispoIdentityVerificationType("6")
                        .rs1(singletonList(CrtIbDispoAppRequest.Rs1.builder()
                                .dispoRole("6")
                                .build()))
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(CrtIbDispoAppResponse.class);

        Long appKey = crtResponse.getAppKey();
        harness.log("SBD-T1193: CRT_IB_DISPO_APP returned appKey=" + appKey);
        return appKey;
    }

    private Long createProdPackage(Harness harness, Long appKey) {
        MWFIT4Response mwfit4Response = harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/mwf.legacy/HUB/MWFIT4/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(MWFIT4Request.builder()
                        .data(singletonList(MWFIT4Request.DataItem.builder().rsAppkey(appKey).build()))
                        .prodPackageType("dispo_ib_creds")
                        .build())
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(MWFIT4Response.class);

        Long prodPackageKey = mwfit4Response.getProdPackageKey();
        harness.log("SBD-T1193: MWFIT4 returned prodPackageKey=" + prodPackageKey);
        return prodPackageKey;
    }

    private void moveWpsToApproval(Harness harness, Long appKey) {
        harness.tasks().wso2().restRequest()
                .prepareRequestFromUfo("/t/mwf.legacy/HUB/MWFEW4/001/")
                .withHeader("Content-Type", "application/json")
                .withPojoPayload(MWFEW4Request.builder()
                        .applKey(appKey)
                        .build())
                .post()
                .andAssertStatus(200);
    }

    private void waitUntilApplicationApproved(Harness harness, Long prodPackageKey) throws InterruptedException {
        String applicationIsApprovedState = "8";
        String applicationIsErrorState = "15";

        Predicate<GetSmePckgAppStateResponse> isApprovedPredicate = resp -> applicationIsApprovedState.equals(resp.getAggregatedState());
        Predicate<GetSmePckgAppStateResponse> isErrorPredicate = resp -> applicationIsErrorState.equals(resp.getAggregatedState());

        WaitForApiRequest<GetSmePckgAppStateResponse> req = WaitForApiRequest.<GetSmePckgAppStateResponse>builder()
                .responseClass(GetSmePckgAppStateResponse.class)
                .path("/t/small.business/NAS/GET_SME_PCKG_APP_STATE/001")
                .requestPojo(GetSmePckgAppStateRequest.builder()
                        .prodPckgKey(prodPackageKey)
                        .build())
                .successPredicate(isApprovedPredicate)
                .failurePredicate(isErrorPredicate)
                .testCaseId("SBD-T1193")
                .timeoutSeconds(300)
                .intervalSeconds(30)
                .build();

        WaitForApiUtils.waitForApi(harness, req);
    }
}

