package io.vertx.up.unity;

import io.horizon.atom.common.Kv;
import io.horizon.atom.common.Refer;
import io.horizon.eon.VString;
import io.horizon.eon.em.typed.ChangeFlag;
import io.horizon.exception.WebException;
import io.horizon.uca.qr.Pagination;
import io.modello.atom.normalize.KRuleTerm;
import io.modello.specification.HRecord;
import io.vertx.core.*;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.eventbus.Message;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.shareddata.ClusterSerializable;
import io.vertx.ext.auth.User;
import io.vertx.ext.web.FileUpload;
import io.vertx.ext.web.RoutingContext;
import io.vertx.up.atom.exchange.DConsumer;
import io.vertx.up.atom.exchange.DFabric;
import io.vertx.up.atom.exchange.DSetting;
import io.vertx.up.atom.worker.Mission;
import io.vertx.up.commune.Envelop;
import io.vertx.up.commune.config.Integration;
import io.vertx.up.commune.record.Apt;
import io.vertx.up.commune.secure.AegisItem;
import io.vertx.up.commune.secure.Vis;
import io.vertx.up.eon.KName;
import io.vertx.up.eon.configure.YmlCore;
import io.vertx.up.eon.em.EmSecure;
import io.vertx.up.fn.Fn;
import io.vertx.up.plugin.database.DataPool;
import io.vertx.up.plugin.jooq.JooqDsl;
import io.vertx.up.plugin.jooq.JooqInfix;
import io.vertx.up.plugin.shared.UxPool;
import io.vertx.up.secure.Lee;
import io.vertx.up.secure.LeeBuiltIn;
import io.vertx.up.uca.jooq.UxJoin;
import io.vertx.up.uca.jooq.UxJooq;
import io.vertx.up.util.Ut;

import java.time.Instant;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * #「Kt」Utility X Component in zero
 * <p>
 * Here Ux is a util interface of uniform to call different tools.
 * It just like helper for business usage.
 */
@SuppressWarnings("all")
public final class Ux {

    /**
     * Create new log instance for store `Annal` mapping
     * <p>
     * Debug method for help us to do development
     * 1) debug:
     * -- debugTc:  It will be used in test case
     * 2) otherwise:
     * 3) dataN/dataO -> New / Old Json
     * ( Business Part: Debugging )
     */

    public static void debug(final Object... objects) {
        Debug.monitor(objects);
    }

    public static void debugTc(final ClusterSerializable cluster) {
        Debug.monitorTc(cluster);
    }

    public static <T> Future<T> debug(final T item) {
        return Debug.debug(item);
    }

    public static <T> T debug(final Throwable error, final Supplier<T> supplier) {
        return Debug.debug(error, supplier);
    }

    public static Function<Throwable, Envelop> otherwise() {
        return Debug.otherwise();
    }

    public static <T> Function<Throwable, T> otherwise(Supplier<T> supplier) {
        return Debug.otherwise(supplier);
    }

    public static <T> Function<Throwable, T> otherwise(T input) {
        return otherwise(() -> input);
    }


    /*
     * Update Data on Record
     * 1. Generic T ( Pojo )
     * 2. List<T>
     * 3. JsonObject
     * 4. JsonArray
     * 5. Record
     * 6. Record[]
     */
    public static <T> T cloneT(final T input) {
        return Compare.cloneT(input);
    }

    public static <T> T updateT(final T query, final JsonObject params) {
        return Compare.updateT(query, params);
    }

    public static <T> List<T> updateT(final List<T> query, final JsonArray params) {
        return Compare.updateT(query, params, KName.KEY);
    }

    public static <T> List<T> updateT(final List<T> query, final JsonArray params, final String field) {
        return Compare.updateT(query, params, field);
    }

    public static JsonArray updateJ(final JsonArray query, final JsonArray params) {
        return Compare.updateJ(query, params, KName.KEY);
    }

    public static JsonArray updateJ(final JsonArray query, final JsonArray params, final String field) {
        return Compare.updateJ(query, params, field);
    }

    public static HRecord updateR(final HRecord record, final JsonObject params) {
        return Compare.updateR(record, params, () -> UUID.randomUUID().toString());
    }

    public static HRecord[] updateR(final HRecord[] record, final JsonArray array) {
        return updateR(record, array, KName.KEY);
    }

    public static HRecord[] updateR(final HRecord[] record, final JsonArray array, final String field) {
        final List<HRecord> recordList = Arrays.asList(record);
        return Compare.updateR(recordList, array, field).toArray(new HRecord[]{});
    }

    /*
     * Rule Match
     * 1. single checking
     * 2. double checking
     * 3. array checking
     */
    public static JsonObject ruleAll(final Collection<KRuleTerm> rules, final JsonObject input) {
        return Unique.ruleAll(rules, input);
    }

    public static ConcurrentMap<Boolean, JsonArray> ruleAll(final Collection<KRuleTerm> rules, final JsonArray input) {
        return Unique.ruleAll(rules, input);
    }

    public static JsonObject ruleAll(final Collection<KRuleTerm> rules, final JsonObject recordO, final JsonObject recordN) {
        return Unique.ruleAll(rules, recordO, recordN);
    }

    public static JsonObject ruleAll(final Collection<KRuleTerm> rules, final JsonArray source, final JsonObject record) {
        return Unique.ruleAll(rules, source, record);
    }

    public static JsonObject ruleAny(final Collection<KRuleTerm> rules, final JsonObject input) {
        return Unique.ruleAny(rules, input);
    }

    public static JsonObject ruleAny(final Collection<KRuleTerm> rules, final JsonObject record0, final JsonObject recordN) {
        return Unique.ruleAny(rules, record0, recordN);
    }

