/**
 * Função utilitária para extrair o IP do cliente de um Request HTTP
 * Sem usar APIs externas - usa apenas headers HTTP
 */

/**
 * Extrai o IP do cliente de um Request HTTP
 * Considera headers como X-Forwarded-For, X-Real-IP, etc.
 */
export function getClientIP(request: Request): string | undefined {
	// Headers que podem conter o IP do cliente (case-insensitive)
	const getHeader = (name: string): string | null => {
		// Tentar diferentes variações de case
		const variations = [
			name,
			name.toLowerCase(),
			name.toUpperCase(),
			name.charAt(0).toUpperCase() + name.slice(1).toLowerCase()
		];

		for (const variation of variations) {
			const value = request.headers.get(variation);
			if (value) return value;
		}

		// As variações de case já cobrem a maioria dos casos
		// Se não encontrou, retorna null
		return null;
	};

	const forwardedFor = getHeader('x-forwarded-for');
	const realIP = getHeader('x-real-ip');
	const cfConnectingIP = getHeader('cf-connecting-ip'); // Cloudflare
	const trueClientIP = getHeader('true-client-ip'); // Cloudflare Enterprise
	const xClientIP = getHeader('x-client-ip');
	const forwarded = getHeader('forwarded');
	const remoteAddr = getHeader('remote-addr');

	// Log para debug
	console.log('Procurando IP nos headers:', {
		'x-forwarded-for': forwardedFor,
		'x-real-ip': realIP,
		'cf-connecting-ip': cfConnectingIP,
		'true-client-ip': trueClientIP,
		'x-client-ip': xClientIP,
		forwarded: forwarded,
		'remote-addr': remoteAddr
	});

	// Prioridade: X-Forwarded-For pode conter múltiplos IPs (proxy chain)
	// O primeiro IP é geralmente o IP original do cliente
	if (forwardedFor) {
		const ips = forwardedFor.split(',').map((ip) => ip.trim());
		// Pegar o primeiro IP válido
		for (const ip of ips) {
			if (isValidIP(ip)) {
				console.log('IP encontrado em X-Forwarded-For:', ip);
				return ip;
			}
		}
	}

	// Forwarded header (RFC 7239)
	if (forwarded) {
		// Formato: for=192.0.2.60;proto=http;by=203.0.113.43
		const forMatch = forwarded.match(/for=([^;,\s]+)/i);
		if (forMatch && forMatch[1]) {
			const ip = forMatch[1].replace(/^\[|\]$/g, ''); // Remove brackets de IPv6
			if (isValidIP(ip)) {
				console.log('IP encontrado em Forwarded:', ip);
				return ip;
			}
		}
	}

	// Outros headers com IP único
	if (realIP && isValidIP(realIP)) {
		console.log('IP encontrado em X-Real-IP:', realIP);
		return realIP;
	}

	if (cfConnectingIP && isValidIP(cfConnectingIP)) {
		console.log('IP encontrado em CF-Connecting-IP:', cfConnectingIP);
		return cfConnectingIP;
	}

	if (trueClientIP && isValidIP(trueClientIP)) {
		console.log('IP encontrado em True-Client-IP:', trueClientIP);
		return trueClientIP;
	}

	if (xClientIP && isValidIP(xClientIP)) {
		console.log('IP encontrado em X-Client-IP:', xClientIP);
		return xClientIP;
	}

	if (remoteAddr && isValidIP(remoteAddr)) {
		console.log('IP encontrado em Remote-Addr:', remoteAddr);
		return remoteAddr;
	}

	// Tentar extrair do URL (último recurso)
	try {
		const url = new URL(request.url);
		// Se o servidor estiver configurado para passar IP via query param
		const ipFromQuery = url.searchParams.get('ip');
		if (ipFromQuery && isValidIP(ipFromQuery)) {
			console.log('IP encontrado em query param:', ipFromQuery);
			return ipFromQuery;
		}
	} catch {
		// Ignorar erro de parsing do URL
	}

	console.log('Nenhum IP válido encontrado nos headers');
	return undefined;
}

/**
 * Valida se uma string é um endereço IP válido (IPv4 ou IPv6)
 */
function isValidIP(ip: string): boolean {
	if (!ip || ip.length === 0) {
		return false;
	}

	// Validar IPv4
	const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
	if (ipv4Regex.test(ip)) {
		const parts = ip.split('.');
		return parts.every((part) => {
			const num = parseInt(part, 10);
			return num >= 0 && num <= 255;
		});
	}

	// Validar IPv6 (formato simplificado)
	const ipv6Regex = /^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$/;
	if (ipv6Regex.test(ip)) {
		return true;
	}

	// Validar IPv6 comprimido (com ::)
	const ipv6CompressedRegex = /^([0-9a-fA-F]{0,4}:)*::([0-9a-fA-F]{0,4}:)*[0-9a-fA-F]{0,4}$/;
	if (ipv6CompressedRegex.test(ip)) {
		return true;
	}

	return false;
}
