"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
exports.__esModule = true;
var json_schema_merge_allof_1 = __importDefault(require("json-schema-merge-allof"));
var memoizee_1 = __importDefault(require("memoizee"));
var utils_1 = require("./utils");
var sampleDefaults = function (genericSample) {
    return function (schema) {
        return typeof schema["default"] === typeof genericSample ? schema["default"] : genericSample;
    };
};
var primitives = {
    string: sampleDefaults('string'),
    string_email: sampleDefaults('user@example.com'),
    'string_date-time': sampleDefaults(new Date().toISOString()),
    string_date: sampleDefaults(new Date().toISOString().substring(0, 10)),
    'string_YYYY-MM-DD': sampleDefaults(new Date().toISOString().substring(0, 10)),
    string_uuid: sampleDefaults('3fa85f64-5717-4562-b3fc-2c963f66afa6'),
    string_hostname: sampleDefaults('example.com'),
    string_ipv4: sampleDefaults('198.51.100.42'),
    string_ipv6: sampleDefaults('2001:0db8:5b96:0000:0000:426f:8e17:642a'),
    number: sampleDefaults(0),
    number_float: sampleDefaults(0.0),
    integer: sampleDefaults(0),
    boolean: sampleDefaults(true)
};
var primitive = function (schema) {
    schema = (0, utils_1.objectify)(schema);
    var type = schema.type, format = schema.format;
    // @todo add support for if `type` is an array
    var fn = primitives["".concat(type, "_").concat(format)] || primitives[type];
    if ((0, utils_1.isFunc)(fn)) {
        return fn(schema);
    }
    return "Unknown Type: ".concat(schema.type);
};
/**
 * Generate a piece of sample data from a JSON Schema object. If `example` declarations are present
 * they will be utilized, but generally this will generate fake data for the information present in
 * the schema.
 *
 * @param schema JSON Schema to generate a sample for.
 */
function sampleFromSchema(schema, opts) {
    if (opts === void 0) { opts = {}; }
    var objectifySchema = (0, utils_1.objectify)(schema);
    var type = objectifySchema.type;
    var hasPolymorphism = (0, utils_1.usesPolymorphism)(objectifySchema);
    if (hasPolymorphism === 'allOf') {
        try {
            return sampleFromSchema((0, json_schema_merge_allof_1["default"])(objectifySchema, {
                resolvers: {
                    // Ignore any unrecognized OAS-specific keywords that might be present on the schema
                    // (like `xml`).
                    defaultResolver: json_schema_merge_allof_1["default"].options.resolvers.title
                }
            }), opts);
        }
        catch (error) {
            return undefined;
        }
    }
    else if (hasPolymorphism) {
        return sampleFromSchema(objectifySchema[hasPolymorphism][0], opts);
    }
    var example = objectifySchema.example, additionalProperties = objectifySchema.additionalProperties, properties = objectifySchema.properties, items = objectifySchema.items;
    var includeReadOnly = opts.includeReadOnly, includeWriteOnly = opts.includeWriteOnly;
    if (example !== undefined) {
        return (0, utils_1.deeplyStripKey)(example, '$$ref', function (val) {
            // do a couple of quick sanity tests to ensure the value
            // looks like a $$ref that swagger-client generates.
            return typeof val === 'string' && val.indexOf('#') > -1;
        });
    }
    if (!type) {
        if (properties || additionalProperties) {
            type = 'object';
        }
        else if (items) {
            type = 'array';
        }
        else {
            return undefined;
        }
    }
    if (type === 'object') {
        var props = (0, utils_1.objectify)(properties);
        var obj = {};
        // eslint-disable-next-line no-restricted-syntax
        for (var name_1 in props) {
            if (props[name_1] && props[name_1].deprecated) {
                // eslint-disable-next-line no-continue
                continue;
            }
            if (props[name_1] && props[name_1].readOnly && !includeReadOnly) {
                // eslint-disable-next-line no-continue
                continue;
            }
            if (props[name_1] && props[name_1].writeOnly && !includeWriteOnly) {
                // eslint-disable-next-line no-continue
                continue;
            }
            obj[name_1] = sampleFromSchema(props[name_1], opts);
        }
        if (additionalProperties === true) {
            obj.additionalProp = {};
        }
        else if (additionalProperties) {
            var additionalProps = (0, utils_1.objectify)(additionalProperties);
            var additionalPropVal = sampleFromSchema(additionalProps, opts);
            obj.additionalProp = additionalPropVal;
        }
        return obj;
    }
    if (type === 'array') {
        // `items` should always be present on arrays, but if it isn't we should at least do our best
        // to support its absence.
        if (typeof items === 'undefined') {
            return [];
        }
        if (Array.isArray(items.anyOf)) {
            return items.anyOf.map(function (i) { return sampleFromSchema(i, opts); });
        }
        if (Array.isArray(items.oneOf)) {
            return items.oneOf.map(function (i) { return sampleFromSchema(i, opts); });
        }
        return [sampleFromSchema(items, opts)];
    }
    if (schema["enum"]) {
        if (schema["default"]) {
            return schema["default"];
        }
        return (0, utils_1.normalizeArray)(schema["enum"])[0];
    }
    if (type === 'file') {
        return undefined;
    }
    return primitive(schema);
}
exports["default"] = (0, memoizee_1["default"])(sampleFromSchema);
