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

import cz.moneta.test.dsl.Harness;
import cz.moneta.test.harness.support.auth.Credentials;
import cz.moneta.test.harness.support.rest.RawRestRequest;

import java.util.List;
import java.util.function.Predicate;

public class IdmTasks {

    private final Harness harness;

    private static final String GET_DETAIL_PAYLOAD = "{\n" +
            "\"passwordType\": \"IB\",\n" +
            "\"resetPassword\": true,\n" +
            "%s" +
            "}";

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

    /**
     * Get user credentials to IB.
     * Password will be reset by calling this method.
     *
     * @param birthNumber client's birthnumber
     * @return returns Credentials object with username and password for IB
     */
    public Credentials getIbCredentialsByRC(String birthNumber) {
        String entityId = getEntityIdByRC(birthNumber);
        return resetIbUserPasswordByEntityId(entityId);
    }

    /**
     * Get user credentials to IB.
     * Password will be reset by calling this method.
     *
     * @param ico client's ico
     * @return returns Credentials object with username and password for IB
     */
    public Credentials getIbCredentialsByIco(String ico) {
        String cif = getCifByIco(ico);
        String username = getUserNameForIcoByCif(cif);
        return resetIbUserPasswordByUsername(username);
    }

    /**
     * Resets IB client's password
     *
     * @param username IB client username
     * @return returns Credentials object with username and new password for IB
     */
    public Credentials resetIbUserPasswordByUsername(String username) {
        return resetIbUserPassword(String.format(GET_DETAIL_PAYLOAD, "\"username\": \"" + username + "\"\n"));
    }

    /**
     * Resets IB client's password
     *
     * @param entityId IB client entityId
     * @return returns Credentials object with username and new password for IB
     */
    public Credentials resetIbUserPasswordByEntityId(String entityId) {
        return resetIbUserPassword(String.format(GET_DETAIL_PAYLOAD, "\"entityId\": \"" + entityId + "\"\n"));
    }

    private Credentials resetIbUserPassword(String requestBody) {
        String bearerToken = harness.tasks().wso2().authorization().getToken("DigitalchannelsSB_CBL");

        RawRestRequest.Response response = harness.withWso2()
                .prepareRequest()
                .withPath("/t/digitalchannels.sb/idm/1.0/password/get-detail")
                .withHeader("Authorization", bearerToken)
                .withHeader("Content-Type", "application/json")
                .withHeader("activityId", harness.tasks().wso2().restRequest().getRandomId())
                .withHeader("requestId", harness.tasks().wso2().restRequest().getRandomId())
                .withPayload(requestBody)
                .post()
                .andAssertStatus(200)
                .andAssertFieldValue("passwordStatus", "ENABLED");
        return new Credentials(response.extract("username").asText(), response.extract("password").asText());
    }

    private String getEntityIdByRC(String birthNumber) {
        return harness.tasks().wso2().restRequest().prepareEmptyRequestFromCbl("t/digitalchannels.sb/GET_EM_ENTITIES_CONTEXTS_LIST/001")
                .addField("BIRTH_NUMBER", birthNumber)
                .post()
                .andAssertStatus(200)
                .extract("RS_DATA[0].ENTITY_ID")
                .asText();
    }

    private String getCifByIco(String ico) {
        return harness.tasks().wso2().restRequest().prepareEmptyRequestFromCbl("/t/data.cluster/GET_INST_PT_KEY/001")
                .addField("ICO_NUM_IN", ico)
                .addField("SRC_SYS_ID", "ICB0")
                .post()
                .andAssertStatus(200)
                .andAssertPresent("RS_1[0].CIF")
                .extract("RS_1[0].CIF")
                .asText();
    }

    private String getUserNameForIcoByCif(String cif) {
        // Get contexts list
        GetEmCliContextsListResponse response = harness.tasks().wso2().restRequest().prepareEmptyRequestFromCbl( "/t/digitalchannels.sb/GET_EM_CLI_CONTEXTS_LIST/001")
                .addField("CIF", cif)
                .post()
                .andAssertStatus(200)
                .mapResponseIntoObject(GetEmCliContextsListResponse.class);

        // Filter unneeded records
        List<GetEmCliContextsListResponse.RS_DATA> filteredList = response.RS_DATA.stream()
                .filter(u -> u.CONTEXT_ROLES != null)
                .filter(u -> u.LOGIN_NAME != null)
                .toList();

        // Predicates for filter main account
        List<Predicate<GetEmCliContextsListResponse.RS_DATA>> roleConditions = List.of(
                u -> u.CONTEXT_ROLES.equals("10099"),
                u -> u.CONTEXT_ROLES.contains(","),
                u -> u.CONTEXT_ROLES.contains("20001"),
                u -> true
        );

        // Filter main account
        GetEmCliContextsListResponse.RS_DATA mainUserData = roleConditions.stream()
                    .flatMap(conditions -> filteredList.stream().filter(conditions).limit(1))
                    .findFirst()
                    .orElseThrow(() -> new IllegalStateException("No IB access found!"));

        return mainUserData.LOGIN_NAME;
    }
}