"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generator = exports.generatorId = void 0;
const Generator = __importStar(require("@postxl/generator"));
const utils_1 = require("@postxl/utils");
const backend_core_1 = require("../backend-core");
const base_1 = require("../base");
const frontend_core_1 = require("../frontend-core");
const discriminated_union_generator_1 = require("./generators/discriminated-union.generator");
const dto_types_generator_1 = require("./generators/dto-types.generator");
const enum_type_generator_1 = require("./generators/enum-type.generator");
const model_type_generator_1 = require("./generators/model-type.generator");
const models_generator_1 = require("./generators/models.generator");
exports.generatorId = Generator.toGeneratorInterfaceId('types');
const moduleName = Generator.toBackendModuleName('types');
const location = Generator.toBackendModuleLocation(`@${moduleName}`);
exports.generator = {
    id: exports.generatorId,
    requires: [backend_core_1.backendGeneratorId, base_1.baseGeneratorId, frontend_core_1.frontendGeneratorId],
    register: (context) => {
        // Register with backend module
        const typesModule = { name: moduleName, hasIndex: true };
        context.backend.modules.push(typesModule);
        // Register with frontend module
        context.frontend.tsConfigReferences.set(moduleName, {
            name: moduleName,
            filePath: Generator.toFilePath('../backend/libs/types/src'),
            hasIndex: true,
        });
        let user;
        const models = new Map();
        for (const [modelName, model] of context.models) {
            const modelWithTypes = registerModel(model);
            models.set(modelName, modelWithTypes);
            if (modelName === 'User') {
                user = modelWithTypes.types;
            }
        }
        if (!user) {
            throw new Error(`Schema does not contain a User model! Only found these names: ${[...context.models.keys()].join(', ')}`);
        }
        const enums = new Map();
        for (const [enumName, enum_] of context.enums) {
            enums.set(enumName, registerEnumTypes(enum_));
        }
        const types = {
            location,
            modelNames: {
                name: Generator.toTypeName('ModelName'),
                location,
            },
            dto: {
                create: {
                    name: Generator.toTypeName('CreateDto'),
                    location,
                },
                update: {
                    name: Generator.toTypeName('UpdateDto'),
                    location,
                },
                upsert: {
                    name: Generator.toTypeName('UpsertDto'),
                    location,
                },
                genericModel: {
                    name: Generator.toTypeName('GenericModel'),
                    location,
                },
                idType: {
                    name: Generator.toTypeName('IdType'),
                    location,
                },
            },
            user,
        };
        return {
            ...context,
            models,
            enums,
            types,
        };
    },
    generate: async (context) => {
        const vfsSrc = new Generator.VirtualFileSystem();
        const index = new Generator.IndexGenerator(Generator.toFilePath('./index')).add(Generator.toFilePath(`./dto.types`));
        for (const model of context.models.values()) {
            vfsSrc.write(model.types._filePath + '.ts', (0, model_type_generator_1.generateModel)({ model, context }));
            index.add(model.types._filePath);
            for (const du of model.types.discriminatedUnions.values()) {
                vfsSrc.write(du.type._filePath + '.ts', (0, discriminated_union_generator_1.generateDiscriminatedUnion)({ model, discriminatedUnion: du, context }));
                index.add(du.type._filePath);
            }
        }
        for (const enum_ of context.enums.values()) {
            vfsSrc.write(enum_.types._filePath + '.ts', (0, enum_type_generator_1.generateEnum)(enum_));
            index.add(enum_.types._filePath);
        }
        vfsSrc.write('./models.ts', (0, models_generator_1.generateModels)(context));
        index.add(Generator.toFilePath('./models'));
        vfsSrc.write('/index.ts', index.generate());
        vfsSrc.write('/dto.types.ts', (0, dto_types_generator_1.generateDtoTypes)(context.types));
        const vfs = new Generator.VirtualFileSystem();
        vfs.insertFromVfs({ targetPath: '/src', vfs: vfsSrc });
        vfs.write('/tsconfig.lib.json', Generator.generateTsConfig('types'));
        context.vfs.insertFromVfs({ targetPath: 'backend/libs/types', vfs });
        return Promise.resolve(context); // NOSONAR
    },
};
function registerModel(model) {
    const { PascalCase, camelCase } = model._conjugated;
    const location = Generator.toBackendModuleLocation(`@types`);
    const discriminatedUnions = registerDiscriminatedUnions(model);
    const types = {
        name: Generator.toTypeName(`${PascalCase}`),
        location,
        id: {
            name: Generator.toTypeName(`${PascalCase}Id`),
            location,
            unbrandedType: Generator.toTypeName(model.idField.unbrandedTypeName),
            toBranded: {
                name: Generator.toFunctionName(`to${PascalCase}Id`),
                location,
            },
            decoder: {
                name: Generator.toFunctionName(`z${PascalCase}Id`),
                location,
            },
        },
        dto: {
            create: { name: Generator.toTypeName(`Create${PascalCase}`), location },
            update: { name: Generator.toTypeName(`Update${PascalCase}`), location },
            upsert: { name: Generator.toTypeName(`Upsert${PascalCase}`), location },
            clone: { name: Generator.toTypeName(`Clone${PascalCase}`), location },
        },
        scopeName: Generator.toConstantValue(PascalCase),
        discriminatedUnions,
        _filePath: Generator.toFilePath(`./${camelCase}.types`),
    };
    return {
        ...model,
        types,
    };
}
function registerDiscriminatedUnions(model) {
    const result = new Map();
    for (const field of model.fields.values()) {
        if (field.kind !== 'discriminatedUnion') {
            continue;
        }
        const memberTypes = new Map();
        for (const [discriminator, member] of field.members) {
            const memberTypeName = Generator.toTypeName(`${field.type}_${(0, utils_1.toPascalCase)(member.type)}`);
            memberTypes.set(discriminator, {
                name: memberTypeName,
                location,
            });
        }
        const type = {
            type: {
                name: Generator.toTypeName(field.type),
                location,
                _filePath: Generator.toFilePath(`./${field.name}.discriminatedUnion.types`),
            },
            field,
            discriminatorType: {
                name: Generator.toTypeName(`${(0, utils_1.toPascalCase)(field.name)}${(0, utils_1.toPascalCase)(field.discriminatorFieldName)}`),
                location,
            },
            memberTypes,
        };
        result.set(field.name, type);
    }
    return result;
}
function registerEnumTypes(enum_) {
    return {
        ...enum_,
        types: {
            name: Generator.toTypeName(enum_._conjugated.PascalCase),
            location,
            constName: Generator.toVariableName(enum_._conjugated.PascalCase),
            memberArrayName: Generator.toVariableName(`${enum_._conjugated.camelCase}Members`),
            _filePath: Generator.toFilePath(`./${enum_._conjugated.camelCase}.enum.types`),
        },
    };
}
//# sourceMappingURL=types.generator.js.map