package cz.moneta.test.harness.context;

import cz.moneta.test.harness.endpoints.Endpoint;
import cz.moneta.test.harness.support.data.Generator;
import cz.moneta.test.harness.support.data.GeneratorType;
import cz.moneta.test.harness.support.util.Level;

import java.util.Set;
import java.util.function.Supplier;

public interface StoreAccessor extends ConfigAccessor {

    /**
     * This method is used to get a direct access to an application or system endpoint. Typical usage is:
     * <br/>
     * <pre>{@code
     * public Login openLoginPage() {
     *     LoansBranchEndpoint endpoint = harness.getEndpoint(LoansBranchEndpoint.class);
     *     endpoint.openApplication();
     *     return Builders.newWebFlowBuilder(Login.class, endpoint, harness);
     * }
     * }</pre>
     *
     * Subsequent calls to this method within the same test class return the same instance of the endpoint.
     * <br/>
     * <i><b>NOTE</b></i> calling this method with different arguments results in multiple instance of the same endpoint
     * being instantiated
     *
     * @param endpointClass desired endpoint class
     * @param args arguments to be passed to the endpoint implementation constructor
     * @return returns an existing or - in case has not been instantiated - new instance of the endpoint
     */
    <E extends Endpoint> E getEndpoint(Class<E> endpointClass, Object... args);

    void closeEndpoint(Endpoint endpoint);

    <E extends Endpoint> Set<E> getActiveEndpoints();

    /**
     * Returns a value previously stored via the {@link StoreAccessor#store} method within the same test class.
     * <pre>{@code
     * harness.withUfoBanka()
     *      .openLoginPage()
     *      .then(bankaTasks.login().withCredentialsAndTurnOffSignpad(credentials))
     *      .fillSearchTerm(harness.get(HKO001_MainClientPage.CLIENT_CIF_STORE_KEY))
     *      .clickSearchByCif()
     * }</pre>
     */
    <T> T get(String key);

    <T> T get(String key, boolean nullEnabled);

    /**
     * Stores the given value with the key. The key-value pair is kept for the duration of the test class execution.
     */
    void store(String key, Object value);

    /**
     * Works much like {@link StoreAccessor#get} only it gets values from the persistent global storage that is kept
     * for the duration of the execution of all test classes
     *
     * @param key key
     * @param orCreate if the key-value pair is not found, the supplier instantiates and stores the value before
     *                 returning it
     */
    <T> T getGlobal(String key, Supplier<T> orCreate);

    /**
     * Works much like {@link StoreAccessor#get} only it gets values from the persistent global storage that is kept
     * for the duration of the execution of all test classes
     */
    <T> T getGlobal(String key);

    /**
     * Works much like {@link StoreAccessor#store} only it stores values in the persistent global storage that is kept
     * for the duration of the execution of all test classes
     */
    void storeGlobal(String key, Object value);

    void storeGlobal(String key, Supplier orCreate);

    void log(String template, Object... args);

    void log(Level level, String template, Object... args);

    /**
     * Generates a value.
     * <p/>
     * Typical usage:
     * <pre>{@code
     * String ico = harness.generate(GeneratorType.ICO);
     * }</pre>

     * @param type typ of the generator to be used
     * @param params parameters to be passed to the {@link Generator#generate} method
     */
    <T> T generate(GeneratorType type, Object... params);
}