    public static JsonObject ruleAny(final Collection<KRuleTerm> rules, final JsonArray source, final JsonObject record) {
        return Unique.ruleAny(rules, source, record);
    }

    public static ConcurrentMap<Boolean, JsonArray> ruleAny(final Collection<KRuleTerm> rules, final JsonArray input) {
        return Unique.ruleAny(rules, input);
    }

    public static JsonObject ruleTwins(final JsonObject recordO, final JsonObject recordN) {
        return Unique.ruleTwins(recordO, recordN);
    }

    public static JsonObject ruleNil(final JsonObject twins, final ChangeFlag flag) {
        return Unique.ruleNil(twins, flag);
    }

    public static JsonObject ruleNil(final JsonObject recordN, final JsonObject recordO) {
        return Objects.isNull(recordN) ? recordO : recordN;
    }

    public static Apt ruleApt(final JsonArray twins, final boolean isReplaced) {
        return Unique.ruleApt(twins, isReplaced);
    }

    // ------------------------- Compare Json ------------------------
    /*
     *  1) ruleJOk
     *  2) ruleJReduce
     *  3) ruleJEqual
     *  4) ruleJFind
     */
    public static boolean ruleJOk(final JsonObject record, final Set<String> fields) {
        return CompareJ.ruleJOk(record, fields);
    }

    public static boolean ruleJOk(final JsonObject record, final JsonArray matrix) {
        return CompareJ.ruleJOk(record, matrix);
    }

    public static JsonArray ruleJReduce(final JsonArray records, final Set<String> fields) {
        return CompareJ.ruleJReduce(records, fields);
    }

    public static JsonArray ruleJReduce(final JsonArray records, final JsonArray matrix) {
        return CompareJ.ruleJReduce(records, matrix);
    }

    public static boolean ruleJEqual(final JsonObject record, final JsonObject latest, final Set<String> fields) {
        return CompareJ.ruleJEqual(record, latest, fields);
    }

    public static boolean ruleJEqual(final JsonObject record, final JsonObject latest, final JsonArray matrix) {
        return CompareJ.ruleJEqual(record, latest, matrix);
    }

    public static JsonObject ruleJFind(final JsonArray source, final JsonObject expected, final Set<String> fields) {
        return CompareJ.ruleJFind(source, expected, fields);
    }

    public static JsonObject ruleJFind(final JsonArray source, final JsonObject expected, final JsonArray matrix) {
        return CompareJ.ruleJFind(source, expected, matrix);
    }

    /*
     * Entity ( Pojo ) to JsonObject, support pojo file here
     * 1) toJson / fromJson
     * 2) toZip:  Toggle switch from interface style to worker here, the key should be "0", "1", "2", "3", ....
     * 3) toJArray
     * ( Business Part, support `pojoFile` conversation )
     * 4) toFile
     */

    public static <T> JsonObject toJson(final T entity) {
        return To.toJObject(entity, "");
    }

    public static <T> JsonObject toJson(final T entity, final String pojo) {
        return To.toJObject(entity, pojo);
    }

    public static <T> JsonArray toJson(final List<T> list) {
        return To.toJArray(list, "");
    }

    public static <T> JsonArray toJson(final List<T> list, final String pojo) {
        return To.toJArray(list, pojo);
    }

    public static JsonObject toZip(final Object... args) {
        return To.toToggle(args);
    }

    /*
     * Analyze the arguments by type
     * 1) used by `io.vertx.up.container.mime.parse.TypedAtomic`.
     * 2) used by `io.vertx.up.uca.invoker.InvokerUtil`.
     * The arguments are different, but could support more method declare
     */
    // Job
    public static Object toParameter(final Envelop envelop, final Class<?> type, final Mission mission, final Refer underway) {
        return Web.toParameter(envelop, type, mission, underway);
    }

    // Worker
    public static Object toParameter(final Envelop envelop, final Class<?> type) {
        return Web.toParameter(envelop, type);
    }

    // Agent
    public static Object toParameter(final RoutingContext context, final Class<?> type) {
        return Web.toParameter(context, type);
    }

    public static <T> T fromJson(final JsonObject data, final Class<T> clazz) {
        return From.fromJson(data, clazz, "");
    }

    public static <T> List<T> fromJson(final JsonArray array, final Class<T> clazz) {
        return From.fromJson(array, clazz, "");
    }

    public static <T> List<T> fromPage(final JsonObject data, final Class<T> clazz) {
        return fromJson(pageData(data), clazz);
    }

    public static <T> T fromJson(final JsonObject data, final Class<T> clazz, final String pojo) {
        return From.fromJson(data, clazz, pojo);
    }

    public static <T> List<T> fromJson(final JsonArray array, final Class<T> clazz, final String pojo) {
        return From.fromJson(array, clazz, pojo);
    }

    /**
     * File upload tool to convert data
     *
     * @param fileUploads Set of file uploads
     * @param expected    The method declared type
     * @param consumer    File consumer to read `filename` to Buffer
     * @param <T>         Returned type for declared
     *
     * @return T reference that converted
     */
    public static <T> T toFile(final Set<FileUpload> fileUploads, final Class<?> expected, final Function<String, Buffer> consumer) {
        return Upload.toFile(fileUploads, expected, consumer);
    }

    /**
     * Single file upload converting
     *
     * @param fileUpload The `FileUpload` reference
     * @param expected   The method declared type
     * @param consumer   File consumer to read `filename` to Buffer
     * @param <T>        Returned type of declared
     *
     * @return T reference that converted
     */
    public static <T> T toFile(final FileUpload fileUpload, final Class<?> expected, final Function<String, Buffer> consumer) {
        return Upload.toFile(fileUpload, expected, consumer);
    }

