"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SequenceNumComputedFieldProvider = void 0;
const string_helper_1 = require("../../../helpers/string.helper");
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const create_field_metadata_dto_1 = require("../../../dtos/create-field-metadata.dto");
const computed_field_provider_decorator_1 = require("../../../decorators/computed-field-provider.decorator");
const model_sequence_entity_1 = require("../../../entities/model-sequence.entity");
const typeorm_2 = require("typeorm");
let SequenceNumComputedFieldProvider = class SequenceNumComputedFieldProvider {
    constructor(dataSource) {
        this.dataSource = dataSource;
    }
    name() {
        return "SequenceNumComputedFieldProvider";
    }
    help() {
        return "Computed field provider used to create fields whose value is based on some prefix, padding & sequence number. " +
            "Use mode='counter' (default) to auto-increment the sequence's currentValue. " +
            "Use mode='entityId' to use the entity's own id as the number (afterInsert only, does not update the counter).";
    }
    buildSequenceString(modelSequence, numericValue) {
        const prefix = modelSequence.prefix ?? "";
        const separator = modelSequence.separator ?? "";
        const padded = String(numericValue).padStart(modelSequence.padding ?? 5, "0");
        return `${prefix}${separator}${padded}`;
    }
    async generateCounterSequenceValue(sequenceName, manager) {
        const run = async (mgr) => {
            const modelSequenceRepo = mgr.getRepository(model_sequence_entity_1.ModelSequence);
            const modelSequence = await modelSequenceRepo.findOne({
                where: { sequenceName },
                lock: { mode: "pessimistic_write" }
            });
            if (!modelSequence) {
                throw new Error(`ModelSequence not found for ${sequenceName}`);
            }
            const nextValue = modelSequence.currentValue + 1;
            const sequenceString = this.buildSequenceString(modelSequence, nextValue);
            modelSequence.currentValue = nextValue;
            await modelSequenceRepo.save(modelSequence);
            const modelSequenceWithModel = await modelSequenceRepo.findOne({
                where: { id: modelSequence.id },
                relations: { model: true },
            });
            const modelSingularName = modelSequenceWithModel?.model?.singularName;
            if (!modelSingularName) {
                throw new Error(`Model singularName not found for sequence ${sequenceName}`);
            }
            return { sequenceString, currentValue: nextValue, modelSingularName };
        };
        return manager ? run(manager) : this.dataSource.transaction(run);
    }
    async generateEntityIdSequenceValue(sequenceName, entityId) {
        const modelSequenceRepo = this.dataSource.manager.getRepository(model_sequence_entity_1.ModelSequence);
        const modelSequence = await modelSequenceRepo.findOne({
            where: { sequenceName },
            relations: { model: true },
        });
        if (!modelSequence) {
            throw new Error(`ModelSequence not found for ${sequenceName}`);
        }
        const modelSingularName = modelSequence.model?.singularName;
        if (!modelSingularName) {
            throw new Error(`Model singularName not found for sequence ${sequenceName}`);
        }
        return { sequenceString: this.buildSequenceString(modelSequence, entityId), modelSingularName };
    }
    async postComputeAndSaveValue(triggerEntity, computedFieldMetadata) {
        const { sequenceName, mode = 'counter' } = computedFieldMetadata.computedFieldValueProviderCtxt ?? {};
        if (!sequenceName) {
            throw new Error("sequenceName is required for sequence computation");
        }
        let sequenceString;
        let modelSingularName;
        if (mode === 'entityId') {
            const eventType = computedFieldMetadata.eventContext?.eventType;
            if (eventType !== create_field_metadata_dto_1.ComputedFieldTriggerOperation.afterInsert) {
                throw new Error(`SequenceNumComputedFieldProvider with mode='entityId' only supports "${create_field_metadata_dto_1.ComputedFieldTriggerOperation.afterInsert}" events, but received "${eventType}"`);
            }
            ({ sequenceString, modelSingularName } = await this.generateEntityIdSequenceValue(sequenceName, triggerEntity.id));
        }
        else {
            ({ sequenceString, modelSingularName } = await this.generateCounterSequenceValue(sequenceName));
        }
        const entityName = (0, string_helper_1.classify)(modelSingularName);
        const entityRepo = this.dataSource.manager.getRepository(entityName);
        await entityRepo.update(triggerEntity.id, { [computedFieldMetadata.fieldName]: sequenceString });
    }
};
exports.SequenceNumComputedFieldProvider = SequenceNumComputedFieldProvider;
exports.SequenceNumComputedFieldProvider = SequenceNumComputedFieldProvider = __decorate([
    (0, computed_field_provider_decorator_1.ComputedFieldProvider)(),
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectDataSource)()),
    __metadata("design:paramtypes", [typeorm_2.DataSource])
], SequenceNumComputedFieldProvider);
//# sourceMappingURL=sequence-num-computed-field-provider.js.map