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

import cz.moneta.test.dsl.Harness;
import cz.moneta.test.harness.exception.HarnessException;
import lombok.experimental.UtilityClass;

import java.util.function.Predicate;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@UtilityClass
public class WaitForApiUtils {
    public <T> void waitForApi(Harness harness, WaitForApiRequest<T> req) throws InterruptedException {
        int attempts = Math.max(1, req.getTimeoutSeconds() / req.getIntervalSeconds());
        T lastResponse = null;

        for (int i = 0; i < attempts; i++) {
            lastResponse = harness.tasks().wso2().restRequest()
                    .prepareRequestFromUfo(req.getPath())
                    .withHeader("Content-Type", "application/json")
                    .withPojoPayload(req.getRequestPojo())
                    .post()
                    .andAssertStatus(200)
                    .mapResponseIntoObject(req.getResponseClass());

            harness.log(String.format("%s: waitForApi attempt %d path=%s response=%s", req.getTestCaseId(), i + 1, req.getPath(), lastResponse));

            if (testSuccessPredicate(req.getSuccessPredicate(), lastResponse)) {
                return;
            }

            testFailurePredicate(lastResponse, req);

            Thread.sleep(req.getIntervalSeconds() * 1000L);
        }

        throw new AssertionError(String.format("%s: Timeout waiting for success predicate on path=%s, lastResponse=%s", req.getTestCaseId(), req.getPath(), lastResponse
        ));
    }

    private static <T> boolean testSuccessPredicate(Predicate<T> successPredicate, T response) {
        assertNotNull(successPredicate);
        return successPredicate.test(response);
    }

    private static <T> void testFailurePredicate(T response, WaitForApiRequest<T> req) {
        Predicate<T> failurePredicate = req.getFailurePredicate();

        if (failurePredicate == null) {
            return;
        }

        if (failurePredicate.test(response)) {
            throw new HarnessException("Wait aborted: failure condition matched for path=" + req.getPath()
                    + ", request=" + req.getRequestPojo()
                    + ", lastResponse=" + response + ".");
        }
    }
}