    /**
     * Split `Set<FileUpload>` by fieldname
     *
     * @param fileUploads FileUpload Set
     *
     * @return Map of `field = Set<FileUpload>`
     */
    public static ConcurrentMap<String, Set<FileUpload>> toFile(final Set<FileUpload> fileUploads) {
        return Upload.toFile(fileUploads);
    }

    /*
     * Envelop building here
     * 1) envelop: ( Get different Envelop )
     * 2) future: ( Wrapper Future.successedFuture / Future.failureFuture ) at same time
     * 3) handler: ( Handler<AsyncResult<T>> )
     * 4) compare: ( Compare two object )
     * 5) complex:
     *    - JsonObject -> condition -> executor
     *    - JsonArray -> condition -> grouper -> executor
     */
    public static Envelop fromEnvelop(final Class<? extends WebException> clazz, final Object... args) {
        return To.toEnvelop(clazz, args);
    }

    public static <T> Envelop fromEnvelop(final T entity) {
        return To.toEnvelop(entity);
    }

    public static <T> Envelop fromEnvelop(final T entity, final WebException error) {
        return To.toEnvelop(entity, error);
    }

    public static <T> Future<T> fromAsync(final CompletionStage<T> state) {
        return Async.fromAsync(state);
    }

    public static <T> Future<T> future(final T entity) {
        return To.future(entity);
    }

    public static <T> Future<T> future(final T input, final List<Function<T, Future<T>>> functions) {
        return Async.future(input, functions);
    }

    public static <T> Future<T> future(final T input, final Set<Function<T, Future<T>>> functions) {
        return Async.future(input, functions);
    }

    public static <T> Future<T> future() {
        return To.future(null);
    }

    public static Future<JsonObject> complex(final JsonObject input, final Predicate<JsonObject> predicate, final Supplier<Future<JsonObject>> executor) {
        return Complex.complex(input, predicate, executor);
    }

    public static Future<JsonArray> complex(final Pagination first, final Function<JsonObject, Future<Integer>> total, final Function<Pagination, Future<JsonObject>> page, final Function<JsonObject, Future<JsonArray>> result) {
        return Complex.complex(first, total, page, result, JsonArray::addAll);
    }

    public static Function<Pagination, Future<JsonArray>> complex(final Function<JsonObject, Future<Integer>> total, final Function<Pagination, Future<JsonObject>> page, final Function<JsonObject, Future<JsonArray>> result) {
        return Complex.complex(total, page, result);
    }

    public static Function<Pagination, Future<JsonArray>> complex(final Function<Pagination, Future<JsonObject>> page) {
        return complex(data -> To.future(data.getInteger("count")), page, response -> To.future(response.getJsonArray("list")));
    }

    public static <T> Handler<AsyncResult<T>> handler(final Message<Envelop> message) {
        return Web.toHandler(message);
    }

    public static <T> Future<T> handler(final Consumer<Handler<AsyncResult<T>>> handler) {
        return Web.toFuture(handler);
    }
    /*
     * 1) compare
     * 2) compareJ
     * 3) compareRun
     */

    public static <T, R> ConcurrentMap<ChangeFlag, List<T>> compare(final List<T> original, final List<T> current, final Function<T, R> fnValue, final String pojoFile) {
        return Compare.compare(original, current, fnValue, pojoFile);
    }

    public static <T, R> ConcurrentMap<ChangeFlag, List<T>> compare(final List<T> original, final List<T> current, final Function<T, R> fnValue) {
        return Compare.compare(original, current, fnValue, VString.EMPTY);
    }

    public static <T, R> ConcurrentMap<ChangeFlag, List<T>> compare(final List<T> original, final List<T> current, final Set<String> uniqueSet, final String pojoFile) {
        return Compare.compare(original, current, uniqueSet, pojoFile);
    }

    public static <T, R> ConcurrentMap<ChangeFlag, List<T>> compare(final List<T> original, final List<T> current, final Set<String> uniqueSet) {
        return Compare.compare(original, current, uniqueSet, VString.EMPTY);
    }

    public static ConcurrentMap<ChangeFlag, JsonArray> compareJ(
        final JsonArray original, final JsonArray current, final Set<String> fields) {
        return CompareJ.compareJ(original, current, fields);
    }

    public static ConcurrentMap<ChangeFlag, JsonArray> compareJ(
        final JsonArray original, final JsonArray current, final String field) {
        return CompareJ.compareJ(original, current, field);
    }

    public static ConcurrentMap<ChangeFlag, JsonArray> compareJ(
        final JsonArray original, final JsonArray current, final JsonArray matrix) {
        return CompareJ.compareJ(original, current, matrix);
    }

    public static Future<ConcurrentMap<ChangeFlag, JsonArray>> compareJAsync(
        final JsonArray original, final JsonArray current, final Set<String> fields) {
        return To.future(CompareJ.compareJ(original, current, fields));
    }

    public static Future<ConcurrentMap<ChangeFlag, JsonArray>> compareJAsync(
        final JsonArray original, final JsonArray current, final String field) {
        return To.future(CompareJ.compareJ(original, current, field));
    }

    public static Future<ConcurrentMap<ChangeFlag, JsonArray>> compareJAsync(
        final JsonArray original, final JsonArray current, final JsonArray matrix) {
        return To.future(CompareJ.compareJ(original, current, matrix));
    }

    public static <T> Future<JsonArray> compareRun(final ConcurrentMap<ChangeFlag, List<T>> compared, final Function<List<T>, Future<List<T>>> insertAsyncFn, final Function<List<T>, Future<List<T>>> updateAsyncFn) {
        return Compare.run(compared, insertAsyncFn, updateAsyncFn);
    }

