"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); }
};
var MqMessageService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MqMessageService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const core_1 = require("@nestjs/core");
const typeorm_2 = require("typeorm");
const crud_service_1 = require("./crud.service");
const mq_message_entity_1 = require("../entities/mq-message.entity");
const common_2 = require("@nestjs/common");
const mq_message_repository_1 = require("../repository/mq-message.repository");
let MqMessageService = MqMessageService_1 = class MqMessageService extends crud_service_1.CRUDService {
    constructor(entityManager, repo, moduleRef) {
        super(entityManager, repo, 'mqMessage', 'solid-core', moduleRef);
        this.entityManager = entityManager;
        this.repo = repo;
        this.moduleRef = moduleRef;
        this.logger = new common_2.Logger(MqMessageService_1.name);
    }
    async lockNextPendingMessage(queueName) {
        return await this.entityManager.transaction(async (manager) => {
            const rawJob = await manager.query(`
          SELECT ss_mq_message.id
            FROM ss_mq_message
            left join ss_mq_message_queue on ss_mq_message.mq_message_queue_id = ss_mq_message_queue.id
           WHERE ss_mq_message_queue."name" = $1
             AND ss_mq_message.stage = 'pending'
           ORDER BY ss_mq_message.created_at ASC
             FOR UPDATE SKIP LOCKED
           LIMIT 1`, [queueName]);
            if (!rawJob || rawJob.length === 0) {
                return null;
            }
            const job = await manager.getRepository(mq_message_entity_1.MqMessage).findOne({ where: { id: rawJob[0].id }, relations: ['mqMessageQueue'] });
            if (job) {
                job.stage = 'scheduled';
                await manager.save(job);
                return job;
            }
            return null;
        });
    }
    async waitForTerminalStatus(messageId, opts) {
        const { timeoutMs = 60_000, intervalMs = 500, maxIntervalMs = 2_000, throwOnFailure = false, parseJson = true, logEveryN = 10, } = opts || {};
        const start = Date.now();
        let attempt = 0;
        let delay = intervalMs;
        const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
        while (true) {
            attempt++;
            const rec = await this.repo.findOne({
                where: { messageId },
                select: {
                    id: true,
                    messageId: true,
                    stage: true,
                    finishedAt: true,
                    elapsedMillis: true,
                    output: true,
                    error: true,
                    input: true,
                },
                loadEagerRelations: false,
            });
            if (attempt % logEveryN === 0) {
                this.logger.debug(`waitForTerminalStatus(${messageId}) poll #${attempt} -> ${rec?.stage ?? 'not_found'}`);
            }
            if (!rec) {
            }
            else if (rec.stage === 'succeeded' || rec.stage === 'failed') {
                if (parseJson) {
                    rec.output = rec.output;
                    rec.error = rec.error;
                }
                if (rec.stage === 'failed' && throwOnFailure) {
                    throw new Error(`Queue message ${messageId} failed` + (rec.error ? `: ${JSON.stringify(rec.error).slice(0, 500)}` : ''));
                }
                return rec;
            }
            const elapsed = Date.now() - start;
            if (elapsed >= timeoutMs) {
                throw new Error(`Timed out after ${timeoutMs}ms waiting for message ${messageId} to reach terminal status`);
            }
            await sleep(delay);
            delay = Math.min(Math.floor(delay * 1.5), maxIntervalMs);
        }
    }
    safeJsonParse(value) {
        if (value == null)
            return value;
        if (typeof value !== 'string')
            return value;
        const s = value.trim();
        if (!s)
            return s;
        try {
            return JSON.parse(s);
        }
        catch {
            return value;
        }
    }
};
exports.MqMessageService = MqMessageService;
exports.MqMessageService = MqMessageService = MqMessageService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectEntityManager)()),
    __metadata("design:paramtypes", [typeorm_2.EntityManager,
        mq_message_repository_1.MqMessageRepository,
        core_1.ModuleRef])
], MqMessageService);
//# sourceMappingURL=mq-message.service.js.map