"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.generateDataMocker = generateDataMocker;
const Generator = __importStar(require("@postxl/generator"));
function generateDataMocker(context) {
    const imports = Generator.ImportGenerator.from(context.mockData.dataMocker.location)
        .add(context.mockData.idTracker)
        .addImport({
        from: Generator.toPackageName('@decoders/data-model.decoder'),
        items: [Generator.toFunctionName('DataModel')],
    })
        .addTypeImport({
        from: Generator.toPackageName('@postxl/utils'),
        items: [Generator.toTypeName('Debrand')],
    });
    const classComponents = {
        publicProperties: [],
        privateProperties: [],
        classMethods: [],
    };
    for (const model of context.models.values()) {
        const names = {
            repo: Generator.toVariableName(model._conjugated.camelCasePlural),
            idTracker: Generator.toVariableName(`${model._conjugated.camelCase}Ids`),
            variable: Generator.toVariableName(model._conjugated.camelCase),
        };
        // Generate all class components for the current model
        const components = generateClassComponents({ model, context, imports, names });
        // Merge the generated components into the main object
        classComponents.publicProperties.push(...components.publicProperties);
        classComponents.privateProperties.push(...components.privateProperties);
        classComponents.classMethods.push(...components.classMethods);
    }
    return `
  ${imports.generate()}

  export class ${context.mockData.dataMocker.name} implements DataModel {
    ${classComponents.publicProperties.join('\n')}

    ${classComponents.privateProperties.join('\n')}

    ${classComponents.classMethods.join('\n')}
  }
  `;
}
function generateClassComponents({ model, context, imports, names, }) {
    const components = {
        publicProperties: [],
        privateProperties: [],
        classMethods: [],
    };
    // Generate public property
    components.publicProperties.push(generatePublicProperty({ model, imports, names }));
    // Generate private property
    components.privateProperties.push(generatePrivateProperty({ model, imports, context, names }));
    // Generate class method
    components.classMethods.push(generateClassMethod({ model, context, imports, names }));
    return components;
}
function generatePublicProperty({ model, imports, names: { repo }, }) {
    imports.add(model.types);
    return `public ${repo}: ${model.types.name}[] = []`;
}
function generatePrivateProperty({ model, context, names: { idTracker }, }) {
    return `private readonly ${idTracker}: ${context.mockData.idTracker.name}<${model.types.name}> = new ${context.mockData.idTracker.name}<${model.types.name}>('${model.name}')`;
}
function generateClassMethod({ model, context, imports, names, }) {
    imports.add(model.mockData.stub);
    const { relationFields } = generateRelationFields({
        model,
        context,
        imports,
        names,
    });
    const { discriminatedUnionFields } = generateRelationDiscriminatedUnionFields({
        model,
        context,
        imports,
        names,
    });
    return `
    public ${model.mockData.dataMocker.add}(${names.variable}: Debrand<Partial<${model.types.name}>>): this {
    ${relationFields.join('\n')}
    ${discriminatedUnionFields.join('\n')}
    this.${names.idTracker}.assertId(${names.variable})
    const stubData = ${model.mockData.stub.name}(${names.variable})
    this.${names.repo}.push(stubData)
    return this
  }
  `;
}
function generateRelationFields({ model, context, imports, names, }) {
    const relationFields = [];
    for (const field of model.fields.values()) {
        if (field.kind === 'relation') {
            relationFields.push(ensureRelatedModelExists({ model, field, context, imports, names }));
        }
    }
    return { relationFields };
}
function generateRelationDiscriminatedUnionFields({ model, context, imports, names, }) {
    const discriminatedUnionFields = [];
    for (const field of model.fields.values()) {
        if (field.kind === 'discriminatedUnion') {
            discriminatedUnionFields.push(
            // Process common fields
            ...processCommonFields({ field, model, context, imports, names }), 
            // Process discriminated union members
            ...processDiscriminatedUnionMembers({ field, model, context, imports, names }));
        }
    }
    return { discriminatedUnionFields };
}
function processCommonFields({ field, model, context, imports, names, }) {
    const commonFieldResults = [];
    for (const commonField of field.commonFields.values()) {
        if (commonField.kind === 'relation') {
            commonFieldResults.push(ensureRelatedModelInDiscriminatedUnionCommonFieldExists({
                model,
                field,
                relationField: commonField,
                context,
                imports,
                names,
            }));
        }
    }
    return commonFieldResults;
}
function processDiscriminatedUnionMembers({ field, model, context, imports, names, }) {
    const memberFieldResults = [];
    for (const [discriminator, member] of field.members) {
        for (const memberField of member.fields.values()) {
            if (memberField.kind === 'relation') {
                memberFieldResults.push(ensureRelatedModelInDiscriminatedUnionMemberExists({
                    model,
                    duField: field,
                    relationField: memberField,
                    discriminator,
                    context,
                    imports,
                    names,
                }));
            }
        }
    }
    return memberFieldResults;
}
function ensureRelatedModelExists({ field, context, imports, names, }) {
    const relatedModel = context.models.get(field.referencedModelName);
    imports.add(relatedModel.types.id.toBranded);
    const label = relatedModel.labelField.name === relatedModel.idField.name
        ? ''
        : `${relatedModel.labelField.name}: \`${field.label} \${${names.variable}.${field.name}}\`,`;
    return `
    if (${names.variable}?.${field.name} && !this.${names.repo}.some((a) => a.id === ${names.variable}.${field.name})) {
      this.${relatedModel.mockData.dataMocker.add}({
      ${relatedModel.idField.name}: ${relatedModel.types.id.toBranded.name}(${names.variable}.${field.name}),
      ${label}
      })
    }
  `;
}
function ensureRelatedModelInDiscriminatedUnionCommonFieldExists({ field, relationField, context, imports, names, }) {
    const relatedModel = context.models.get(relationField.referencedModelName);
    imports.add(relatedModel.types.id.toBranded);
    const relatedModelNamePlural = Generator.toVariableName(relatedModel._conjugated.camelCasePlural);
    const label = relatedModel.labelField.name === relatedModel.idField.name
        ? ''
        : `${relatedModel.labelField.name}: \`${relationField.label} \${${names.variable}.${field.name}.${relationField.name}}\`,`;
    return `
    if (${names.variable}?.${field.name} &&
    ${names.variable}.${field.name}.${relationField.name} &&
    !this.${relatedModelNamePlural}.some((a) => a.id === ${names.variable}.${field.name}!.${relationField.name})
     ){
      this.${relatedModel.mockData.dataMocker.add}({
        ${relatedModel.idField.name}: ${relatedModel.types.id.toBranded.name}(${names.variable}.${field.name}.${relationField.name}),
        ${label}
      })}
    `;
}
function ensureRelatedModelInDiscriminatedUnionMemberExists({ model, duField, relationField, discriminator, context, imports, names, }) {
    const relatedModel = context.models.get(relationField.referencedModelName);
    const memberType = model.types.discriminatedUnions.get(duField.name).memberTypes.get(discriminator);
    imports.add(relatedModel.types.id.toBranded).add(memberType);
    const relatedModelNamePlural = Generator.toVariableName(relatedModel._conjugated.camelCasePlural);
    const label = relatedModel.labelField.name === relatedModel.idField.name
        ? ''
        : `${relatedModel.labelField.name}: \`${relationField.label} \${(${names.variable}.${duField.name} as ${memberType.name}).${relationField.name}}\`,`;
    return `
    if (${names.variable}?.${duField.name} &&
    ${names.variable}?.${duField.name}.type === '${discriminator}' &&
    '${relationField.name}' in ${names.variable}.${duField.name} &&
    !this.${relatedModelNamePlural}.some((a) => a.id === (${names.variable}.${duField.name} as ${memberType.name}).${relationField.name})
     ){
      this.${relatedModel.mockData.dataMocker.add}({
        ${relatedModel.idField.name}: ${relatedModel.types.id.toBranded.name}((${names.variable}.${duField.name} as ${memberType.name}).${relationField.name}),
        ${label}
      })}
    `;
}
//# sourceMappingURL=data-mocker.generator.js.map