"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const force_login_1 = require("./force-login");
const React = __importStar(require("react"));
const apollo_cache_inmemory_1 = require("apollo-cache-inmemory");
const apollo_link_http_1 = require("apollo-link-http");
const react_apollo_1 = require("react-apollo");
const apollo_client_1 = __importDefault(require("apollo-client"));
//import { ApolloLink } from 'apollo-link';
const apollo_link_schema_1 = require("apollo-link-schema");
//import fetch from 'node-fetch';
require('es6-promise').polyfill();
require("isomorphic-fetch");
/**
 * we MUST NOT IMPORT CONTEXTs directly, but require them at time of use generally from Infrastructure-Components
 * because this then resolves to node_modules
 */
//import AttachDataLayer from './attach-data-layer';
const types_1 = __importDefault(require("../types"));
const loader_1 = require("../libs/loader");
/**
 *
 */
exports.createServerSideClient = (link) => new apollo_client_1.default({
    //ssrMode: true,
    // Remember that this is the interface the SSR server will use to connect to the
    // API server, so we need to ensure it isn't firewalled, etc
    link: link,
    cache: new apollo_cache_inmemory_1.InMemoryCache(),
});
/**
 * Puts the preloaded state in a string that can be put into a <script>-tag
 * Also puts the path to the GraphQL-Endpoint there
 *
 * @param preloadedState the state
 */
// here, we can also add stringified (json) data about the dataLayer, e.g. Schema
// it works without ... window.__SCHEMA__ = \`${schema}\`
exports.importEnvironmentVariables = (preloadedState, url) => {
    return `window.__APOLLO_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\\u003c')};
window.__GRAPHQL__ = "${url}"`;
};
/**
 * Function to be used on the client side to connect the client app with the dehydrated state from the server
 * to be rehydrated on the client
 *
 * Note: Queries and Mutations work with POST-requests, if you want query requests to work with GET,
 * set `useGETForQueries` to true. Mutations always use POST
 *
 * @param app the ReactApp to connect with the DataLayer
 */
exports.hydrateFromDataLayer = (app, dataLayer) => {
    const AttachDataLayer = require("infrastructure-components").AttachDataLayer;
    console.log("hydration, dataLayer: ", dataLayer);
    var preloadedState = {};
    if (typeof window != 'undefined' && window.__APOLLO_STATE__) {
        preloadedState = window.__APOLLO_STATE__;
        delete window.__APOLLO_STATE__;
    }
    console.log("uri: ", window.__GRAPHQL__);
    const client = new apollo_client_1.default({
        cache: new apollo_cache_inmemory_1.InMemoryCache().restore(preloadedState),
        link: apollo_link_http_1.createHttpLink({
            uri: window.__GRAPHQL__,
            credentials: 'include',
        })
    });
    console.log("local client: ", client);
    return React.createElement(react_apollo_1.ApolloProvider, { client: client },
        React.createElement(react_apollo_1.ApolloConsumer, null, client => React.createElement(AttachDataLayer, { apolloClient: client, dataLayer: dataLayer }, app)));
};
/**
 * Function to be used on server side that connects a ReactApp (jsx) with a GraphQL-Layer hosted on AWS Lambda/DynamoDb
 * Creates the server side store
 *
 * Fetch-library is required , see [this](https://github.com/apollographql/apollo-client/issues/3578)
 * see [fetch polyfill](https://www.apollographql.com/docs/link/links/http.html#options)
 *
 * @param app the ReactApp to connect with the DataLayer
 * @schema specifies the schema to connect the store with, if undefined: use the uri (via network). see [[UseSchemaLinkSpec]]
 */
