export function createIdempotencyMiddleware(options) {
    process.stdout.write('[IDEMPOTENCY] createIdempotencyMiddleware factory called\n');
    return async (request, reply) => {
        process.stdout.write(`[IDEMPOTENCY] Middleware function INVOKED for ${request.method} ${request.url}\n`);
        const { enabled, store } = options;
        const logger = request.logger || request.log;
        if (!enabled) {
            process.stdout.write('[IDEMPOTENCY] Middleware disabled, skipping\n');
            return;
        }
        const idempotencyKey = request.headers['idempotency-key'];
        logger.info('Idempotency middleware executing', {
            hasKey: !!idempotencyKey,
            key: idempotencyKey || 'none',
            url: request.url,
            method: request.method,
            headers: Object.keys(request.headers).filter(h => h.toLowerCase().includes('idempotency'))
        });
        process.stdout.write(`[IDEMPOTENCY] Middleware executing for ${request.method} ${request.url}, hasKey: ${!!idempotencyKey}\n`);
        if (!idempotencyKey) {
            return;
        }
        const uuidV4Regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
        if (!uuidV4Regex.test(idempotencyKey)) {
            return reply.status(400).send({
                error: 'invalid_idempotency_key',
                message: 'Idempotency-Key must be a valid UUID v4'
            });
        }
        const route = request.routeOptions?.url || request.url.split('?')[0] || 'unknown';
        const tenant = request.headers['x-tenant'] || 'default';
        const bodyHash = await generateBodyHash(request.body);
        try {
            const existing = await store.get(idempotencyKey, tenant, route);
            if (existing) {
                if (existing.bodyHash === bodyHash) {
                    const logger = request.logger || request.log;
                    logger.info('Idempotency hit - returning cached response', {
                        key: idempotencyKey,
                        tenant,
                        route,
                        hash: bodyHash
                    });
                    return reply
                        .status(existing.statusCode === 201 ? 200 : existing.statusCode)
                        .headers(existing.headers || {})
                        .send(existing.response);
                }
                else {
                    const logger = request.logger || request.log;
                    logger.warn('Idempotency conflict - same key, different body', {
                        key: idempotencyKey,
                        tenant,
                        route,
                        existingHash: existing.bodyHash,
                        newHash: bodyHash
                    });
                    return reply.status(409).send({
                        error: 'idempotency_conflict',
                        message: 'Idempotency key already used with different request body',
                        metadata: {
                            existingHash: existing.bodyHash,
                            newHash: bodyHash,
                            existingResponse: existing.response,
                            createdAt: existing.createdAt
                        }
                    });
                }
            }
            const logger = request.logger || request.log;
            logger.debug('Idempotency miss - will store response', {
                key: idempotencyKey,
                tenant,
                route,
                hash: bodyHash
            });
            request.idempotencyContext = {
                key: idempotencyKey,
                tenant,
                route,
                bodyHash,
                store
            };
        }
        catch (error) {
            const logger = request.logger || request.log;
            logger.error('Idempotency error', {
                key: idempotencyKey,
                tenant,
                route,
                error: error instanceof Error ? error.message : String(error)
            });
            return;
        }
    };
}
export async function captureIdempotencyResponse(request, reply, payload) {
    const context = request.idempotencyContext;
    if (!context) {
        return payload;
    }
    try {
        const { key, tenant, route, bodyHash, store } = context;
        await store.set(key, tenant, route, bodyHash, {
            statusCode: reply.statusCode,
            body: payload,
            headers: reply.getHeaders()
        });
        const logger = request.logger || request.log;
        logger.info('Idempotency response stored', {
            key,
            tenant,
            route,
            hash: bodyHash,
            statusCode: reply.statusCode
        });
    }
    catch (error) {
        const logger = request.logger || request.log;
        logger.error('Idempotency store error', {
            error: error instanceof Error ? error.message : String(error)
        });
    }
    return payload;
}
async function generateBodyHash(body) {
    const text = JSON.stringify(body || {});
    const encoder = new TextEncoder();
    const data = encoder.encode(text);
    if (typeof crypto !== 'undefined' && crypto.subtle) {
        const hashBuffer = await crypto.subtle.digest('SHA-256', data);
        const hashArray = Array.from(new Uint8Array(hashBuffer));
        return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
    }
    else {
        let hash = 0;
        for (let i = 0; i < text.length; i++) {
            const char = text.charCodeAt(i);
            hash = ((hash << 5) - hash) + char;
            hash = hash & hash;
        }
        return Math.abs(hash).toString(16);
    }
}
//# sourceMappingURL=idempotency.js.map