"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);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InboxService = void 0;
const api_prisma_1 = require("@hed-hog/api-prisma");
const common_1 = require("@nestjs/common");
const types_1 = require("../types");
let InboxService = class InboxService {
    constructor(prisma) {
        this.prisma = prisma;
    }
    toDomainEvent(record) {
        return {
            id: String(record.id),
            outboxEventId: String(record.outbox_event_id),
            consumerName: record.consumer_name,
            status: record.status,
            attemptCount: record.attempt_count,
            lastError: record.last_error,
            processedAt: record.processed_at,
            createdAt: record.created_at,
            updatedAt: record.updated_at,
        };
    }
    toDatabaseId(eventId) {
        return typeof eventId === 'number' ? eventId : Number(eventId);
    }
    toDatabaseUpdate(partialUpdate) {
        if (!partialUpdate) {
            return undefined;
        }
        return {
            attempt_count: partialUpdate.attemptCount,
            last_error: partialUpdate.lastError,
            processed_at: partialUpdate.processedAt,
        };
    }
    /**
     * Get or create inbox event for idempotency tracking
     * Returns existing if already processed, otherwise creates new
     */
    async getOrCreate(outboxEventId, consumerName) {
        // Try to find existing
        let inboxEvent = await this.prisma.inbox_event.findFirst({
            where: {
                outbox_event_id: this.toDatabaseId(outboxEventId),
                consumer_name: consumerName,
            },
        });
        // Create if doesn't exist
        if (!inboxEvent) {
            inboxEvent = await this.prisma.inbox_event.create({
                data: {
                    outbox_event_id: this.toDatabaseId(outboxEventId),
                    consumer_name: consumerName,
                    status: types_1.InboxEventStatus.RECEIVED,
                    attempt_count: 0,
                },
            });
        }
        return this.toDomainEvent(inboxEvent);
    }
    /**
     * Update inbox event status
     */
    async updateStatus(inboxEventId, status, partialUpdate) {
        const inboxEvent = await this.prisma.inbox_event.update({
            where: { id: this.toDatabaseId(inboxEventId) },
            data: Object.assign({ status }, this.toDatabaseUpdate(partialUpdate)),
        });
        return this.toDomainEvent(inboxEvent);
    }
    /**
     * Mark inbox event as processing
     */
    async markProcessing(inboxEventId) {
        return this.updateStatus(inboxEventId, types_1.InboxEventStatus.PROCESSING);
    }
    /**
     * Mark inbox event as successfully processed
     */
    async markProcessed(inboxEventId) {
        return this.updateStatus(inboxEventId, types_1.InboxEventStatus.PROCESSED, {
            processedAt: new Date(),
        });
    }
    /**
     * Mark inbox event as failed
     */
    async markFailed(inboxEventId, error) {
        const record = await this.prisma.inbox_event.findUnique({
            where: { id: this.toDatabaseId(inboxEventId) },
        });
        if (!record) {
            throw new Error(`Inbox event ${inboxEventId} not found`);
        }
        const inboxEvent = this.toDomainEvent(record);
        return this.updateStatus(inboxEventId, types_1.InboxEventStatus.FAILED, {
            attemptCount: inboxEvent.attemptCount + 1,
            lastError: error,
        });
    }
    /**
     * Mark inbox event as skipped
     */
    async markSkipped(inboxEventId) {
        return this.updateStatus(inboxEventId, types_1.InboxEventStatus.SKIPPED);
    }
    /**
     * Increment attempt count
     */
    async incrementAttempt(inboxEventId) {
        const record = await this.prisma.inbox_event.findUnique({
            where: { id: this.toDatabaseId(inboxEventId) },
        });
        if (!record) {
            throw new Error(`Inbox event ${inboxEventId} not found`);
        }
        const inboxEvent = this.toDomainEvent(record);
        return this.updateStatus(inboxEventId, inboxEvent.status, {
            attemptCount: inboxEvent.attemptCount + 1,
        });
    }
    /**
     * Get inbox event by ID
     */
    async getById(inboxEventId) {
        const inboxEvent = await this.prisma.inbox_event.findUnique({
            where: { id: this.toDatabaseId(inboxEventId) },
        });
        return inboxEvent ? this.toDomainEvent(inboxEvent) : null;
    }
    /**
     * Check if event was already processed by consumer
     */
    async isProcessed(outboxEventId, consumerName) {
        const inboxEvent = await this.prisma.inbox_event.findFirst({
            where: {
                outbox_event_id: this.toDatabaseId(outboxEventId),
                consumer_name: consumerName,
            },
        });
        return (inboxEvent !== null &&
            inboxEvent.status === types_1.InboxEventStatus.PROCESSED);
    }
    /**
     * Count unprocessed items for a consumer
     */
    async countUnprocessed(consumerName) {
        return this.prisma.inbox_event.count({
            where: {
                consumer_name: consumerName,
                status: {
                    notIn: [types_1.InboxEventStatus.PROCESSED, types_1.InboxEventStatus.SKIPPED],
                },
            },
        });
    }
};
exports.InboxService = InboxService;
exports.InboxService = InboxService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [api_prisma_1.PrismaService])
], InboxService);
//# sourceMappingURL=inbox.service.js.map