    /*
     *  future prefix processing here
     *
     * JsonArray
     * 1) futureA
     * -- futureA()
     * -- futureA(List)
     * -- futureA(List, pojo)
     * -- futureA(String)
     * -- futureA(Record[])
     *
     * JsonObject
     * 2) futureJ
     * -- futureJ()
     * -- futureJ(T)
     * -- futureJ(T, pojo)
     * -- futureJ(String)
     * -- futureJ(Record)
     * -- futureJM(T, String)
     *
     * List
     * 3) futureL
     * -- futureL()
     * -- futureL(List)
     * -- futureL(List, pojo)
     * -- futureL(String)
     *
     * Grouped
     * 4) futureG
     * -- futureG(List, String)
     * -- futureG(T, String)
     * -- futureG(List)
     * -- futureG(T)
     *
     * Error Future
     * 5) futureE
     * -- futureE(T)
     * -- futureE(Supplier)
     *
     * New Api for normalized mount
     * 6) futureN
     * -- futureN(JsonObject, JsonObject)
     * -- futureN(JsonArray, JsonArray)
     * -- futureN(JsonArray, JsonArray, String)
     * > N for normalize and add new field:  __data,  __flag instead of original data
     *
     * Combine JsonObject and JsonArray by index
     * 7) futureC
     *
     * Filter JsonObject and JsonArray
     * 8) futureF
     * -- futureF(String...)
     * -- futureF(Set<String>)
     * -- futureF(ClustSerializble, String...)
     * -- futureF(JsonArray, String...)
     * -- futureF(JsonObject, Set<String>)
     * -- futureF(JsonArray, Set<String>)
     */
    // ----------------------- futureF ----------------------

    public static <T extends ClusterSerializable> Function<T, Future<T>> futureF(final Set<String> removed) {
        return input -> (input instanceof JsonObject) ?
            futureF((JsonObject) input, removed).compose(json -> To.future((T) json)) :
            futureF((JsonArray) input, removed).compose(array -> To.future((T) array));
    }

    public static <T extends ClusterSerializable> Function<T, Future<T>> futureF(final String... removed) {
        return futureF(Arrays.stream(removed).collect(Collectors.toSet()));
    }

    public static Future<JsonObject> futureF(final JsonObject input, final String... removed) {
        return To.future(To.subset(input, Arrays.stream(removed).collect(Collectors.toSet())));
    }

    public static Future<JsonObject> futureF(final JsonObject input, final Set<String> removed) {
        return To.future(To.subset(input, removed));
    }

    public static Future<JsonArray> futureF(final JsonArray input, final String... removed) {
        return To.future(To.subset(input, Arrays.stream(removed).collect(Collectors.toSet())));
    }

    public static Future<JsonArray> futureF(final JsonArray input, final Set<String> removed) {
        return To.future(To.subset(input, removed));
    }

    // ----------------------- futureN ----------------------
    public static Future<JsonObject> futureN(final JsonObject input, final JsonObject previous, final JsonObject current) {
        return Norm.effect(input, previous, current);
    }

    public static Future<JsonArray> futureN(final JsonArray previous, final JsonArray current) {
        return Norm.effect(previous, current, KName.KEY);
    }

    public static Future<JsonArray> futureN(final JsonArray previous, final JsonArray current, final String field) {
        return Norm.effect(previous, current, field);
    }

    public static <T> Future<T> futureC(final T input, final T processed) {
        return Norm.combine(input, processed);
    }

    public static Future<Boolean> futureT() {
        return To.future(Boolean.TRUE);
    }

    public static <T> Future<Boolean> futureT(final T input) {
        return To.future(Boolean.TRUE);
    }

    public static Future<Boolean> futureF() {
        return To.future(Boolean.FALSE);
    }

    public static <T> Future<List<T>> futureL() {
        return future(new ArrayList<>());
    }

    public static <T> Future<List<T>> futureL(final T single) {
        final List<T> list = new ArrayList<>();
        list.add(single);
        return future(list);
    }

    public static <T> Function<Throwable, Future<T>> futureE(final T input) {
        return Async.toErrorFuture(() -> input);
    }

    public static <T> Function<Throwable, Future<T>> futureE(final Supplier<T> supplier) {
        return Async.toErrorFuture(supplier);
    }

    public static <T> Future<JsonArray> futureA(final List<T> list, final String pojo) {
        return Future.succeededFuture(To.toJArray(list, pojo));
    }

    public static Future<JsonArray> futureA() {
        return futureA(new ArrayList<>(), VString.EMPTY);
    }

    public static Future<JsonArray> futureA(Throwable ex) {
        return Async.<JsonArray>toErrorFuture(JsonArray::new).apply(ex);
    }

    public static <T> Future<JsonArray> futureA(final List<T> list) {
        return futureA(list, VString.EMPTY);
    }

    public static <T> Function<List<T>, Future<JsonArray>> futureA(final String pojo) {
        return list -> futureA(list, pojo);
    }

    // --------------- T of entity processing -----------------

    public static <T> Future<JsonObject> futureJ(final T entity, final String pojo) {
        return Future.succeededFuture(To.toJObject(entity, pojo));
    }

    public static <T, R> Function<List<R>, Future<JsonObject>> futureJM(final T entity, final String field) {
        return list -> Future.succeededFuture(To.toMerge(entity, field, list));
    }

    public static Future<JsonObject> futureJ() {
        return futureJ(new JsonObject(), VString.EMPTY);
    }

    public static Future<JsonObject> futureJ(Throwable ex) {
        return Async.<JsonObject>toErrorFuture(JsonObject::new).apply(ex);
    }

    public static <T> Future<JsonObject> futureJ(final T entity) {
        return futureJ(entity, VString.EMPTY);
    }

