package cz.moneta.test.dsl;

import cz.moneta.test.dsl.aresapi.AresApiBuilder;
import cz.moneta.test.dsl.auto.autoapi.AutoApiBuilder;
import cz.moneta.test.dsl.auto.smartauto.SmartAuto;
import cz.moneta.test.dsl.auto.smartauto.setman.SmartAutoSetman;
import cz.moneta.test.dsl.broadcom.Broadcom;
import cz.moneta.test.dsl.brokerportal.BrokerPortal;
import cz.moneta.test.dsl.caapi.CaApiBuilder;
import cz.moneta.test.dsl.cagw.CaGw;
import cz.moneta.test.dsl.cashman.Cashman;
import cz.moneta.test.dsl.cebia.Cebia;
import cz.moneta.test.dsl.demo.Spirits;
import cz.moneta.test.dsl.demo.web.DemoWebChrome;
import cz.moneta.test.dsl.demo.web.DemoWebEdge;
import cz.moneta.test.dsl.dmbsib.DmbsIb;
import cz.moneta.test.dsl.elastic.ElasticApiBuilder;
import cz.moneta.test.dsl.exevido.Exevido;
import cz.moneta.test.dsl.finanso.Finanso;
import cz.moneta.test.dsl.forte.Forte;
import cz.moneta.test.dsl.fortelight.ForteLight;
import cz.moneta.test.dsl.greenscreen.GreenScreen;
import cz.moneta.test.dsl.hypos.Hypos;
import cz.moneta.test.dsl.ib.Ib;
import cz.moneta.test.dsl.payment_engine_mq.PaeMqBuilder;
import cz.moneta.test.dsl.ilods.Ilods;
import cz.moneta.test.dsl.imq.ImqFirstVision;
import cz.moneta.test.dsl.kafka.Kafka;
import cz.moneta.test.dsl.kasanova.Kasanova;
import cz.moneta.test.dsl.mobile.smartbanking.home.Sb;
import cz.moneta.test.dsl.monetaapiportal.MonetaApiPortal;
import cz.moneta.test.dsl.monetaportal.MonetaPortal;
import cz.moneta.test.dsl.mwf.IHub;
import cz.moneta.test.dsl.newib.NewIb;
import cz.moneta.test.dsl.oauth2.web.Oauth2Web;
import cz.moneta.test.dsl.openapi.OpenApiBuilder;
import cz.moneta.test.dsl.payment_engine.PaymentEngine;
import cz.moneta.test.dsl.refinanso.Refinanso;
import cz.moneta.test.dsl.salesforce.SalesForce;
import cz.moneta.test.dsl.salesforceapi.SalesForceApiBuilder;
import cz.moneta.test.dsl.szrmock.SzrMockBuilder;
import cz.moneta.test.dsl.testautomationpage.TestAutomationPage;
import cz.moneta.test.dsl.udebs.Udebs;
import cz.moneta.test.dsl.ufo.Ufo;
import cz.moneta.test.dsl.util.data.*;
import cz.moneta.test.dsl.util.data.generators.*;
import cz.moneta.test.dsl.util.task.Tasks;
import cz.moneta.test.dsl.util.task.dataprepare.DataPrepareTasks;
import cz.moneta.test.dsl.wso2.MockServer;
import cz.moneta.test.dsl.wso2.Wso2;
import cz.moneta.test.harness.annotations.TestContext;
import cz.moneta.test.harness.context.BaseStoreAccessor;
import cz.moneta.test.harness.support.data.GeneratorType;
import org.junit.jupiter.api.extension.ExtensionContext.Store;

import static cz.moneta.test.harness.support.data.GeneratorType.*;

/**
 * {@link Harness} is considered the central entry and interaction point of the Harness framework. It utilizes the
 * builder pattern and provides a comprehensive fluent API.
 * <p/>
 * It serves as an entry point to individual systems' and applications' DSL via <i>Harness#with&lt;system&gt;</i> methods
 * (e.g. {@link Harness#withUdebs()})
 * <p/>
 * Additionally, it sports a number of utility methods. These include (for details see the individual method documentation):
 * <ul>
 * <li>{@link Harness#getEndpoint} retrieves individual system/application endpoint with its api</li>
 * <li>{@link Harness#get} retrieves value from Harness key-value store (this store has test class scope)</li>
 * <li>{@link Harness#store} stores value in Harness key-value store with a given key</li>
 * <li>{@link Harness#getGlobal} retrieves value from Harness global key-value store (this store is persistent across all tests run)</li>
 * <li>{@link Harness#storeGlobal} stores value in Harness global key-value store with a given key</li>
 * <li>{@link Harness#log} is the preferred method of logging in Harness</li>
 * <li>{@link Harness#generate} gives access to value generators registered with Harness (see {@link GeneratorType GeneratorType} for the list of available generators)</li>
 * <li>{@link Harness#getConfig} gives access to properties stored in harness <i>config</i> files</li>
 * <li>{@link Harness#data} gives access to test data builders (e.g. {@link cz.moneta.test.dsl.util.data.client.NonClient NonClient})
 * <li>{@link Harness#tasks} gives access to a collection of tasks such as isolated database calls or re-usable parts of web flows
 * </ul>
 * <p/>
 * <p>
 * Harness can be (and usually is) injected into test methods as a parameter.
 * <pre>{@code
 *    @literal @TestCase
 *     public void tc_check_config(Harness harness) {
 *         SpiritRef countDooku = harness.withDemo()
 *                 .summonSpirit("Count Dooku");
 *         ...
 *     }
 *  }</pre>
 */
