/**
 * Connection Resilience Middleware
 * Optimizes connection handling to bypass ISP restrictions and improve reliability
 */

const config = require("../config.json");

/**
 * Configure optimized connection settings
 */
function configureConnectionResilience(app) {
	// Set connection timeout
	app.use((req, res, next) => {
		// Increase timeout for slow connections (some ISPs throttle)
		const timeout = 120000; // 2 minutes
		
		// Handle request timeout
		req.setTimeout(timeout, () => {
			const clientIP = req.ip || req.socket?.remoteAddress || "unknown";
			console.warn(`[Timeout] Request ${req.method} ${req.url} from ${clientIP} timed out after ${timeout}ms`);
			
			if (!res.headersSent) {
				res.status(504).json({
					success: false,
					error: {
						type: 'REQUEST_TIMEOUT',
						message: 'Operation timed out. The server took too long to respond.',
						code: 'ETIMEDOUT',
						suggestion: 'Please try again later or check your internet connection.'
					}
				});
			}
			
			// Destroy socket to free resources if response cannot be sent
			// or after sending response to ensure connection is closed
			// req.destroy();
		});
		
		res.setTimeout(timeout); // 2 minutes

		// Set keep-alive headers to maintain connection
		res.setHeader("Connection", "keep-alive");
		res.setHeader("Keep-Alive", "timeout=120, max=100");

		next();
	});

	// Add additional headers to bypass some ISP restrictions
	app.use((req, res, next) => {
		// Prevent ISP caching/modification
		res.setHeader("Cache-Control", "no-transform");

		// Add vary headers for better caching behavior
		res.setHeader("Vary", "Accept-Encoding, Origin");

		next();
	});
}

/**
 * Enhanced error handling for connection issues
 */
function handleConnectionErrors(err, req, res, next) {
	// Log connection-specific errors
	if (err.code === "ECONNRESET" || err.code === "EPIPE" || err.code === "ETIMEDOUT") {
		console.warn(`Connection error from ${req.ip}: ${err.code} - ${err.message}`);

		// Return a specific response for connection issues; Retry-After dari config
		res.set("Retry-After", String(config.backendConfig?.retryAfterSeconds ?? 30));
		return res.status(503).json({
			error: "Connection interrupted",
			code: err.code,
			message: "Please retry your request",
			timestamp: new Date().toISOString(),
		});
	}

	// Pass to next error handler
	next(err);
}

/**
 * Request retry helper middleware
 * Adds retry information to response headers
 */
function addRetryHeaders(req, res, next) {
	// Add headers to help client implement retry logic
	res.setHeader("X-Retry-After", "5"); // Suggest retry after 5 seconds
	res.setHeader("X-RateLimit-Limit", "10000000"); // Match rate limit config
	res.setHeader("X-Request-ID", generateRequestID()); // Unique request ID for tracking

	next();
}

/**
 * Generate unique request ID
 */
function generateRequestID() {
	return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

/**
 * DNS prefetch and preconnect helper
 * Returns middleware that adds resource hints
 */
function addResourceHints(domains = []) {
	return (req, res, next) => {
		// Add DNS prefetch for external resources
		const hints = domains.map((domain) => `<${domain}>; rel=dns-prefetch`).join(", ");

		if (hints) {
			res.setHeader("Link", hints);
		}

		next();
	};
}

/**
 * Compress response for faster transmission
 * (Works with compression middleware but adds additional headers)
 */
function optimizeTransmission(req, res, next) {
	// Encourage compression
	if (!res.getHeader("Content-Encoding")) {
		res.setHeader("X-Content-Type-Options", "nosniff");
	}

	// Add timing information
	const startTime = Date.now();
	res.on("finish", () => {
		const duration = Date.now() - startTime;
		console.log(`[${req.method}] ${req.url} - ${res.statusCode} - ${duration}ms`);
	});

	next();
}

/**
 * Graceful degradation for problematic requests
 */
function gracefulDegradation(req, res, next) {
	// Handle problematic user agents or patterns
	const userAgent = req.headers["user-agent"] || "";

	// Some ISPs inject their own user agents or modify headers
	if (userAgent.toLowerCase().includes("bot") && !userAgent.toLowerCase().includes("googlebot")) {
		console.warn(`Suspicious user agent from ${req.ip}: ${userAgent}`);
	}

	next();
}

/**
 * IP whitelist/blacklist helper (optional)
 * Can be used to temporarily handle specific ISP ranges
 */
function createIPFilter(whitelist = [], blacklist = []) {
	return (req, res, next) => {
		const clientIP = getClientIP(req);

		// Check blacklist
		if (blacklist.length > 0 && blacklist.some((ip) => clientIP.startsWith(ip))) {
			return res.status(403).json({
				error: "Access denied",
				message: "Your IP range is temporarily restricted",
			});
		}

		// Check whitelist (if defined, only allow whitelisted IPs)
		if (whitelist.length > 0 && !whitelist.some((ip) => clientIP.startsWith(ip))) {
			return res.status(403).json({
				error: "Access denied",
				message: "Your IP is not whitelisted",
			});
		}

		next();
	};
}

/**
 * Get client IP helper
 */
function getClientIP(req) {
	// Proxy headers intentionally ignored; rely on direct connection
	return req.ip || req.socket?.remoteAddress || req.connection?.remoteAddress || "unknown";
}

module.exports = {
	configureConnectionResilience,
	handleConnectionErrors,
	addRetryHeaders,
	addResourceHints,
	optimizeTransmission,
	gracefulDegradation,
	createIPFilter,
};