    public static <T> Function<T, Future<JsonObject>> futureJ(final String pojo) {
        return entity -> futureJ(entity, pojo);
    }

    // --------------- List<T> of future processing -----------------
    public static <T> Future<List<JsonObject>> futureL(final List<T> list, final String pojo) {
        return Future.succeededFuture(To.toJList(list, pojo));
    }

    public static <T> Future<List<JsonObject>> futureLJ() {
        return futureL(new ArrayList<>(), VString.EMPTY);
    }

    public static <T> Future<List<JsonObject>> futureL(final List<T> list) {
        return futureL(list, VString.EMPTY);
    }

    public static <T> Function<List<T>, Future<List<JsonObject>>> futureL(final String pojo) {
        return list -> futureL(list, pojo);
    }

    // --------------- Record processing -----------------

    public static Future<JsonObject> futureJ(final HRecord record) {
        return Fn.runOr(futureJ(), () -> To.future(record.toJson()), record);
    }

    public static Future<JsonArray> futureA(final HRecord[] records) {
        return Fn.runOr(futureA(), () -> To.future(Ut.toJArray(records)), records);
    }

    // --------------- Future of Map -----------------
    public static <T> Future<ConcurrentMap<String, JsonArray>> futureG(final List<T> item, final String field) {
        return futureG(To.toJArray(item, ""), field);
    }

    public static Future<ConcurrentMap<String, JsonArray>> futureG(final JsonArray item, final String field) {
        return Future.succeededFuture(Ut.elementGroup(item, field));
    }

    public static <T> Future<ConcurrentMap<String, JsonArray>> futureG(final List<T> item) {
        return futureG(To.toJArray(item, ""), "type");
    }

    public static Future<ConcurrentMap<String, JsonArray>> futureG(final JsonArray item) {
        return futureG(item, "type");
    }

    /*
     * Channel Execution
     *
     * 1. channel
     * 2. channelS
     * 3. channelA
     */
    public static <T, O> Future<O> channel(final Class<T> clazz, final Supplier<O> supplier,
                                           final Function<T, Future<O>> executor) {
        return Async.channel(clazz, supplier, executor);
    }


    public static <T, O> O channelS(final Class<T> clazz, final Supplier<O> supplier,
                                    final Function<T, O> executor) {
        return Async.channelSync(clazz, supplier, executor);
    }

    public static <T, O> O channelS(final Class<T> clazz, final Function<T, O> executor) {
        return Async.channelSync(clazz, () -> null, executor);
    }

    public static <T, O> Future<O> channelA(final Class<T> clazz, final Supplier<Future<O>> supplier,
                                            final Function<T, Future<O>> executor) {
        return Async.channelAsync(clazz, supplier, executor);
    }

    /*
     * Normalize pageData in framework
     * {
     *      "list": [],
     *      "count": xx
     * }
     * Normalize old/new data in framework
     */

    public static JsonObject pageData() {
        return Web.pageData(new JsonArray(), 0L);
    }

    public static JsonObject pageData(final JsonArray data, final long size) {
        return Web.pageData(data, size);
    }

    public static JsonArray pageData(final JsonObject data) {
        return Ut.valueJArray(data.getJsonArray(KName.LIST));
    }

    public static JsonObject pageData(final JsonObject pageData, final Function<JsonArray, JsonArray> function) {
        return Web.pageData(pageData, function);
    }

    /*
     * JqTool Engine method
     * 1) whereDay
     * 2) whereAnd
     * 3) whereOr
     * 4) whereKeys
     */
    public static JsonObject whereDay(final JsonObject filters, final String field, final Instant instant) {
        return Where.whereDay(filters, field, instant);
    }

    public static JsonObject whereDay(final JsonObject filters, final String field, final LocalDateTime instant) {
        return Where.whereDay(filters, field, Ut.parse(instant).toInstant());
    }

    public static JsonObject whereKeys(final Set<String> keys) {
        return Where.whereKeys(Ut.toJArray(keys));
    }

    public static JsonObject whereKeys(final JsonArray keys) {
        return Where.whereKeys(keys);
    }

    public static JsonObject whereAnd() {
        return Where.whereAnd();
    }

    public static JsonObject whereAnd(final String field, final Object value) {
        return Where.whereAnd().put(field, value);
    }

    public static JsonObject whereOr() {
        return Where.whereOr();
    }

    public static JsonObject whereOr(final String field, final Object value) {
        return Where.whereOr().put(field, value);
    }

    public static JsonObject whereAmb(final ClusterSerializable json, final String field) {
        return Where.whereAmb(json, field, field, true);
    }

    public static JsonObject whereAmb(final ClusterSerializable json,
                                      final String fieldFrom, final String fieldTo) {
        return Where.whereAmb(json, fieldFrom, fieldTo, true);
    }

    // Where current condition is null
    /*
     * Query Engine API
     *
     * QH -> Query with Criteria   （全格式）
     * H  -> Criteria              （查询条件）
     * V  -> Projection            （列过滤）
     *
     * 1) irNil / irAnd / irOne
     *    - irNil:          判断查询条件是否为空，"": true | false 单节点也为空
     *    - irOp:           判断查询条件是 AND 还是 OR，AND返回true，OR返回false
     *    - irOne:          判断查询条件是否单条件（只有一个条件）
     * 2) irAndQH / irAndH
     *    - irAndQH:        参数本身为全格式:
     *      {
     *           "criteria": {}
     *      }
     *    - irAndH:         参数本身为全格式中的 criteria 纯格式
     * 3) irQV / irV
     *    - irQV:           参数本身为全格式:
     *      {
     *           "projection": []
     *      }
     *    - irV:            参数本身为全格式中的 projection 纯格式
     *
     * 全格式返回全格式，纯格式返回纯格式
     */
    public static boolean irNil(final JsonObject condition) {
        return Query.irNil(condition);
    }

