import { ApiError } from "../errors";
import { readIdempotency, writeIdempotency } from "../idempotency/idempotencyStore";
import { env } from "../../config/env";
import { successResponse } from "./errorMiddleware";
export function idempotency(options) {
    return function idempotencyMiddleware(req, _res, next) {
        const idempotencyKey = req.header("idempotency-key");
        if (!idempotencyKey) {
            if (options.required === false) {
                return next();
            }
            return next(new ApiError("DUPLICATE_REQUEST", "Missing Idempotency-Key", 400));
        }
        const cached = readIdempotency(options.scope, idempotencyKey);
        if (cached) {
            const cachedPayload = cached.response ?? cached;
            const cachedStatus = cached.statusCode || 200;
            const payload = (() => {
                if (cachedPayload &&
                    typeof cachedPayload === "object" &&
                    "data" in cachedPayload &&
                    "request_id" in cachedPayload &&
                    "timestamp" in cachedPayload) {
                    const typed = cachedPayload;
                    typed.request_id = req.requestId;
                    typed.timestamp = new Date().toISOString();
                    return typed;
                }
                return cachedPayload;
            })();
            return _res.status(cachedStatus).json(payload);
        }
        req.body = { ...(req.body || {}), __idempotencyKey: idempotencyKey };
        const originalJson = _res.json.bind(_res);
        const originalStatus = _res.status.bind(_res);
        let statusCode = 200;
        _res.status = function statusWithStore(code) {
            statusCode = code;
            return originalStatus(code);
        };
        _res.json = function jsonWithStore(payload) {
            const responsePayload = payload &&
                typeof payload === "object" &&
                "data" in payload &&
                "request_id" in payload &&
                "timestamp" in payload
                ? successResponse(req, payload.data)
                : payload;
            writeIdempotency(options.scope, idempotencyKey, {
                response: responsePayload,
                statusCode,
                at: Date.now()
            }, options.ttlMs || env.IDEMPOTENCY_TTL_MS);
            return originalJson(responsePayload);
        };
        next();
    };
}
