"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const graphql_1 = require("graphql");
const types_1 = __importDefault(require("../types"));
const libs_1 = require("../libs");
const entry_component_1 = require("./entry-component");
const datalayer_libs_1 = require("./datalayer-libs");
exports.DATALAYER_INSTANCE_TYPE = "DataLayerComponent";
;
/**
 * identifies a component as a DataLayer
 *
 * @param component to be tested
 */
function isDataLayer(component) {
    return component !== undefined && component.instanceType === exports.DATALAYER_INSTANCE_TYPE;
}
exports.isDataLayer = isDataLayer;
;
exports.default = (props) => {
    const componentProps = {
        infrastructureType: types_1.default.INFRASTRUCTURE_TYPE_COMPONENT,
        instanceType: exports.DATALAYER_INSTANCE_TYPE,
        instanceId: props.id
    };
    //const listEntities = getChildrenArray(props).filter(child => isEntity(child));
    //const entries = getChildrenArray(props).filter(child => isEntry(child));
    const entries = libs_1.findComponentRecursively(props.children, entry_component_1.isEntry);
    const complementedProps = {};
    /**
     * create the
     * @type {{queries: {}, mutations: {}}}
     */
    const datalayerProps = {
        entries: entries,
        mutations: (resolveWithData) => entries.reduce((result, entry) => {
            result[entry.getSetMutationName()] = {
                args: entry.createEntryArgs(),
                type: entry.createEntryType("set_"),
                resolve: (source, args, context, info) => {
                    if (!resolveWithData) {
                        return entry.id;
                    }
                    //console.log("resolve: ", resolveWithData, source, context, info, args);
                    // This context gets the data from the context put into the <Query/> or Mutation...
                    //console.log("context: ", context);
                    const result = entry.setEntry(args, context, process.env.TABLE_NAME, complementedProps["isOffline"]);
                    //console.log("result: ", result);
                    return result;
                }
            };
            result[entry.getDeleteMutationName()] = {
                args: entry.createEntryArgs(),
                type: entry.createEntryType("delete_"),
                resolve: (source, args, context, info) => {
                    if (!resolveWithData) {
                        return entry.id;
                    }
                    //console.log("resolve: ", resolveWithData, source, context, info, args);
                    // This context gets the data from the context put into the <Query/> or Mutation...
                    //console.log("context: ", context);
                    const result = entry.deleteEntry(args, context, process.env.TABLE_NAME, complementedProps["isOffline"]);
                    //console.log("result: ", result);
                    return result;
                }
            };
            //console.log("mutation definition: ", result["set_"+entry.id]);
            return result;
        }, {}),
        queries: (resolveWithData) => entries.reduce((result, entry) => {
            const listType = entry.createEntryType("list_");
            const getType = entry.createEntryType("get_");
            //console.log("listType: ", listType);
            //console.log("dl-comp-props: ", complementedProps["isOffline"], datalayerProps["isOffline"])
            // list all the items, specifying the primaryKey
            const inputArgs = {};
            inputArgs[entry.primaryKey] = { name: entry.primaryKey, type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) };
            result[entry.getPrimaryListQueryName()] = {
                args: inputArgs,
                type: resolveWithData ? new graphql_1.GraphQLList(listType) : listType,
                resolve: (source, args, context, info) => {
                    //console.log("resolve list: ", resolveWithData, source, args, context, complementedProps["isOffline"]);
                    if (!resolveWithData) {
                        return entry.id;
                    }
                    return entry.listEntries(args, context, process.env.TABLE_NAME, "pk", complementedProps["isOffline"]);
                }
            };
            // list all the items, specifying the RANGE
            const inputRangeArgs = {};
            inputRangeArgs[entry.rangeKey] = { name: entry.rangeKey, type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) };
            result[entry.getRangeListQueryName()] = {
                args: inputRangeArgs,
                type: resolveWithData ? new graphql_1.GraphQLList(listType) : listType,
                resolve: (source, args, context, info) => {
                    //console.log("resolve: ", resolveWithData, source, args, context, complementedProps["isOffline"]);
                    if (!resolveWithData) {
                        return entry.id;
                    }
                    return entry.listEntries(args, context, process.env.TABLE_NAME, "sk", complementedProps["isOffline"]);
                }
            };
            const inputArgsGet = {};
            if (entry.primaryKey) {
                inputArgsGet[entry.primaryKey] = { name: entry.primaryKey, type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) };
            }
            if (entry.rangeKey) {
                inputArgsGet[entry.rangeKey] = { name: entry.rangeKey, type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) };
            }
            result[entry.getGetQueryName()] = {
                args: inputArgsGet,
                type: getType,
                resolve: (source, args, context, info) => {
                    //console.log("resolve: ", resolveWithData, source, args, context);
                    if (!resolveWithData) {
                        return entry.id;
                    }
                    return entry.getEntry(args, context, process.env.TABLE_NAME, complementedProps["isOffline"]);
                }
            };
            const scanRangeArgs = {};
            scanRangeArgs[`start_${entry.rangeKey}`] = { name: `start_${entry.rangeKey}`, type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) };
            scanRangeArgs[`end_${entry.rangeKey}`] = { name: `end_${entry.rangeKey}`, type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) };
            // scan the table
            result[entry.getRangeScanName()] = {
                args: scanRangeArgs,
                type: resolveWithData ? new graphql_1.GraphQLList(listType) : listType,
                resolve: (source, args, context, info) => {
                    //console.log("resolve scan: ", resolveWithData, source, args, context);
                    if (!resolveWithData) {
                        return entry.id;
                    }
                    return entry.scan(args, context, process.env.TABLE_NAME, "sk", complementedProps["isOffline"]);
                }
            };
            const scanPrimaryArgs = {};
            scanPrimaryArgs[`start_${entry.primaryKey}`] = { name: `start_${entry.primaryKey}`, type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) };
            scanPrimaryArgs[`end_${entry.primaryKey}`] = { name: `end_${entry.primaryKey}`, type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) };
            // scan the table
            result[entry.getPrimaryScanName()] = {
                args: scanPrimaryArgs,
                type: resolveWithData ? new graphql_1.GraphQLList(listType) : listType,
                resolve: (source, args, context, info) => {
                    //console.log("resolve scan: ", resolveWithData, source, args, context);
                    if (!resolveWithData) {
                        return entry.id;
                    }
                    return entry.scan(args, context, process.env.TABLE_NAME, "pk", complementedProps["isOffline"]);
                }
            };
            const scanAllArgs = { scanall: { name: "scanall", type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLString) } };
            // scan the table
            result[entry.getScanName()] = {
                args: scanAllArgs,
                type: resolveWithData ? new graphql_1.GraphQLList(listType) : listType,
                resolve: (source, args, context, info) => {
                    //console.log("resolve scan: ", resolveWithData, source, args, context);
                    if (!resolveWithData) {
                        return entry.id;
                    }
                    return entry.scan(args, context, process.env.TABLE_NAME, "pk", complementedProps["isOffline"]);
                }
            };
            return result;
        }, {}),
        /*
        getEntryDataFields: (entryId) => {
            const entry = entries.find(entry => entry.id === entryId);
            if (entry !== undefined) {
                return entry.createEntryFields()
            };

            console.warn("could not find entry: ",entryId);
            return {};
        },*/
        // TODO forward this request to the Entry and let the entry handle the whole request!
        getEntryListQuery: (entryId, dictKey) => {
            const entry = entries.find(entry => entry.id === entryId);
            if (entry !== undefined) {
                return entry.getEntryListQuery(dictKey);
            }
            ;
            console.warn("could not find entry: ", entryId);
            return {};
            /*
             const fields = datalayerProps.getEntryDataFields(entryId);
             //console.log("fields: ", fields);

             return getEntryListQuery(
                 entryId,
                 dictKey,
                 fields
             );*/
        },
        getEntryQuery: (entryId, dictKey) => {
            const entry = entries.find(entry => entry.id === entryId);
            if (entry !== undefined) {
                return entry.getEntryQuery(dictKey);
            }
            ;
            console.warn("could not find entry: ", entryId);
            return {};
        },
        getEntryScanQuery: (entryId, dictKey) => {
            const entry = entries.find(entry => entry.id === entryId);
            if (entry !== undefined) {
                return entry.getEntryScanQuery(dictKey);
            }
            ;
            console.warn("could not find entry: ", entryId);
            return {};
        },
        setEntryMutation: (entryId, values) => {
            const entry = entries.find(entry => entry.id === entryId);
            if (entry !== undefined) {
                return entry.setEntryMutation(values);
            }
            ;
            console.warn("could not find entry: ", entryId);
            return {};
        },
        deleteEntryMutation: (entryId, values) => {
            const entry = entries.find(entry => entry.id === entryId);
            if (entry !== undefined) {
                return entry.deleteEntryMutation(values);
            }
            ;
            console.warn("could not find entry: ", entryId);
            return {};
        },
        updateEntryQuery: (entryId, fDictKey) => {
            //console.log("updateEntryQuery: ", entryId);
            return {
                entryId: entryId,
                getEntryQuery: () => datalayerProps.getEntryQuery(entryId, fDictKey({})),
                setEntryMutation: (oldData) => datalayerProps.setEntryMutation(entryId, fDictKey(oldData)),
            };
        },
        setClient: (client) => {
            complementedProps["client"] = client;
        },
        setOffline: (offline) => {
            complementedProps["isOffline"] = offline;
            // provide offline flags to children (esp. to Auth)
            libs_1.findComponentRecursively(props.children, (child) => child.setIsOffline !== undefined).forEach(child => {
                child.setIsOffline(offline);
            });
        }
    };
    const schemaProps = {
        getSchema: (resolveWithData) => new graphql_1.GraphQLSchema({
            query: new graphql_1.GraphQLObjectType({
                name: 'RootQueryType',
                fields: datalayerProps.queries(resolveWithData)
            }), mutation: new graphql_1.GraphQLObjectType({
                name: 'RootMutationType',
                fields: datalayerProps.mutations(resolveWithData)
            })
        })
    };
    // we need to provide the DataLayerId to webApps, these may be anywhere in the tree, not
    // only direct children. So rather than mapping the children, we need to change them
    libs_1.findComponentRecursively(props.children, (child) => child.setDataLayerId !== undefined).forEach(child => {
        child.setDataLayerId(props.id);
    });
    libs_1.findComponentRecursively(props.children, (child) => child.setStoreData !== undefined).forEach(child => {
        child.setStoreData(function (pkEntity, pkVal, skEntity, skVal, jsonData) {
            return __awaiter(this, void 0, void 0, function* () {
                return yield datalayer_libs_1.setEntry(process.env.TABLE_NAME, //"code-architect-dev-data-layer",
                pkEntity, // schema.Entry.ENTITY, //pkEntity
                pkVal, // pkId
                skEntity, //schema.Data.ENTITY, // skEntity
                skVal, // skId
                jsonData, // jsonData
                complementedProps["isOffline"]);
            });
        });
        child.setGetData(function (pkEntity, pkVal, skEntity, skVal) {
            return __awaiter(this, void 0, void 0, function* () {
                if (pkVal !== undefined) {
                    return yield datalayer_libs_1.ddbGetEntry(process.env.TABLE_NAME, //"code-architect-dev-data-layer",
                    pkEntity, // schema.Entry.ENTITY, //pkEntity
                    pkVal, // pkId
                    skEntity, //schema.Data.ENTITY, // skEntity
                    skVal, // skId
                    complementedProps["isOffline"]);
                }
                else {
                    return datalayer_libs_1.ddbListEntries(process.env.TABLE_NAME, //tableName
                    "sk", //key
                    skEntity, // entity
                    skVal, //value,
                    pkEntity, // rangeEntity
                    complementedProps["isOffline"]);
                }
            });
        });
    });
    return Object.assign({}, props, componentProps, datalayerProps, schemaProps, complementedProps);
};
//# sourceMappingURL=datalayer-component.js.map