    public static boolean irOp(final JsonObject condition) {
        return Query.irAnd(condition);
    }

    public static boolean irOne(final JsonObject condition) {
        return Query.irOne(condition);
    }

    // ---------------------- Qr Modification --------------------------
    public static JsonObject irAndQH(final JsonObject qr, final Kv<String, Object> kv) {
        Objects.requireNonNull(kv);
        return Query.irQH(qr, kv.key(), kv.value());
    }

    public static JsonObject irAndQH(final JsonObject qr, final String field, final Object value) {
        return Query.irQH(qr, field, value);
    }

    public static JsonObject irAndQH(final JsonObject query, final JsonObject criteria, final boolean clear) {
        return Query.irQH(query, criteria, clear);
    }

    public static JsonObject irAndH(final JsonObject original, final JsonObject criteria) {
        return Query.irH(original, criteria);
    }

    public static JsonObject irAndH(final JsonObject original, final String field, final Object value) {
        return Query.irH(original, field, value);
    }

    public static JsonObject irAndH(final JsonObject original, final Kv<String, Object> kv) {
        Objects.requireNonNull(kv);
        return Query.irH(original, kv.key(), kv.value());
    }

    // Qr Combine ( projection + projection )
    public static JsonObject irQV(final JsonObject query, final JsonArray projection, final boolean clear) {
        return Query.irQV(query, projection, clear);
    }

    public static JsonArray irV(final JsonArray original, final JsonArray projection) {
        return Query.irV(original, projection);
    }

    // ---------------------- Request Data Extract --------------------------
    // -> Message<Envelop> -> T ( Interface mode )

    public static JsonArray getArray(final Envelop envelop, final int index) {
        return In.request(envelop, index, JsonArray.class);
    }

    // -> Message<Envelop> -> T ( Interface mode )
    public static JsonArray getArray(final Envelop envelop) {
        return In.request(envelop, 0, JsonArray.class);
    }

    // -> Message<Envelop> -> T ( Interface mode )

    public static JsonArray getArray1(final Envelop envelop) {
        return In.request(envelop, 1, JsonArray.class);
    }

    // -> Message<Envelop> -> T ( Interface mode )

    public static JsonArray getArray2(final Envelop envelop) {
        return In.request(envelop, 2, JsonArray.class);
    }

    // -> Message<Envelop> -> String ( Interface mode )

    public static String getString(final Envelop envelop, final int index) {
        return In.request(envelop, index, String.class);
    }

    // -> Message<Envelop> -> String ( Interface mode )
    public static String getString(final Envelop envelop) {
        return In.request(envelop, 0, String.class);
    }

    // -> Message<Envelop> -> String ( Interface mode )
    public static String getString1(final Envelop envelop) {
        return In.request(envelop, 1, String.class);
    }

    // -> Message<Envelop> -> String ( Interface mode )
    public static String getString2(final Envelop envelop) {
        return In.request(envelop, 2, String.class);
    }

    // -> Message<Envelop> -> String ( Interface mode )

    public static Vis getVis(final Envelop envelop, final int index) {
        return In.request(envelop, index, Vis.class);
    }

    // -> Message<Envelop> -> String ( Interface mode )
    public static Vis getVis(final Envelop envelop) {
        return In.request(envelop, 0, Vis.class);
    }

    // -> Message<Envelop> -> String ( Interface mode )
    public static Vis getVis1(final Envelop envelop) {
        return In.request(envelop, 1, Vis.class);
    }

    // -> Message<Envelop> -> String ( Interface mode )
    public static Vis getVis2(final Envelop envelop) {
        return In.request(envelop, 2, Vis.class);
    }

    // -> Message<Envelop> -> JsonObject ( Interface mode )
    public static JsonObject getJson(final Envelop envelop, final int index) {
        return In.request(envelop, index, JsonObject.class);
    }
    // -> Message<Envelop> -> JsonObject ( Interface mode )

    public static <T> T fromEnvelop(final Envelop envelop, final Class<T> clazz, final String pojo) {
        return From.fromJson(getJson(envelop), clazz, pojo);
    }

    public static JsonObject fromEnvelop(final Envelop envelop, final String pojo) {
        return From.fromJson(Ux.getJson(envelop), pojo);
    }

    public static JsonObject getJson(final Envelop envelop) {
        return In.request(envelop, 0, JsonObject.class);
    }

    // -> Message<Envelop> -> JsonObject ( Interface mode )

    public static <T> T fromEnvelop1(final Envelop envelop, final Class<T> clazz, final String pojo) {
        return From.fromJson(getJson1(envelop), clazz, pojo);
    }

    public static JsonObject fromEnvelop1(final Envelop envelop, final String pojo) {
        return From.fromJson(Ux.getJson1(envelop), pojo);
    }

    public static JsonObject getJson1(final Envelop envelop) {
        return In.request(envelop, 1, JsonObject.class);
    }

    // -> Message<Envelop> -> JsonObject ( Interface mode )

    public static JsonObject getJson2(final Envelop envelop) {
        return In.request(envelop, 2, JsonObject.class);
    }

    public static JsonObject fromEnvelop2(final Envelop envelop, final String pojo) {
        return From.fromJson(Ux.getJson2(envelop), pojo);
    }

    public static <T> T fromEnvelop2(final Envelop envelop, final Class<T> clazz, final String pojo) {
        return From.fromJson(getJson2(envelop), clazz, pojo);
    }

    // -> Message<Envelop> -> Integer ( Interface mode )

