import { deepCloneWith, isIterableObject, REMOVE } from '@takeshape/util';
import defaults from 'lodash/fp/defaults.js';
const inputSchemaCache = new Map();
function getInputSchemaCache(options) {
    // Ensure key order does not invalidate the cache
    const key = JSON.stringify(options, Object.keys(options).sort());
    let cache = inputSchemaCache.get(key);
    if (!cache) {
        cache = new WeakMap();
        inputSchemaCache.set(key, cache);
    }
    return cache;
}
/**
 * Convert all output properties in the schema to be input properties,
 * For an update, remove `required` and `default` fields as well.
 */
export function createInputSchema(schema, options = {}) {
    const inputSchemaCache = getInputSchemaCache(defaults({ isUpdate: false }, options));
    let rewrittenSchema = inputSchemaCache.get(schema);
    if (rewrittenSchema) {
        return rewrittenSchema;
    }
    rewrittenSchema = deepCloneWith(schema, (value, key, parent, clone) => {
        // Remove required
        if (options.isUpdate && key === 'required' && Array.isArray(value) && value.length) {
            return REMOVE;
        }
        // Remove default
        if (options.isUpdate &&
            key === 'default' &&
            value !== undefined &&
            isIterableObject(parent) &&
            parent.type !== undefined) {
            return REMOVE;
        }
        if (isIterableObject(value) && value.type === 'object' && isIterableObject(value.properties)) {
            const properties = {};
            for (const [key, prop] of Object.entries(value.properties)) {
                if (isIterableObject(prop) && (!prop['@resolver'] || prop['@input'])) {
                    properties[key] = clone(prop, key, value);
                }
            }
            let required;
            if (!options.isUpdate && Array.isArray(value.required)) {
                required = value.required.filter((key) => Boolean(properties[key]));
            }
            return {
                ...value,
                properties,
                required
            };
        }
        if (isIterableObject(value) && isIterableObject(value['@input'])) {
            const { '@input': input, '@l10n': l10n, '@syncLocaleStructure': syncLocaleStructure, '@mapping': mapping, title, ...output } = value;
            return {
                ...clone(input, '@input', value),
                title,
                '@l10n': l10n,
                '@syncLocaleStructure': syncLocaleStructure,
                '@mapping': mapping,
                '@output': output
            };
        }
    });
    inputSchemaCache.set(schema, rewrittenSchema);
    return rewrittenSchema;
}