exports.connectWithDataLayer = (dataLayerId, request) => (app) => __awaiter(this, void 0, void 0, function* () {
    /**
     * we MUST NOT IMPORT CONTEXTs directly, but require them at time of use generally from Infrastructure-Components
     * because this then resolves to node_modules
     */
    const AttachDataLayer = require("infrastructure-components").AttachDataLayer;
    //console.log("AttachDataLayer: ", AttachDataLayer)
    //console.log("connectWithDataLayer: ", dataLayerId);
    // load the IsomorphicComponent
    // we must load it directly from the module here, to enable the aliad of the config_file_path
    const isoConfig = loader_1.loadConfigurationFromModule(require('__CONFIG_FILE_PATH__'), loader_1.INFRASTRUCTURE_MODES.RUNTIME);
    // with a clientApp, we can check whether it is wrapped into a datalayer
    const dataLayer = loader_1.extractObject(isoConfig, types_1.default.INFRASTRUCTURE_TYPE_COMPONENT, dataLayerId);
    //console.log("dataLayer: ", dataLayer);
    return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
        const awsGraphqlFetch = (uri, options) => {
            console.log("fetch: ", uri, options);
            //options.headers["Authorization"] = token;
            return fetch(uri, options);
        };
        //console.log("STAGE_PATH: ", process.env.STAGE_PATH);
        //console.log("DOMAIN_ENABLED: ", process.env.DOMAIN_ENABLED);
        // TODO take these variables, esp. GraphQl-Path from the component rather than from the env-variables,
        // because, there might be more than one DataLayers!
        // when we have a valid stage_path or a domain, e.g. https://xxxxxxxxxxx.execute-api.eu-west-1.amazonaws.com/dev/query',
        /*const graphqlUrl = (
            process.env.STAGE_PATH !== undefined && process.env.STAGE_PATH !== "undefined" && process.env.STAGE_PATH.length > 0
        ) || process.env.DOMAIN_ENABLED === "true" ?
            // then use the path
        (process.env.DOMAIN_ENABLED !== undefined && process.env.DOMAIN_ENABLED === "true" &&
        process.env.DOMAIN_NAME !== undefined && process.env.DOMAIN_NAME !== undefined ?
            "https://"+process.env.DOMAIN_NAME : process.env.DOMAIN_URL) + "/"+process.env.GRAPHQL_PATH :
            // else mock the endpoint - use the dev-endpoint
            "https://yfse1b9v0m.execute-api.eu-west-1.amazonaws.com/dev/query"; // undefined; //
        //
            // TODO set undefined or a Mock or the Dev-Address here

           */
        const graphqlUrl = "https://yfse1b9v0m.execute-api.eu-west-1.amazonaws.com/dev/query"; // process.env.DOMAIN_URL + "/"+process.env.GRAPHQL_PATH;
        console.log("graphqlUrl: ", graphqlUrl);
        //console.log("schema: ", schema);
        const client = new apollo_client_1.default({
            ssrMode: true,
            //ssrForceFetchDelay: 100,
            cache: new apollo_cache_inmemory_1.InMemoryCache(),
            /* instead of the createHttpLink, we use SchemaLink({ schema }) to void network traffic, for both endpoints
             * implements [[UseSchemaLinkSpec]]
             *
             */
            link: new apollo_link_schema_1.SchemaLink({
                schema: dataLayer.getSchema(true),
                context: {
                    // when we have a userId, put it into the context so thatwe have it through ssr, too.
                    userId: force_login_1.getUserId(request)
                }
            })
            /*link: createHttpLink({
                uri: graphqlUrl,
                fetch: awsGraphqlFetch,
                credentials: 'include',
            }),*/
        });
        console.log("client: ", client);
        const connectedApp = React.createElement(react_apollo_1.ApolloProvider, { client: client },
            React.createElement(react_apollo_1.ApolloConsumer, null, client => React.createElement(AttachDataLayer, { apolloClient: client, dataLayer: dataLayer }, app)));
        console.log("connectedApp: ", connectedApp);
        try {
            //.catch((err) => console.log("err: ", err))
            yield react_apollo_1.getDataFromTree(connectedApp).then(() => resolve({ connectedApp: connectedApp, getState: () => {
                    console.log("time to resolve");
                    const data = client.extract();
                    console.log("data: ", data);
                    return exports.importEnvironmentVariables(data, graphqlUrl.trim());
                } }));
        }
        catch (error) {
            console.log("error: ", error);
        }
    }));
});
//# sourceMappingURL=datalayer-integration.js.map