    public static Integer getInteger(final Envelop envelop, final int index) {
        return In.request(envelop, index, Integer.class);
    }

    public static Integer getInteger(final Envelop envelop) {
        return In.request(envelop, 0, Integer.class);
    }

    // -> Message<Envelop> -> Integer ( Interface mode )
    public static Integer getInteger1(final Envelop envelop) {
        return In.request(envelop, 1, Integer.class);
    }

    // -> Message<Envelop> -> Integer ( Interface mode )
    public static Integer getInteger2(final Envelop envelop) {
        return In.request(envelop, 2, Integer.class);
    }

    // -> Message<Envelop> -> Long ( Interface mode )

    public static Long getLong(final Envelop envelop, final int index) {
        return In.request(envelop, index, Long.class);
    }

    // -> Message<Envelop> -> Long ( Interface mode )
    public static Long getLong(final Envelop envelop) {
        return In.request(envelop, 0, Long.class);
    }

    // -> Message<Envelop> -> Long ( Interface mode )
    public static Long getLong1(final Envelop envelop) {
        return In.request(envelop, 1, Long.class);
    }

    // -> Message<Envelop> -> Long ( Interface mode )
    public static Long getLong2(final Envelop envelop) {
        return In.request(envelop, 2, Long.class);
    }

    // -> Message<Envelop> -> T ( Interface mode )

    public static <T> T getT(final Envelop envelop, final int index, final Class<T> clazz) {
        return In.request(envelop, index, clazz);
    }

    // -> Message<Envelop> -> T ( Interface mode )

    public static <T> T getT(final Envelop envelop, final Class<T> clazz) {
        return In.request(envelop, 0, clazz);
    }

    // -> Message<Envelop> -> T ( Interface mode )

    public static <T> T getT1(final Envelop envelop, final Class<T> clazz) {
        return In.request(envelop, 1, clazz);
    }

    // -> Message<Envelop> -> T ( Interface mode )

    public static <T> T getT2(final Envelop envelop, final Class<T> clazz) {
        return In.request(envelop, 2, clazz);
    }

    // ---------------------- Agent mode usage --------------------------
    // -> Message<Envelop> -> JsonObject ( Agent mode )
    // -> Envelop -> JsonObject ( Agent mode )
    public static JsonObject getBody(final Envelop envelop) {
        return In.request(envelop, JsonObject.class);
    }

    // -> Envelop -> T ( Agent mode )
    public static <T> T getBodyT(final Envelop envelop, final Class<T> clazz) {
        return In.request(envelop, clazz);
    }

    // ---------------------- Agent mode usage --------------------------

    /**
     * This method will be configured in `vertx-extension.yml` file in common situation,
     * The file content should be as following:
     * <p>
     * ```yml
     * // <pre><code>
     * init:
     *   - component: "[ComponentName1]"
     *   - component: "[ComponentName2]"
     * // </code></pre>
     * ```
     * </p>
     * new mode as
     * <p>
     * ```yml
     * // <pre><code>
     * init:
     *    extension:
     *     - component: "[ComponentName1]"
     *     - component: "[ComponentName2]"
     *    bridge:
     *     - component: "xxxx"
     *     - order: 1
     * // </code></pre>
     * ```
     * </p>
     * All components here will be called when container starting, the component must declare the init method as
     * <p>
     * ```java
     * // <pre><code>
     * public static void init(){
     *     // Here are initialize code logical
     *     Ke.banner("「Εκδήλωση」- Crud ( Ix )");
     *
     *     Ix.infoInit(LOGGER, "IxConfiguration...");
     * }
     * // </code></pre>
     * ```
     * </p>
     * This method should be used when you want to develop zero extension module for business requirement.
     *
     * @param init The configuration data came from `init` node in file
     */
    public static Future<Boolean> nativeInit(final JsonObject initConfig, final Vertx vertx) {
        return Atomic.nativeInit(initConfig, vertx);
    }

    public static Vertx nativeVertx() {
        return Atomic.nativeVertx();
    }

    public static WorkerExecutor nativeWorker(final String name) {
        return Atomic.nativeWorker(name, 10);
    }

    public static WorkerExecutor nativeWorker(final String name, final Integer mins) {
        return Atomic.nativeWorker(name, mins);
    }

    public static <T> Future<T> nativeWorker(final String name, final Handler<Promise<T>> handler) {
        return Atomic.nativeWorker(name, handler);
    }

    // -> Dict for caculation
    /*
     * Keep following dict method
     */
    public static ConcurrentMap<String, DConsumer> dictEpsilon(final JsonObject epsilon) {
        return DConsumer.mapEpsilon(epsilon);
    }

    public static Future<ConcurrentMap<String, JsonArray>> dictCalc(final DSetting dict, final MultiMap paramsMap) {
        return Dict.dictCalc(dict, paramsMap);
    }

    public static <T> Future<T> dictTo(final T record, final DFabric fabric) {
        return Dict.dictTo(record, fabric);
    }

    /*
     * key part for extract data from environment
     */
    public static String keyUser(final User user) {
        Objects.requireNonNull(user);
        final JsonObject principle = user.principal();
        if (principle.containsKey(KName.USER)) {
            return principle.getString(KName.USER);
        } else {
            /*
             * To avoid fetch user information from JWT token
             */
            final String accessToken = principle.getString(KName.ACCESS_TOKEN);
            final JsonObject credential = Jwt.extract(accessToken);
            return credential.getString(KName.USER);
        }
    }

    // ---------------------------------- Children Utility

