"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());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InputData = exports.JSONInput = void 0;
exports.jsonInputForTargetLanguage = jsonInputForTargetLanguage;
const collection_utils_1 = require("collection-utils");
const Description_js_1 = require("../attributes/Description.js");
const TypeNames_js_1 = require("../attributes/TypeNames.js");
const All_js_1 = require("../language/All.js");
const Messages_js_1 = require("../Messages.js");
const Support_js_1 = require("../support/Support.js");
const CompressedJSON_js_1 = require("./CompressedJSON.js");
const Inference_js_1 = require("./Inference.js");
function messageParseError(name, description, e) {
    return (0, Messages_js_1.messageError)("MiscJSONParseError", {
        description: (0, collection_utils_1.withDefault)(description, "input"),
        address: name,
        message: (0, Support_js_1.errorMessage)(e),
    });
}
class JSONInput {
    constructor(_compressedJSON) {
        this._compressedJSON = _compressedJSON;
        this.kind = "json";
        this.needIR = true;
        this.needSchemaProcessing = false;
        this._topLevels = new Map();
    }
    addSample(topLevelName, sample) {
        let topLevel = this._topLevels.get(topLevelName);
        if (topLevel === undefined) {
            topLevel = { samples: [], description: undefined };
            this._topLevels.set(topLevelName, topLevel);
        }
        topLevel.samples.push(sample);
    }
    setDescription(topLevelName, description) {
        const topLevel = this._topLevels.get(topLevelName);
        if (topLevel === undefined) {
            (0, Support_js_1.panic)("Trying to set description for a top-level that doesn't exist");
        }
        topLevel.description = description;
    }
    addSamples(name, values, description) {
        for (const value of values) {
            this.addSample(name, value);
            if (description !== undefined) {
                this.setDescription(name, description);
            }
        }
    }
    addSource(source) {
        return __awaiter(this, void 0, void 0, function* () {
            const { name, samples, description } = source;
            try {
                const values = yield (0, collection_utils_1.arrayMapSync)(samples, (s) => __awaiter(this, void 0, void 0, function* () { return yield this._compressedJSON.parse(s); }));
                this.addSamples(name, values, description);
            }
            catch (e) {
                return messageParseError(name, description, e);
            }
        });
    }
    addSourceSync(source) {
        const { name, samples, description } = source;
        try {
            const values = samples.map((s) => this._compressedJSON.parseSync(s));
            this.addSamples(name, values, description);
        }
        catch (e) {
            messageParseError(name, description, e);
        }
    }
    singleStringSchemaSource() {
        return undefined;
    }
    addTypes(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels) {
        return __awaiter(this, void 0, void 0, function* () {
            this.addTypesSync(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels);
        });
    }
    addTypesSync(_ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels) {
        const inference = new Inference_js_1.TypeInference(this._compressedJSON, typeBuilder, inferMaps, inferEnums);
        for (const [name, { samples, description }] of this._topLevels) {
            const tref = inference.inferTopLevelType((0, TypeNames_js_1.makeNamesTypeAttributes)(name, false), samples, fixedTopLevels);
            typeBuilder.addTopLevel(name, tref);
            if (description !== undefined) {
                const attributes = Description_js_1.descriptionTypeAttributeKind.makeAttributes(new Set([description]));
                typeBuilder.addAttributes(tref, attributes);
            }
        }
    }
}
exports.JSONInput = JSONInput;
function jsonInputForTargetLanguage(targetLanguage, languages, handleJSONRefs = false) {
    if (typeof targetLanguage === "string") {
        targetLanguage = (0, Support_js_1.defined)((0, All_js_1.languageNamed)(targetLanguage, languages));
    }
    const compressedJSON = new CompressedJSON_js_1.CompressedJSONFromString(targetLanguage.dateTimeRecognizer, handleJSONRefs);
    return new JSONInput(compressedJSON);
}
class InputData {
    constructor() {
        // FIXME: Make into a Map, indexed by kind.
        // biome-ignore lint/suspicious/noExplicitAny: <explanation>
        this._inputs = new Set();
    }
    addInput(input) {
        this._inputs = this._inputs.add(input);
    }
    getOrAddInput(kind, makeInput) {
        let input = (0, collection_utils_1.iterableFind)(this._inputs, (i) => i.kind === kind);
        if (input === undefined) {
            input = makeInput();
            this.addInput(input);
        }
        return input;
    }
    addSource(kind, source, makeInput) {
        return __awaiter(this, void 0, void 0, function* () {
            const input = this.getOrAddInput(kind, makeInput);
            yield input.addSource(source);
        });
    }
    addSourceSync(kind, source, makeInput) {
        const input = this.getOrAddInput(kind, makeInput);
        input.addSourceSync(source);
    }
    addTypes(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels) {
        return __awaiter(this, void 0, void 0, function* () {
            for (const input of this._inputs) {
                yield input.addTypes(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels);
            }
        });
    }
    addTypesSync(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels) {
        for (const input of this._inputs) {
            input.addTypesSync(ctx, typeBuilder, inferMaps, inferEnums, fixedTopLevels);
        }
    }
    get needIR() {
        return (0, collection_utils_1.iterableSome)(this._inputs, (i) => i.needIR);
    }
    get needSchemaProcessing() {
        return (0, collection_utils_1.iterableSome)(this._inputs, (i) => i.needSchemaProcessing);
    }
    singleStringSchemaSource() {
        const schemaStrings = (0, collection_utils_1.setFilterMap)(this._inputs, (i) => i.singleStringSchemaSource());
        if (schemaStrings.size > 1) {
            return (0, Support_js_1.panic)("We have more than one input with a string schema source");
        }
        return (0, collection_utils_1.iterableFirst)(schemaStrings);
    }
}
exports.InputData = InputData;
