const redisClient = require("../redisClient");

// Simple idempotency middleware using in-memory redisClient replacement
// Expects header 'x-idempotency-key'. If present, caches response for TTL and
// replays on duplicate requests, preventing duplicate processing after offline retries.

const TTL_SECONDS = 24 * 60 * 60; // 24 hours
const fs = require("fs");
const path = require("path");
const logDir = path.join(__dirname, "..", "logs");
const logFile = path.join(logDir, "idempotency.log");

function logEvent(event) {
	try {
		if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
		fs.appendFileSync(
			logFile,
			JSON.stringify({
				timestamp: new Date().toISOString(),
				...event,
			}) + "\n",
			"utf8"
		);
	} catch (_) {}
}

module.exports = function idempotency() {
	return async function (req, res, next) {
		const key = req.headers["x-idempotency-key"] || req.headers["X-Idempotency-Key"];
		if (!key) return next();

		const cacheKey = `idem:${req.method}:${req.originalUrl}:${key}`;
		try {
			const cached = await redisClient.get(cacheKey);
			if (cached) {
				res.set("x-idempotent-replay", "1");
				res.set("x-idempotency-key", key);
				logEvent({ type: "replay", method: req.method, url: req.originalUrl, key, status: cached.status });
				return res.status(cached.status || 200).json(cached.body);
			}

			// Wrap res.json to capture first successful response and cache it
			const originalJson = res.json.bind(res);
			res.json = async (body) => {
				try {
					await redisClient.setEx(cacheKey, TTL_SECONDS, { status: res.statusCode || 200, body });
					res.set("x-idempotency-key", key);
					res.set("x-idempotent-cache", "1");
					logEvent({ type: "cache", method: req.method, url: req.originalUrl, key, status: res.statusCode || 200 });
				} catch (_) {}
				return originalJson(body);
			};
			return next();
		} catch (err) {
			// On cache error, continue normally
			logEvent({ type: "error", method: req.method, url: req.originalUrl, key, message: err && err.message });
			return next();
		}
	};
};