    /**
     * Inner class of `Jooq` tool of Jooq Engine operations based on pojo here.
     * When developers want to access database and select zero default implementation.
     *
     * @author lang
     * <pre><code>
     *
     *     public Future<JsonObject> fetchAsync(final User user){
     *         return Ux.Jooq.on(UserDao.class)
     *                    .insertAsync(user)
     *                    .compose(Ux::fnJObject);
     *     }
     *
     * </code></pre>
     * <p>
     * Here you can do database access smartly and do nothing then.
     */
    public static class Jooq {

        /**
         * Get reference of UxJooq that bind to Dao class, this method won't access standard database,
         * instead it will access history database that has been configured in `vertx-jooq.yml` file.
         * <p>
         * key = orbit
         *
         * <pre><code>
         *
         * jooq:
         *   orbit:
         *     driverClassName: "com.mysql.cj.jdbc.Driver"
         *     ......
         *
         * </code></pre>
         *
         * @param clazz The class of `VertxDao` that has been generated by jooq tool
         *
         * @return UxJooq reference that has been initialized
         */
        public static UxJooq ons(final Class<?> clazz) {
            final JooqDsl dsl = JooqInfix.getDao(clazz, YmlCore.jooq.ORBIT);
            return CACHE.CC_JOOQ.pick(() -> new UxJooq(clazz, dsl), "HIS-" + dsl.poolKey());
            // return Fn.po?lThread(Cache.JOOQ_POOL_HIS, () -> new UxJooq(clazz, dsl), dsl.poolKey());
        }

        /**
         * Get reference of UxJooq that bind to Dao class, this method access standard database,
         * the configured position is `vertx-jooq.yml`
         * <p>
         * key = provider
         *
         * <pre><code>
         * jooq:
         *   provider:
         *     driverClassName: "com.mysql.cj.jdbc.Driver"
         * </code></pre>
         *
         * @param clazz The class of `VertxDao` that has been generated by jooq tool
         *
         * @return UxJooq reference that has been initialized
         */
        public static UxJooq on(final Class<?> clazz) {
            final JooqDsl dsl = JooqInfix.getDao(clazz);
            return CACHE.CC_JOOQ.pick(() -> new UxJooq(clazz, dsl), dsl.poolKey());
            // return Fn.po?lThread(Cache.JOOQ_POOL, () -> new UxJooq(clazz, dsl), dsl.poolKey());
        }

        /**
         * The overloading method of above `on(Class<?>)` method here.
         *
         * @param clazz The class of `VertxDao` that has been generated by jooq tool
         * @param pool  Input data pool reference, it provide developers to access other database in one application.
         *
         * @return UxJooq reference that has been initialized
         */
        public static UxJooq on(final Class<?> clazz, final DataPool pool) {
            final JooqDsl dsl = JooqInfix.getDao(clazz, pool);
            return CACHE.CC_JOOQ.pick(() -> new UxJooq(clazz, dsl), dsl.poolKey());
            // return Fn.po?lThread(Cache.JOOQ_POOL, () -> new UxJooq(clazz, dsl), dsl.poolKey());
        }

        /**
         * The overloading method of above `on(Class<?>)` method here.
         *
         * @param clazz The class of `VertxDao` that has been generated by jooq tool
         * @param key   the key configuration in vertx-jooq.yml such as above "orbit", "provider"
         *
         * @return UxJooq reference that has been initialized
         */
        public static UxJooq on(final Class<?> clazz, final String key) {
            final JooqDsl dsl = JooqInfix.getDao(clazz, key);
            return CACHE.CC_JOOQ.pick(() -> new UxJooq(clazz, dsl), dsl.poolKey());
            // return Fn.po?lThread(Cache.JOOQ_POOL, () -> new UxJooq(clazz, dsl), dsl.poolKey());
        }
    }

    // -> Jooq -> Multi
    public static class Join {

        public static UxJoin on(final String configFile) {
            return new UxJoin(configFile);
        }

        public static UxJoin on() {
            return new UxJoin(null);
        }

        public static UxJoin on(final Class<?> daoCls) {
            return new UxJoin(null).add(daoCls);
        }
    }

    public static class Pool {

        public static UxPool on(final String name) {
            return CACHE.CC_UX_POOL.pick(() -> new UxPool(name), name);
            // return Fn.po?l(Cache.MAP_POOL, name, () -> new UxPool(name));
        }

        public static UxPool on() {
            return new UxPool();
        }
    }

    public static class Job {
        public static UxJob on() {
            return new UxJob();
        }
    }

    public static class Ldap {
        public static UxLdap on(final Integration integration) {
            return CACHE.CC_LDAP.pick(() -> new UxLdap(integration), String.valueOf(integration.hashCode()));
        }
    }

    public static class Timer {
        public static UxTimer on() {
            return new UxTimer();
        }
    }

    /*
     * Here the Jwt class is for lagency system because all following method will be called and existed
     * But the new structure is just like following:
     *
     * 1. Lee -> ( Impl ) by Service Loader
     * 2. The `AuthWall.JWT` will be selected and called API of Lee interface
     * 3. The final result is token ( encoding / decoding ) part
     * 4. The implementation class is defined in `zero-ifx-auth` instead of standard framework
     *
     * If you want to use security module, you should set-up `zero-ifx-auth` infix instead, or
     * you can run zero framework in non-secure mode
     */
    public static class Jwt {

        public static String token(final JsonObject data) {
            final Lee lee = Ut.service(LeeBuiltIn.class);
            return lee.encode(data, AegisItem.configMap(EmSecure.AuthWall.JWT));
        }

        public static JsonObject extract(final String token) {
            final Lee lee = Ut.service(LeeBuiltIn.class);
            return lee.decode(token, AegisItem.configMap(EmSecure.AuthWall.JWT));
        }

        public static JsonObject extract(final JsonObject jwtToken) {
            return extract(jwtToken.getString(KName.ACCESS_TOKEN));
        }
    }

}
