"use strict";
var tslib_1 = require("tslib");
var pg_1 = require("pg");
var pg_connection_string_1 = require("pg-connection-string");
var events_1 = require("events");
var postgraphile_core_1 = require("postgraphile-core");
var createPostGraphQLHttpRequestHandler_1 = require("./http/createPostGraphQLHttpRequestHandler");
var exportPostGraphQLSchema_1 = require("./schema/exportPostGraphQLSchema");
function postgraphql(poolOrConfig, schemaOrOptions, maybeOptions) {
    var schema;
    var options;
    // If the second argument is undefined, use defaults for both `schema` and
    // `options`.
    if (typeof schemaOrOptions === 'undefined') {
        schema = 'public';
        options = {};
    }
    else if (typeof schemaOrOptions === 'string' || Array.isArray(schemaOrOptions)) {
        schema = schemaOrOptions;
        options = maybeOptions || {};
    }
    else {
        schema = 'public';
        options = schemaOrOptions;
    }
    // Check for a jwtSecret without a jwtPgTypeIdentifier
    // a secret without a token identifier prevents JWT creation
    if (options.jwtSecret && !options.jwtPgTypeIdentifier) {
        // tslint:disable-next-line no-console
        console.warn('WARNING: jwtSecret provided, however jwtPgTypeIdentifier (token identifier) not provided.');
    }
    // Creates the Postgres schemas array.
    var pgSchemas = Array.isArray(schema) ? schema : [schema];
    // Do some things with `poolOrConfig` so that in the end, we actually get a
    // Postgres pool.
    var pgPool = 
    // If it is already a `Pool`, just use it.
    poolOrConfig instanceof pg_1.Pool || quacksLikePgPool(poolOrConfig)
        ? poolOrConfig
        : new pg_1.Pool(typeof poolOrConfig === 'string'
            ? pg_connection_string_1.parse(poolOrConfig)
            : poolOrConfig || {});
    var _emitter = new events_1.EventEmitter();
    // Creates a promise which will resolve to a GraphQL schema. Connects a
    // client from our pool to introspect the database.
    //
    // This is not a constant because when we are in watch mode, we want to swap
    // out the `gqlSchema`.
    var gqlSchema;
    var gqlSchemaPromise = createGqlSchema();
    // Finally create our Http request handler using our options, the Postgres
    // pool, and GraphQL schema. Return the final result.
    return createPostGraphQLHttpRequestHandler_1.default(Object.assign({}, options, {
        getGqlSchema: function () { return Promise.resolve(gqlSchema || gqlSchemaPromise); },
        pgPool: pgPool,
        _emitter: _emitter,
    }));
    function createGqlSchema() {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var error_1;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 5, , 6]);
                        if (!options.watchPg) return [3 /*break*/, 2];
                        return [4 /*yield*/, postgraphile_core_1.watchPostGraphQLSchema(pgPool, pgSchemas, options, function (newSchema) {
                                gqlSchema = newSchema;
                                _emitter.emit('schemas:changed');
                                exportGqlSchema(gqlSchema);
                            })];
                    case 1:
                        _a.sent();
                        if (!gqlSchema) {
                            throw new Error('Consistency error: watchPostGraphQLSchema promises to call the callback before the promise resolves; but this hasn\'t happened');
                        }
                        return [3 /*break*/, 4];
                    case 2: return [4 /*yield*/, postgraphile_core_1.createPostGraphQLSchema(pgPool, pgSchemas, options)];
                    case 3:
                        gqlSchema = _a.sent();
                        exportGqlSchema(gqlSchema);
                        _a.label = 4;
                    case 4: return [2 /*return*/, gqlSchema];
                    case 5:
                        error_1 = _a.sent();
                        return [2 /*return*/, handleFatalError(error_1)];
                    case 6: return [2 /*return*/];
                }
            });
        });
    }
    function exportGqlSchema(newGqlSchema) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var error_2;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 2, , 3]);
                        return [4 /*yield*/, exportPostGraphQLSchema_1.default(newGqlSchema, options)];
                    case 1:
                        _a.sent();
                        return [3 /*break*/, 3];
                    case 2:
                        error_2 = _a.sent();
                        handleFatalError(error_2);
                        return [3 /*break*/, 3];
                    case 3: return [2 /*return*/];
                }
            });
        });
    }
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = postgraphql;
function handleFatalError(error) {
    process.stderr.write(error.stack + "\n"); // console.error fails under the tests
    process.exit(1);
    // `process.exit` will mean all code below it will never get called.
    // However, we need to return a value with type `never` here for
    // TypeScript.
    return null;
}
function constructorName(obj) {
    return obj && typeof obj.constructor === 'function' && obj.constructor.name && String(obj.constructor.name) || null;
}
// tslint:disable-next-line no-any
function quacksLikePgPool(pgConfig) {
    // A diagnosis of exclusion
    if (!pgConfig || typeof pgConfig !== 'object')
        return false;
    if (constructorName(pgConfig) !== 'Pool')
        return false;
    if (!pgConfig['Client'])
        return false;
    if (!pgConfig['options'])
        return false;
    if (typeof pgConfig['connect'] !== 'function')
        return false;
    if (typeof pgConfig['end'] !== 'function')
        return false;
    if (typeof pgConfig['query'] !== 'function')
        return false;
    return true;
}
//# sourceMappingURL=data:application/json;base64, 