@TestContext
public class Harness extends BaseStoreAccessor {

    private static final String SECOND_BANKER_TOKEN = "Second UFO";

    public Harness(Store rootStore, Store globalStore, Store endpointStore, Store configStore, Store generatorsStore) {
        super(rootStore, globalStore, endpointStore, configStore, generatorsStore);
        initGenerators();
    }

    public static String getSecondBankerToken() {
        return SECOND_BANKER_TOKEN;
    }

    public Udebs withUdebs() {
        return new Udebs(this);
    }

    public OpenApiBuilder withOpenApi() {
        return new OpenApiBuilder(this);
    }

    public CaApiBuilder withCaOpenApi() {
        return new CaApiBuilder(this);
    }

    public CaGw withCaGw() {
        return new CaGw(this);
    }

    @Deprecated
    public Ib withIB() {
        return new Ib(this);
    }

    public NewIb withNewIb() {
        return new NewIb(this);
    }

    @Deprecated
    public IHub withIHub() {
        return new IHub(this);
    }

    public Wso2 withWso2() {
        return new Wso2(this);
    }

    public Ufo withUfo() {
        return new Ufo(this);
    }

    public Ufo withUfoSecondInstance() {
        return new Ufo(this, SECOND_BANKER_TOKEN);
    }

    public Oauth2Web withOauth2Web() {
        return new Oauth2Web(this);
    }

    public DmbsIb withDmbsIb() {
        return new DmbsIb(this);
    }

    public Spirits withDemo() {
        return new Spirits(this);
    }

    public DemoWebChrome withDemoChromeTestPage() {
        return new DemoWebChrome(this);
    }

    public DemoWebEdge withDemoEdgeTestPage() {
        return new DemoWebEdge(this);
    }

    public MonetaPortal withMonetaPortal() {
        return new MonetaPortal(this);
    }

    public BrokerPortal withBrokerPortal() {
        return new BrokerPortal(this);
    }

    public Hypos withHypos() {
        return new Hypos(this);
    }

    public SmartAuto withSmartAuto() {
        return new SmartAuto(this);
    }

    public SmartAutoSetman withSmartAutoSetman() {
        return new SmartAutoSetman(this);
    }

    public AutoApiBuilder withAutoApi() {
        return new AutoApiBuilder(this);
    }

    public AresApiBuilder withAresApi() {
        return new AresApiBuilder(this);
    }

    public PaeMqBuilder withPaeMq() {
        return new PaeMqBuilder(this);
    }

    public Sb withSB() {
        return new Sb(this);
    }

    public Kasanova withKasanova() {
        return new Kasanova(this);
    }

    @Deprecated(since = "unmaintained since update to Java 17")
    public Cebia withCebia() {
        return new Cebia(this);
    }

    public GreenScreen withGreenScreen() {
        return new GreenScreen(this);
    }

    public Data data() {
        return new Data(this);
    }

    public Tasks tasks() {
        return new Tasks(this);
    }

    public MonetaApiPortal withMonetaApiPortal() {
        return new MonetaApiPortal(this);
    }

    public PaymentEngine withPaymentEngine() {
        return new PaymentEngine(this);
    }

    public Ilods withIlods() {
        return new Ilods(this);
    }

    public DataPrepareTasks dataPrepare() {
        return new DataPrepareTasks(this);
    }

    public Refinanso withRefinanso() {
        return new Refinanso(this);
    }

    public Finanso withFinanso() {
        return new Finanso(this);
    }

    public TestAutomationPage withTestAutomationPage() {
        return new TestAutomationPage(this);
    }

    public SalesForce withSalesForce() {
        return new SalesForce(this);
    }

    public SalesForceApiBuilder withSalesForceApi() {
        return new SalesForceApiBuilder(this);
    }

    public ElasticApiBuilder withElasticApi() {
        return new ElasticApiBuilder(this);
    }

    public ForteLight withForteLight() {
        return new ForteLight(this);
    }

    public Forte withForte() {
        return new Forte(this);
    }

    public Broadcom withBroadcom() {
        return new Broadcom(this);
    }

    public SzrMockBuilder withSzrMock() {
        return new SzrMockBuilder(this);
    }

    public MockServer withMockServer() {
        return new MockServer(this);
    }

    public Exevido withExevido() {
        return new Exevido(this);
    }

    public Cashman withCashman() {
        return new Cashman(this);
    }

    public ImqFirstVision withImqFirstVision() {
        return new ImqFirstVision(this);
    }

    public Kafka withKafka() {
        return new Kafka(this);
    }

    private void initGenerators() {
        addGenerator(RC, new RcGenerator());
        addGenerator(FIRST_NAME, new FirstNameGenerator());
        addGenerator(LAST_NAME, new LastNameGenerator());
        addGenerator(ID_CARD, new IdCardGenerator());
        addGenerator(ID_CARD_CHECK_DIGIT, new IdCardCheckDigitGenerator());
        addGenerator(PASSPORT_NUMBER, new PassportGenerator());
        addGenerator(MOBILE_PHONE_NUMBER, new MobilePhoneNumberGenerator());
        addGenerator(FIX_LINE_PHONE_NUMBER, new FixLinePhoneNumberGenerator());
        addGenerator(ICO, new IcoGenerator());
        addGenerator(SIPO, new SipoGenerator());
        addGenerator(ACCOUNT_NUMBER, new AccountNumberGenerator());
        addGenerator(RESIDENCY_ADDRESS, new ResidencyAddressGenerator());
        addGenerator(EMPLOYER, new EmployerGenerator());
    }
}
