import { v } from 'convex/values';
import {
	internalMutation,
	mutation,
	query
} from './_generated/server';
import { internal } from './_generated/api';
import type { Id } from './_generated/dataModel';
import type {
	AtaqueCiberneticoTipo,
	SeveridadeSeguranca,
	StatusEventoSeguranca
} from './schema';
import type { MutationCtx, QueryCtx } from './_generated/server';
import { RateLimiter, SECOND } from '@convex-dev/rate-limiter';
import { components } from './_generated/api';

type Indicador = {
	tipo: string;
	valor: string;
	confianca?: number;
};

type RegistroMetricas = {
	pps?: number;
	bps?: number;
	rpm?: number;
	errosPorSegundo?: number;
	hostsAfetados?: number;
};

type RegistroFingerprint = {
	userAgent?: string;
	deviceId?: string;
	ja3?: string;
	tlsVersion?: string;
};

type RegistroGeo = {
	pais?: string;
	regiao?: string;
	cidade?: string;
	latitude?: number;
	longitude?: number;
};

type RegistroEventoArgs = {
	descricao?: string;
	tipoAtaque?: AtaqueCiberneticoTipo;
	severidade?: SeveridadeSeguranca;
	origemIp?: string;
	destinoIp?: string;
	destinoPorta?: number;
	protocolo?: string;
	transporte?: string;
	origemRegiao?: string;
	origemAsn?: string;
	mitreTechnique?: string;
	indicadores?: Indicador[];
	metricas?: RegistroMetricas;
	fingerprint?: RegistroFingerprint;
	geolocalizacao?: RegistroGeo;
	tags?: string[];
};

const ATAQUES_PRIORITARIOS: Array<AtaqueCiberneticoTipo> = [
	'ddos',
	'ransomware',
	'ransomware_lateral',
	'apt',
	'zero_day',
	'botnet',
	'ot_ics',
	'quantum_attack',
	'polymorphic_malware',
	'fileless_malware',
	'firmware_bootloader',
	'adversarial_ai',
	'deepfake_phishing',
	'phishing',
	'sql_injection',
	'xss',
	'path_traversal',
	'command_injection',
	'nosql_injection',
	'xxe',
	'man_in_the_middle',
	'credential_stuffing',
	'brute_force',
	'supply_chain',
	'malware',
	'engenharia_social',
	'cve_exploit',
	'bec',
	'side_channel'
];

const BASE_SEVERIDADE: Record<AtaqueCiberneticoTipo, SeveridadeSeguranca> = {
	phishing: 'moderado',
	malware: 'moderado',
	ransomware: 'alto',
	brute_force: 'moderado',
	credential_stuffing: 'moderado',
	sql_injection: 'alto',
	xss: 'moderado',
	path_traversal: 'alto',
	command_injection: 'alto',
	nosql_injection: 'alto',
	xxe: 'alto',
	man_in_the_middle: 'alto',
	ddos: 'alto',
	engenharia_social: 'moderado',
	cve_exploit: 'alto',
	apt: 'critico',
	zero_day: 'critico',
	supply_chain: 'critico',
	fileless_malware: 'alto',
	polymorphic_malware: 'alto',
	ransomware_lateral: 'critico',
	deepfake_phishing: 'alto',
	adversarial_ai: 'alto',
	side_channel: 'alto',
	firmware_bootloader: 'critico',
	bec: 'alto',
	botnet: 'alto',
	ot_ics: 'critico',
	quantum_attack: 'critico'
};

const SEVERIDADE_SCORE: Record<SeveridadeSeguranca, number> = {
	informativo: 0,
	baixo: 1,
	moderado: 2,
	alto: 3,
	critico: 4
};

const SCORE_SEVERIDADE = Object.entries(SEVERIDADE_SCORE).reduce<
	Record<number, SeveridadeSeguranca>
>((acc, [nome, score]) => {
	acc[score] = nome as SeveridadeSeguranca;
	return acc;
}, {});

// Padrões robustos de detecção de ataques
const KEYWORDS: Record<AtaqueCiberneticoTipo, RegExp[]> = {
	phishing: [/phish/i, /spoof/i, /fake login/i, /phishing/i],
	malware: [/malware/i, /payload/i, /trojan/i, /virus/i, /worm/i],
	ransomware: [/ransom/i, /encrypt/i, /locker/i, /cryptolocker/i],
	brute_force: [
		/brute/i,
		/password guess/i,
		/login flood/i,
		/multiple failed login/i,
		/repeated login attempt/i
	],
	credential_stuffing: [/credential/i, /stuffing/i, /combo/i, /credential dump/i],
	// SQL Injection - padrões mais robustos
	sql_injection: [
		/select\s+.*from/i,
		/union\s+select/i,
		/union\s+all\s+select/i,
		/insert\s+into/i,
		/delete\s+from/i,
		/update\s+.*set/i,
		/drop\s+table/i,
		/exec\s*\(/i,
		/execute\s*\(/i,
		/';?\s*(or|and)\s+['"]?\d+['"]?\s*=\s*['"]?\d+/i,
		/';?\s*(or|and)\s+['"]?1['"]?\s*=\s*['"]?1/i,
		/';?\s*(or|and)\s+['"]?1['"]?\s*=\s*['"]?2/i,
		/\bor\b\s*1\s*=\s*1\b/i,
		/\band\b\s*1\s*=\s*1\b/i,
		/(['"])\s*or\s*\1?\s*1\s*=\s*1/i,
		/\)\s*or\s*\(\s*'1'\s*=\s*'1'\s*\)/i,
		/';?\s*--/i,
		/';?\s*\/\*/i,
		/\/\*.*\*\//i,
		/benchmark\s*\(/i,
		/sleep\s*\(/i,
		/waitfor\s+delay/i,
		/pg_sleep\s*\(/i,
		/load_file\s*\(/i,
		/into\s+outfile/i,
		/into\s+dumpfile/i,
		/char\s*\(/i,
		/ascii\s*\(/i,
		/hex\s*\(/i,
		/convert\s*\(/i,
		/cast\s*\(/i
	],
	// XSS - padrões mais robustos
	xss: [
		/<script[^>]*>/i,
		/<\/script>/i,
		/javascript:/i,
		/onerror\s*=/i,
		/onload\s*=/i,
		/onclick\s*=/i,
		/onmouseover\s*=/i,
		/onfocus\s*=/i,
		/onblur\s*=/i,
		/onchange\s*=/i,
		/onsubmit\s*=/i,
		/<img[^>]*src\s*=\s*[^>]*javascript:/i,
		/<iframe[^>]*>/i,
		/<object[^>]*>/i,
		/<embed[^>]*>/i,
		/alert\s*\(/i,
		/prompt\s*\(/i,
		/confirm\s*\(/i,
		/document\.cookie/i,
		/document\.write/i,
		/eval\s*\(/i,
		/expression\s*\(/i,
		/vbscript:/i,
		/data:text\/html/i
	],
	// Path Traversal
	path_traversal: [
		/\.\.\/\.\.\//i,
		/\.\.\\\.\.\\/i,
		/\.\.%2f/i,
		/\.\.%5c/i,
		/%2e%2e%2f/i,
		/%2e%2e%5c/i,
		/\.\.%252f/i,
		/\.\.%255c/i,
		/\.\.\/\.\.\/\.\.\//i,
		/etc\/passwd/i,
		/proc\/self\/environ/i,
		/windows\/win\.ini/i,
		/\.\.\/\.\.\/\.\.\/\.\.\//i
	],
	// Command Injection
	command_injection: [
		/;\s*(ls|cat|pwd|whoami|id|uname|ps|netstat)/i,
		/\|\s*(ls|cat|pwd|whoami|id|uname|ps|netstat)/i,
		/&&\s*(ls|cat|pwd|whoami|id|uname|ps|netstat)/i,
		/\|\|\s*(ls|cat|pwd|whoami|id|uname|ps|netstat)/i,
		/`[^`]*(ls|cat|pwd|whoami|id|uname|ps|netstat)[^`]*`/i,
		/\$\([^)]*(ls|cat|pwd|whoami|id|uname|ps|netstat)[^)]*\)/i,
		/exec\s*\(/i,
		/system\s*\(/i,
		/passthru\s*\(/i,
		/shell_exec\s*\(/i,
		/proc_open\s*\(/i,
		/popen\s*\(/i
	],
	// NoSQL Injection
	nosql_injection: [
		/\$where/i,
		/\$ne/i,
		/\$gt/i,
		/\$lt/i,
		/\$gte/i,
		/\$lte/i,
		/\$in/i,
		/\$nin/i,
		/\$regex/i,
		/\$exists/i,
		/\$or/i,
		/\$and/i,
		/\$nor/i,
		/\$not/i,
		/\$elemMatch/i,
		/\$size/i,
		/\$type/i,
		/\$mod/i,
		/\$text/i,
		/\$geoWithin/i,
		/\$geoIntersects/i,
		/\$near/i,
		/\$nearSphere/i,
		/\$all/i,
		/\$slice/i,
		/\$comment/i,
		/\$explain/i,
		/\$hint/i,
		/\$maxScan/i,
		/\$maxTimeMS/i,
		/\$min/i,
		/\$max/i,
		/\$orderby/i,
		/\$query/i,
		/\$returnKey/i,
		/\$showDiskLoc/i,
		/\$natural/i
	],
	// XXE (XML External Entity)
	xxe: [
		/<!ENTITY/i,
		/%SYSTEM/i,
		/%PUBLIC/i,
		/<!DOCTYPE[^>]*\[/i,
		/<!ENTITY\s+\w+\s+SYSTEM/i,
		/<!ENTITY\s+\w+\s+PUBLIC/i,
		/&[a-zA-Z_][a-zA-Z0-9_]*;/i,
		/file:\/\//i,
		/php:\/\//i,
		/expect:\/\//i,
		/XXE/i,
		/xml external entity/i
	],
	man_in_the_middle: [/mitm/i, /man-in-the-middle/i, /ssl strip/i, /tls downgrade/i],
	ddos: [/ddos/i, /flood/i, /pps/i, /distributed denial/i, /traffic flood/i],
	engenharia_social: [/social/i, /engenharia/i, /social engineering/i],
	cve_exploit: [/cve-\d{4}-\d+/i, /exploit/i, /cve/i],
	apt: [/apt/i, /persistent/i, /advanced persistent threat/i],
	zero_day: [/zero[-\s]?day/i, /unknown exploit/i, /0-day/i],
	supply_chain: [/supply chain/i, /dependency/i, /supply-chain/i],
	fileless_malware: [/fileless/i, /memory-resident/i, /memory-only/i],
	polymorphic_malware: [/polymorphic/i, /mutation/i, /self-modifying/i],
	ransomware_lateral: [/lateral/i, /spread/i, /lateral movement/i],
	deepfake_phishing: [/deepfake/i, /voice clone/i, /synthetic media/i],
	adversarial_ai: [/adversarial/i, /model evasion/i, /ai attack/i],
	side_channel: [/side channel/i, /cache timing/i, /side-channel/i],
	firmware_bootloader: [/firmware/i, /uefi/i, /bootloader/i, /bios/i],
	bec: [/bec/i, /business email/i, /business email compromise/i],
	botnet: [/botnet/i, /c2/i, /command and control/i, /command-and-control/i],
	ot_ics: [/ics/i, /scada/i, /plc/i, /industrial control/i],
	quantum_attack: [/quantum/i, /post-quantum/i, /quantum computing/i]
};

const CRITICAS: ReadonlySet<SeveridadeSeguranca> = new Set(['alto', 'critico']);

const ataqueValidator = v.union(
	v.literal('phishing'),
	v.literal('malware'),
	v.literal('ransomware'),
	v.literal('brute_force'),
	v.literal('credential_stuffing'),
	v.literal('sql_injection'),
	v.literal('xss'),
	v.literal('path_traversal'),
	v.literal('command_injection'),
	v.literal('nosql_injection'),
	v.literal('xxe'),
	v.literal('man_in_the_middle'),
	v.literal('ddos'),
	v.literal('engenharia_social'),
	v.literal('cve_exploit'),
	v.literal('apt'),
	v.literal('zero_day'),
	v.literal('supply_chain'),
	v.literal('fileless_malware'),
	v.literal('polymorphic_malware'),
	v.literal('ransomware_lateral'),
	v.literal('deepfake_phishing'),
	v.literal('adversarial_ai'),
	v.literal('side_channel'),
	v.literal('firmware_bootloader'),
	v.literal('bec'),
	v.literal('botnet'),
	v.literal('ot_ics'),
	v.literal('quantum_attack')
);

const severidadeValidator = v.union(
	v.literal('informativo'),
	v.literal('baixo'),
	v.literal('moderado'),
	v.literal('alto'),
	v.literal('critico')
);

const statusValidator = v.union(
	v.literal('detectado'),
	v.literal('investigando'),
	v.literal('contido'),
	v.literal('falso_positivo'),
	v.literal('escalado'),
	v.literal('resolvido')
);

const indicadorCategoriaValidator = v.union(
	v.literal('ip'),
	v.literal('dominio'),
	v.literal('hash'),
	v.literal('email')
);

const portActionValidator = v.union(
	v.literal('permitir'),
	v.literal('bloquear'),
	v.literal('monitorar'),
	v.literal('rate_limit')
);

const protocoloValidator = v.union(
	v.literal('tcp'),
	v.literal('udp'),
	v.literal('icmp'),
	v.literal('quic'),
	v.literal('any')
);

const acaoIncidenteValidator = v.union(
	v.literal('block_ip'),
	v.literal('unblock_ip'),
	v.literal('block_port'),
	v.literal('liberar_porta'),
	v.literal('notificar'),
	v.literal('isolar_host'),
	v.literal('gerar_relatorio'),
	v.literal('criar_ticket'),
	v.literal('ajuste_regra'),
	v.literal('custom')
);

const acaoOrigemValidator = v.union(v.literal('automatico'), v.literal('manual'));

// Função para analisar string e detectar ataques
function analisarStringParaAtaques(texto: string): AtaqueCiberneticoTipo | null {
	if (!texto) return null;
	
	const textoLower = texto.toLowerCase();
	
	// Verificar cada tipo de ataque em ordem de prioridade
	for (const tipo of ATAQUES_PRIORITARIOS) {
		const patterns = KEYWORDS[tipo];
		if (patterns && patterns.some((regex) => regex.test(textoLower))) {
			return tipo;
		}
	}
	
	return null;
}

function inferirTipoAtaque(args: RegistroEventoArgs): AtaqueCiberneticoTipo {
	if (args.tipoAtaque) return args.tipoAtaque;

	const corpus = [
		args.descricao ?? '',
		args.mitreTechnique ?? '',
		args.tags?.join(' ') ?? '',
		...(args.indicadores ?? []).map((i) => `${i.tipo}:${i.valor}`)
	]
		.join(' ')
		.toLowerCase();

	// Usar função de análise melhorada
	const tipoDetectado = analisarStringParaAtaques(corpus);
	if (tipoDetectado) {
		return tipoDetectado;
	}

	// Detecções baseadas em métricas e portas
	if ((args.metricas?.pps ?? 0) > 120_000) {
		return 'ddos';
	}
	if ((args.destinoPorta === 3306 || args.destinoPorta === 1433) && corpus.includes('union')) {
		return 'sql_injection';
	}
	if (corpus.includes('tls downgrade')) {
		return 'man_in_the_middle';
	}

	return 'malware';
}

function calcularSeveridade(
	tipo: AtaqueCiberneticoTipo,
	metricas?: RegistroMetricas,
	sugerida?: SeveridadeSeguranca
): SeveridadeSeguranca {
	if (sugerida) return sugerida;
	const baseScore = SEVERIDADE_SCORE[BASE_SEVERIDADE[tipo] ?? 'moderado'];
	let score = baseScore;

	if ((metricas?.pps ?? 0) > 250_000) score += 1;
	if ((metricas?.bps ?? 0) > 1_000_000_000) score += 1;
	if ((metricas?.hostsAfetados ?? 0) > 50) score += 1;
	if ((metricas?.rpm ?? 0) > 10_000) score += 1;

	const bounded = Math.min(Math.max(score, 0), 4);
	return SCORE_SEVERIDADE[bounded] ?? 'moderado';
}

function statusInicial(severidade: SeveridadeSeguranca): StatusEventoSeguranca {
	if (severidade === 'critico') return 'escalado';
	if (severidade === 'alto') return 'investigando';
	return 'detectado';
}

async function ajustarReputacao(
	ctx: MutationCtx,
	indicador: string,
	categoria: 'ip' | 'dominio' | 'hash' | 'email',
	delta: number,
	severidade: SeveridadeSeguranca,
	opcoes?: { blacklist?: boolean; whitelist?: boolean; bloqueadoAte?: number }
) {
	const existente = await ctx.db
		.query('ipReputation')
		.withIndex('by_indicador', (q) => q.eq('indicador', indicador))
		.order('desc')
		.first();

	if (existente) {
		await ctx.db.patch(existente._id, {
			reputacao: Math.max(-100, Math.min(100, existente.reputacao + delta)),
			ultimoRegistro: Date.now(),
			bloqueadoAte: opcoes?.bloqueadoAte ?? existente.bloqueadoAte,
			blacklist: opcoes?.blacklist ?? existente.blacklist,
			whitelist: opcoes?.whitelist ?? existente.whitelist,
			severidadeMax:
				SEVERIDADE_SCORE[severidade] > SEVERIDADE_SCORE[existente.severidadeMax]
					? severidade
					: existente.severidadeMax,
			ocorrencias: existente.ocorrencias + 1
		});
		return existente._id;
	}

	return ctx.db.insert('ipReputation', {
		indicador,
		categoria,
		reputacao: Math.max(-100, Math.min(100, delta)),
		severidadeMax: severidade,
		whitelist: opcoes?.whitelist ?? false,
		blacklist: opcoes?.blacklist ?? false,
		ocorrencias: 1,
		primeiroRegistro: Date.now(),
		ultimoRegistro: Date.now(),
		bloqueadoAte: opcoes?.bloqueadoAte,
		origem: 'detector',
		comentarios: undefined,
		classificacoes: undefined,
		ultimaAcaoId: undefined
	});
}

export const registrarEventoSeguranca = mutation({
	args: {
		referencia: v.string(),
		sensorId: v.optional(v.id('networkSensors')),
		descricao: v.optional(v.string()),
		tipoAtaque: v.optional(ataqueValidator),
		severidade: v.optional(severidadeValidator),
		origemIp: v.optional(v.string()),
		destinoIp: v.optional(v.string()),
		destinoPorta: v.optional(v.number()),
		protocolo: v.optional(v.string()),
		transporte: v.optional(v.string()),
		origemRegiao: v.optional(v.string()),
		origemAsn: v.optional(v.string()),
		mitreTechnique: v.optional(v.string()),
		indicadores: v.optional(
			v.array(
				v.object({
					tipo: v.string(),
					valor: v.string(),
					confianca: v.optional(v.number())
				})
			)
		),
		metricas: v.optional(
			v.object({
				pps: v.optional(v.number()),
				bps: v.optional(v.number()),
				rpm: v.optional(v.number()),
				errosPorSegundo: v.optional(v.number()),
				hostsAfetados: v.optional(v.number())
			})
		),
		fingerprint: v.optional(
			v.object({
				userAgent: v.optional(v.string()),
				deviceId: v.optional(v.string()),
				ja3: v.optional(v.string()),
				tlsVersion: v.optional(v.string())
			})
		),
		geolocalizacao: v.optional(
			v.object({
				pais: v.optional(v.string()),
				regiao: v.optional(v.string()),
				cidade: v.optional(v.string()),
				latitude: v.optional(v.number()),
				longitude: v.optional(v.number())
			})
		),
		tags: v.optional(v.array(v.string()))
	},
	returns: v.object({
		eventoId: v.id('securityEvents'),
		severidade: severidadeValidator,
		novoRegistro: v.boolean()
	}),
	handler: async (ctx, args) => {
		// Aplicar rate limiting por IP se fornecido
		if (args.origemIp) {
			const rateLimitResult = await aplicarRateLimit(ctx, 'ip', args.origemIp, 'registrarEventoSeguranca');
			if (!rateLimitResult.permitido) {
				throw new Error(rateLimitResult.motivo ?? 'Rate limit excedido');
			}
		}

		const tipo = inferirTipoAtaque(args);
		const severidade = calcularSeveridade(tipo, args.metricas ?? undefined, args.severidade ?? undefined);
		const status = statusInicial(severidade);

		const duplicado = await ctx.db
			.query('securityEvents')
			.withIndex('by_referencia', (q) => q.eq('referencia', args.referencia))
			.order('desc')
			.first();

		if (duplicado) {
			await ctx.db.patch(duplicado._id, {
				severidade,
				status,
				atualizadoEm: Date.now(),
				descricao: args.descricao ?? duplicado.descricao,
				metricas: args.metricas ?? duplicado.metricas,
				tags: args.tags ?? duplicado.tags
			});

			return {
				eventoId: duplicado._id,
				severidade,
				novoRegistro: false
			};
		}

		const eventoId = await ctx.db.insert('securityEvents', {
			referencia: args.referencia,
			timestamp: Date.now(),
			tipoAtaque: tipo,
			severidade,
			status,
			descricao:
				args.descricao ??
				`Evento registrado automaticamente para ${tipo.toUpperCase().replace(/_/g, ' ')}.`,
			origemIp: args.origemIp,
			destinoIp: args.destinoIp,
			destinoPorta: args.destinoPorta,
			protocolo: args.protocolo,
			transporte: args.transporte,
			sensorId: args.sensorId,
			detectadoPor: args.sensorId ? 'sensor' : 'manual',
			mitreTechnique: args.mitreTechnique,
			origemRegiao: args.origemRegiao,
			origemAsn: args.origemAsn,
			geolocalizacao: args.geolocalizacao,
			fingerprint: args.fingerprint,
			indicadores: args.indicadores,
			metricas: args.metricas,
			tags: args.tags,
			referenciasExternas: undefined,
			correlacoes: undefined,
			criadoPor: undefined,
			atualizadoEm: Date.now()
		});

		if (args.origemIp) {
			const delta = CRITICAS.has(severidade) ? -30 : -10;
			const bloqueadoAte = CRITICAS.has(severidade) ? Date.now() + 60 * 60 * 1000 : undefined;
			await ajustarReputacao(ctx, args.origemIp, 'ip', delta, severidade, {
				blacklist: CRITICAS.has(severidade),
				bloqueadoAte
			});
		}

		if (CRITICAS.has(severidade)) {
			await ctx.scheduler.runAfter(0, internal.security.dispararAlertasInternos, {
				eventoId
			});
		}

		return { eventoId, severidade, novoRegistro: true };
	}
});

export const listarEventosSeguranca = query({
	args: {
		limit: v.optional(v.number()),
		apos: v.optional(v.number()),
		severidades: v.optional(v.array(severidadeValidator)),
		tiposAtaque: v.optional(v.array(ataqueValidator)),
		status: v.optional(v.array(statusValidator))
	},
	returns: v.array(
		v.object({
			_id: v.id('securityEvents'),
			timestamp: v.number(),
			tipoAtaque: ataqueValidator,
			severidade: severidadeValidator,
			status: statusValidator,
			descricao: v.string(),
			origemIp: v.optional(v.string()),
			destinoIp: v.optional(v.string()),
			destinoPorta: v.optional(v.number()),
			protocolo: v.optional(v.string()),
			tags: v.optional(v.array(v.string()))
		})
	),
	handler: async (ctx, args) => {
		const limit = args.limit && args.limit > 0 ? Math.min(args.limit, 500) : 100;
		const janelaInicial = args.apos ?? Date.now() - 6 * 60 * 60 * 1000;

		const { severidades, tiposAtaque, status } = args;

		let builder;
		if (severidades && severidades.length === 1) {
			const [severidade] = severidades;
			builder = ctx.db
				.query('securityEvents')
				.withIndex('by_severidade', (q) => q.eq('severidade', severidade));
		} else if (tiposAtaque && tiposAtaque.length === 1) {
			const [tipoAtaque] = tiposAtaque;
			builder = ctx.db
				.query('securityEvents')
				.withIndex('by_tipo', (q) => q.eq('tipoAtaque', tipoAtaque));
		} else if (status && status.length === 1) {
			const [estado] = status;
			builder = ctx.db
				.query('securityEvents')
				.withIndex('by_status', (q) => q.eq('status', estado));
		} else {
			builder = ctx.db
				.query('securityEvents')
				.withIndex('by_timestamp', (q) => q.gte('timestamp', janelaInicial));
		}

		const candidatos = await builder.order('desc').take(limit * 3);
		const filtrados = candidatos
			.filter((evento) => {
				if (args.severidades && args.severidades.length > 0 && !args.severidades.includes(evento.severidade)) {
					return false;
				}
				if (args.tiposAtaque && args.tiposAtaque.length > 0 && !args.tiposAtaque.includes(evento.tipoAtaque)) {
					return false;
				}
				if (args.status && args.status.length > 0 && !args.status.includes(evento.status)) {
					return false;
				}
				return true;
			})
			.slice(0, limit);

		return filtrados.map((evento) => ({
			_id: evento._id,
			timestamp: evento.timestamp,
			tipoAtaque: evento.tipoAtaque,
			severidade: evento.severidade,
			status: evento.status,
			descricao: evento.descricao,
			origemIp: evento.origemIp,
			destinoIp: evento.destinoIp,
			destinoPorta: evento.destinoPorta,
			protocolo: evento.protocolo,
			tags: evento.tags
		}));
	}
});

const ATAQUES_AVANCADOS: ReadonlySet<AtaqueCiberneticoTipo> = new Set([
	'apt',
	'zero_day',
	'supply_chain',
	'fileless_malware',
	'polymorphic_malware',
	'ransomware_lateral',
	'deepfake_phishing',
	'adversarial_ai',
	'side_channel',
	'firmware_bootloader',
	'botnet',
	'ot_ics',
	'quantum_attack'
]);

export const obterVisaoCamadas = query({
	args: {
		periodoHoras: v.optional(v.number()),
		buckets: v.optional(v.number())
	},
	returns: v.object({
		series: v.array(
			v.object({
				bucket: v.number(),
				inicio: v.number(),
				fim: v.number(),
				bloqueios: v.number(),
				ddos: v.number(),
				sqlInjection: v.number(),
				phishing: v.number(),
				avancados: v.number()
			})
		),
		totais: v.object({
			eventos: v.number(),
			criticos: v.number(),
			bloqueiosAtivos: v.number(),
			sensoresAtivos: v.number()
		})
	}),
	handler: async (ctx, args) => {
		const agora = Date.now();
		const periodoMs = Math.max(1, args.periodoHoras ?? 6) * 60 * 60 * 1000;
		const inicioJanela = agora - periodoMs;
		const bucketCount = Math.min(Math.max(args.buckets ?? 24, 4), 96);
		const bucketSize = Math.ceil(periodoMs / bucketCount);

		const eventos = await ctx.db
			.query('securityEvents')
			.withIndex('by_timestamp', (q) => q.gte('timestamp', inicioJanela))
			.order('asc')
			.collect();

		const series = Array.from({ length: bucketCount }, (_, index) => {
			const inicio = inicioJanela + index * bucketSize;
			return {
				bucket: index,
				inicio,
				fim: inicio + bucketSize,
				bloqueios: 0,
				ddos: 0,
				sqlInjection: 0,
				phishing: 0,
				avancados: 0
			};
		});

		let criticos = 0;

		for (const evento of eventos) {
			const idx = Math.min(
				bucketCount - 1,
				Math.max(
					0,
					Math.floor((evento.timestamp - inicioJanela) / bucketSize)
				)
			);
			const bucket = series[idx];
			if (evento.severidade === 'critico') criticos += 1;
			if (CRITICAS.has(evento.severidade)) bucket.bloqueios += 1;
			if (evento.tipoAtaque === 'ddos') bucket.ddos += 1;
			if (evento.tipoAtaque === 'sql_injection') bucket.sqlInjection += 1;
			if (evento.tipoAtaque === 'phishing' || evento.tipoAtaque === 'deepfake_phishing') {
				bucket.phishing += 1;
			}
			if (ATAQUES_AVANCADOS.has(evento.tipoAtaque)) bucket.avancados += 1;
		}

		const bloqueios = await ctx.db
			.query('ipReputation')
			.withIndex('by_blacklist', (q) => q.eq('blacklist', true))
			.collect();
		const bloqueiosAtivos = bloqueios.filter(
			(item) => !item.bloqueadoAte || item.bloqueadoAte > agora
		).length;

		const sensoresAtivos = await ctx.db
			.query('networkSensors')
			.withIndex('by_status', (q) => q.eq('status', 'ativo'))
			.collect();

		return {
			series,
			totais: {
				eventos: eventos.length,
				criticos,
				bloqueiosAtivos,
				sensoresAtivos: sensoresAtivos.length
			}
		};
	}
});

export const listarReputacoes = query({
	args: {
		limit: v.optional(v.number()),
		categoria: v.optional(indicadorCategoriaValidator),
		lista: v.optional(v.union(v.literal('blacklist'), v.literal('whitelist')))
	},
	returns: v.array(
		v.object({
			_id: v.id('ipReputation'),
			indicador: v.string(),
			categoria: indicadorCategoriaValidator,
			reputacao: v.number(),
			severidadeMax: severidadeValidator,
			whitelist: v.boolean(),
			blacklist: v.boolean(),
			bloqueadoAte: v.optional(v.number()),
			ocorrencias: v.number(),
			ultimoRegistro: v.number()
		})
	),
	handler: async (ctx, args) => {
		const limit = args.limit && args.limit > 0 ? Math.min(args.limit, 500) : 200;

		const builder = args.lista === undefined
			? ctx.db.query('ipReputation')
			: args.lista === 'blacklist'
				? ctx.db.query('ipReputation').withIndex('by_blacklist', (q) => q.eq('blacklist', true))
				: ctx.db.query('ipReputation').withIndex('by_whitelist', (q) => q.eq('whitelist', true));

		const docs = await builder.order('desc').take(limit * 2);
		const filtrados = docs
			.filter((doc) => {
				if (args.categoria && doc.categoria !== args.categoria) return false;
				return true;
			})
			.slice(0, limit);

		return filtrados.map((doc) => ({
			_id: doc._id,
			indicador: doc.indicador,
			categoria: doc.categoria,
			reputacao: doc.reputacao,
			severidadeMax: doc.severidadeMax,
			whitelist: doc.whitelist,
			blacklist: doc.blacklist,
			bloqueadoAte: doc.bloqueadoAte,
			ocorrencias: doc.ocorrencias,
			ultimoRegistro: doc.ultimoRegistro
		}));
	}
});

export const atualizarReputacaoIndicador = mutation({
	args: {
		usuarioId: v.id('usuarios'),
		indicador: v.string(),
		categoria: indicadorCategoriaValidator,
		acao: v.union(
			v.literal('forcar_blacklist'),
			v.literal('remover_blacklist'),
			v.literal('forcar_whitelist'),
			v.literal('remover_whitelist'),
			v.literal('ajustar_score'),
			v.literal('registrar_comentario')
		),
		delta: v.optional(v.number()),
		comentario: v.optional(v.string()),
		duracaoSegundos: v.optional(v.number())
	},
	returns: v.object({
		reputacaoId: v.id('ipReputation'),
		status: v.string()
	}),
	handler: async (ctx, args) => {
		// Aplicar rate limiting por usuário
		const rateLimitResult = await aplicarRateLimit(ctx, 'usuario', args.usuarioId, 'atualizarReputacaoIndicador');
		if (!rateLimitResult.permitido) {
			throw new Error(rateLimitResult.motivo ?? 'Rate limit excedido');
		}

		const existente = await ctx.db
			.query('ipReputation')
			.withIndex('by_indicador', (q) => q.eq('indicador', args.indicador))
			.order('desc')
			.first();

		const agora = Date.now();
		const bloqueioAte = args.duracaoSegundos ? agora + args.duracaoSegundos * 1000 : undefined;

		if (!existente) {
			const reputacaoId = await ctx.db.insert('ipReputation', {
				indicador: args.indicador,
				categoria: args.categoria,
				reputacao: args.delta ?? 0,
				severidadeMax: 'moderado',
				whitelist: args.acao === 'forcar_whitelist',
				blacklist: args.acao === 'forcar_blacklist',
				ocorrencias: 1,
				primeiroRegistro: agora,
				ultimoRegistro: agora,
				bloqueadoAte: bloqueioAte,
				origem: 'painel',
				comentarios: args.comentario,
				classificacoes: undefined,
				ultimaAcaoId: undefined
			});

			await ctx.db.insert('incidentActions', {
				eventoId: await ctx.db.insert('securityEvents', {
					referencia: `auto-${args.indicador}-${agora}`,
					timestamp: agora,
					tipoAtaque: 'engenharia_social',
					severidade: 'informativo',
					status: 'contido',
					descricao: 'Registro criado via painel de reputação.',
					origemIp: args.categoria === 'ip' ? args.indicador : undefined,
					destinoIp: undefined,
					destinoPorta: undefined,
					protocolo: undefined,
					transporte: undefined,
					sensorId: undefined,
					detectadoPor: 'manual',
					mitreTechnique: undefined,
					origemRegiao: undefined,
					origemAsn: undefined,
					geolocalizacao: undefined,
					fingerprint: undefined,
					indicadores: undefined,
					metricas: undefined,
					tags: ['reputacao'],
					referenciasExternas: undefined,
					correlacoes: undefined,
					criadoPor: args.usuarioId,
					atualizadoEm: agora
				}),
				tipo: args.acao === 'forcar_blacklist' ? 'block_ip' : 'custom',
				origem: 'manual',
				status: 'concluido',
				executadoPor: args.usuarioId,
				detalhes: args.comentario,
				resultado: 'Registro inicial',
				relacionadoA: undefined,
				criadoEm: agora,
				atualizadoEm: agora
			});

			return { reputacaoId, status: 'criado' };
		}

		const patch: Record<string, unknown> = {
			ultimoRegistro: agora
		};

		switch (args.acao) {
			case 'forcar_blacklist':
				patch.blacklist = true;
				patch.bloqueadoAte = bloqueioAte;
				break;
			case 'remover_blacklist':
				patch.blacklist = false;
				patch.bloqueadoAte = undefined;
				break;
			case 'forcar_whitelist':
				patch.whitelist = true;
				break;
			case 'remover_whitelist':
				patch.whitelist = false;
				break;
			case 'ajustar_score':
				patch.reputacao = Math.max(
					-100,
					Math.min(100, (existente.reputacao ?? 0) + (args.delta ?? 0))
				);
				break;
			case 'registrar_comentario':
				patch.comentarios = args.comentario;
				break;
		}

		await ctx.db.patch(existente._id, patch);

		return { reputacaoId: existente._id, status: 'atualizado' };
	}
});

export const configurarRegraPorta = mutation({
	args: {
		usuarioId: v.id('usuarios'),
		regraId: v.optional(v.id('portRules')),
		porta: v.number(),
		protocolo: protocoloValidator,
		acao: portActionValidator,
		temporario: v.boolean(),
		duracaoSegundos: v.optional(v.number()),
		severidadeMin: severidadeValidator,
		notas: v.optional(v.string()),
		tags: v.optional(v.array(v.string())),
		listaReferencia: v.optional(v.id('ipReputation'))
	},
	returns: v.object({
		regraId: v.id('portRules'),
		status: v.string()
	}),
	handler: async (ctx, args) => {
		const agora = Date.now();
		const expiraEm = args.temporario && args.duracaoSegundos ? agora + args.duracaoSegundos * 1000 : undefined;

		if (args.regraId) {
			await ctx.db.patch(args.regraId, {
				porta: args.porta,
				protocolo: args.protocolo,
				acao: args.acao,
				temporario: args.temporario,
				duracaoSegundos: args.duracaoSegundos,
				expiraEm,
				atualizadoPor: args.usuarioId,
				atualizadoEm: agora,
				severidadeMin: args.severidadeMin,
				notas: args.notas,
				tags: args.tags,
				listaReferencia: args.listaReferencia
			});
			return { regraId: args.regraId, status: 'atualizado' };
		}

		const regraId = await ctx.db.insert('portRules', {
			porta: args.porta,
			protocolo: args.protocolo,
			acao: args.acao,
			temporario: args.temporario,
			severidadeMin: args.severidadeMin,
			duracaoSegundos: args.duracaoSegundos,
			expiraEm,
			criadoPor: args.usuarioId,
			atualizadoPor: args.usuarioId,
			criadoEm: agora,
			atualizadoEm: agora,
			notas: args.notas,
			tags: args.tags,
			listaReferencia: args.listaReferencia
		});

		return { regraId, status: 'criado' };
	}
});

export const listarRegrasPorta = query({
	args: {
		acao: v.optional(portActionValidator),
		ativo: v.optional(v.boolean())
	},
	returns: v.array(
		v.object({
			_id: v.id('portRules'),
			porta: v.number(),
			protocolo: protocoloValidator,
			acao: portActionValidator,
			temporario: v.boolean(),
			expiraEm: v.optional(v.number()),
			severidadeMin: severidadeValidator,
			tags: v.optional(v.array(v.string())),
			notas: v.optional(v.string())
		})
	),
	handler: async (ctx, args) => {
		const builder =
			args.acao === undefined
				? ctx.db.query('portRules')
				: ctx.db.query('portRules').withIndex('by_acao', (q) => {
						const acao = args.acao;
						return q.eq('acao', acao as 'permitir' | 'bloquear' | 'monitorar' | 'rate_limit');
					});

		const docs = await builder.order('desc').take(200);
		const filtrados = docs.filter((doc) => {
			if (args.ativo === undefined) return true;
			if (!doc.temporario) return true;
			if (!doc.expiraEm) return !args.ativo;
			const aindaValido = doc.expiraEm > Date.now();
			return args.ativo ? aindaValido : !aindaValido;
		});

		return filtrados.map((doc) => ({
			_id: doc._id,
			porta: doc.porta,
			protocolo: doc.protocolo,
			acao: doc.acao,
			temporario: doc.temporario,
			expiraEm: doc.expiraEm,
			severidadeMin: doc.severidadeMin,
			tags: doc.tags,
			notas: doc.notas
		}));
	}
});

export const registrarAcaoIncidente = mutation({
	args: {
		eventoId: v.id('securityEvents'),
		tipo: acaoIncidenteValidator,
		origem: acaoOrigemValidator,
		executadoPor: v.optional(v.id('usuarios')),
		status: v.optional(v.union(v.literal('pendente'), v.literal('executando'), v.literal('concluido'), v.literal('falhou'))),
		detalhes: v.optional(v.string()),
		resultado: v.optional(v.string()),
		relacionadoA: v.optional(v.id('ipReputation'))
	},
	returns: v.object({
		acaoId: v.id('incidentActions')
	}),
	handler: async (ctx, args) => {
		const agora = Date.now();
		const acaoId = await ctx.db.insert('incidentActions', {
			eventoId: args.eventoId,
			tipo: args.tipo,
			origem: args.origem,
			status: args.status ?? 'concluido',
			executadoPor: args.executadoPor,
			detalhes: args.detalhes,
			resultado: args.resultado,
			relacionadoA: args.relacionadoA,
			criadoEm: agora,
			atualizadoEm: agora
		});

		return { acaoId };
	}
});

export const solicitarRelatorioSeguranca = mutation({
	args: {
		solicitanteId: v.id('usuarios'),
		filtros: v.object({
			dataInicio: v.number(),
			dataFim: v.number(),
			severidades: v.optional(v.array(severidadeValidator)),
			tiposAtaque: v.optional(v.array(ataqueValidator)),
			incluirIndicadores: v.optional(v.boolean()),
			incluirMetricas: v.optional(v.boolean()),
			incluirAcoes: v.optional(v.boolean())
		})
	},
	returns: v.object({
		relatorioId: v.id('reportRequests')
	}),
	handler: async (ctx, args) => {
		const relatorioId = await ctx.db.insert('reportRequests', {
			solicitanteId: args.solicitanteId,
			filtros: {
				dataInicio: args.filtros.dataInicio,
				dataFim: args.filtros.dataFim,
				severidades: args.filtros.severidades,
				tiposAtaque: args.filtros.tiposAtaque,
				incluirIndicadores: args.filtros.incluirIndicadores,
				incluirMetricas: args.filtros.incluirMetricas,
				incluirAcoes: args.filtros.incluirAcoes
			},
			status: 'pendente',
			resultadoId: undefined,
			observacoes: undefined,
			criadoEm: Date.now(),
			atualizadoEm: Date.now(),
			concluidoEm: undefined,
			erro: undefined
		});

		await ctx.scheduler.runAfter(0, internal.security.processarRelatorioSegurancaInternal, {
			relatorioId
		});

		return { relatorioId };
	}
});

// Lista relatórios recentes para exibição no dashboard
export const listarRelatoriosRecentes = query({
	args: {
		limit: v.optional(v.number())
	},
	returns: v.array(
		v.object({
			_id: v.id('reportRequests'),
			status: v.union(
				v.literal('pendente'),
				v.literal('processando'),
				v.literal('concluido'),
				v.literal('falhou')
			),
			criadoEm: v.number(),
			concluidoEm: v.optional(v.number()),
			observacoes: v.optional(v.string())
		})
	),
	handler: async (ctx, args) => {
		const max = Math.min(args.limit ?? 10, 50);
		const rows = await ctx.db
			.query('reportRequests')
			.withIndex('by_criado_em', (q) => q.gte('criadoEm', 0))
			.order('desc')
			.take(max);
		return rows.map((r) => ({
			_id: r._id,
			status: r.status,
			criadoEm: r.criadoEm,
			concluidoEm: r.concluidoEm,
			observacoes: r.observacoes
		}));
	}
});

// Health check leve para o dashboard
export const healthStatus = query({
	args: {},
	returns: v.object({
		ok: v.boolean(),
		now: v.number(),
		pendingReports: v.number()
	}),
	handler: async (ctx) => {
		// Contar rapidamente quantos relatórios pendentes existem (limitado)
		const pending = await ctx.db
			.query('reportRequests')
			.withIndex('by_status', (q) => q.eq('status', 'pendente'))
			.take(1);
		return {
			ok: true,
			now: Date.now(),
			pendingReports: pending.length
		};
	}
});
/**
 * Excluir relatório gerado (e artefato, se houver)
 */
export const deletarRelatorio = mutation({
	args: {
		relatorioId: v.id('reportRequests')
	},
	returns: v.object({ success: v.boolean() }),
	handler: async (ctx, args) => {
		const doc = await ctx.db.get(args.relatorioId);
		if (!doc) {
			return { success: false };
		}
		// Remover arquivo em storage se existir
		if (doc.resultadoId) {
			try {
				await ctx.storage.delete(doc.resultadoId);
			} catch {
				// Ignorar falha ao excluir artefato de storage
			}
		}
		await ctx.db.delete(args.relatorioId);
		return { success: true };
	}
});
export const processarRelatorioSegurancaInternal = internalMutation({
	args: {
		relatorioId: v.id('reportRequests')
	},
	returns: v.null(),
	handler: async (ctx, args) => {
		const relatorio = await ctx.db.get(args.relatorioId);
		if (!relatorio || relatorio.status !== 'pendente') return null;

		const eventos = await ctx.db
			.query('securityEvents')
			.withIndex('by_timestamp', (q) =>
				q
					.gte('timestamp', relatorio.filtros.dataInicio)
					.lte('timestamp', relatorio.filtros.dataFim)
			)
			.collect();

		const filtrados = eventos.filter((evento) => {
			if (
				relatorio.filtros.severidades &&
				relatorio.filtros.severidades.length > 0 &&
				!relatorio.filtros.severidades.includes(evento.severidade)
			) {
			 return false;
			}
			if (
				relatorio.filtros.tiposAtaque &&
				relatorio.filtros.tiposAtaque.length > 0 &&
				!relatorio.filtros.tiposAtaque.includes(evento.tipoAtaque)
			) {
			 return false;
			}
			return true;
		});

		const porSeveridade = filtrados.reduce<Record<SeveridadeSeguranca, number>>(
			(acc, evento) => {
				acc[evento.severidade] = (acc[evento.severidade] ?? 0) + 1;
				return acc;
			},
			{
				informativo: 0,
				baixo: 0,
				moderado: 0,
				alto: 0,
				critico: 0
			}
		);

		const porAtaque = filtrados.reduce<Record<string, number>>((acc, evento) => {
			acc[evento.tipoAtaque] = (acc[evento.tipoAtaque] ?? 0) + 1;
			return acc;
		}, {});

		const observacoes = JSON.stringify({
			total: filtrados.length,
			porSeveridade,
			porAtaque,
			incluiuIndicadores: relatorio.filtros.incluirIndicadores ?? false,
			incluiuMetricas: relatorio.filtros.incluirMetricas ?? false,
			incluiuAcoes: relatorio.filtros.incluirAcoes ?? false
		});

		await ctx.db.patch(relatorio._id, {
			status: 'concluido',
			observacoes,
			atualizadoEm: Date.now(),
			concluidoEm: Date.now()
		});

		return null;
	}
});

// ---------- Alertas (email/chat) ----------
export const listarAlertConfigs = query({
	args: { limit: v.optional(v.number()) },
	returns: v.array(
		v.object({
			_id: v.id('alertConfigs'),
			nome: v.string(),
			canais: v.object({ email: v.boolean(), chat: v.boolean() }),
			emails: v.array(v.string()),
			chatUsers: v.array(v.string()),
			severidadeMin: severidadeValidator,
			tiposAtaque: v.optional(v.array(ataqueValidator)),
			reenvioMin: v.number(),
			criadoEm: v.number(),
			atualizadoEm: v.number()
		})
	),
	handler: async (ctx, args) => {
		const max = Math.min(args.limit ?? 100, 200);
		const rows = await ctx.db
			.query('alertConfigs')
			.withIndex('by_criadoEm', (q) => q.gte('criadoEm', 0))
			.order('desc')
			.take(max);
		return rows.map((r) => ({
			_id: r._id,
			nome: r.nome,
			canais: r.canais,
			emails: r.emails,
			chatUsers: r.chatUsers,
			severidadeMin: r.severidadeMin,
			tiposAtaque: r.tiposAtaque,
			reenvioMin: r.reenvioMin,
			criadoEm: r.criadoEm,
			atualizadoEm: r.atualizadoEm
		}));
	}
});

export const salvarAlertConfig = mutation({
	args: {
		configId: v.optional(v.id('alertConfigs')),
		nome: v.string(),
		canais: v.object({ email: v.boolean(), chat: v.boolean() }),
		emails: v.array(v.string()),
		chatUsers: v.array(v.string()),
		severidadeMin: severidadeValidator,
		tiposAtaque: v.optional(v.array(ataqueValidator)),
		reenvioMin: v.number(),
		criadoPor: v.id('usuarios')
	},
	returns: v.object({ _id: v.id('alertConfigs') }),
	handler: async (ctx, args) => {
		const agora = Date.now();
		if (args.configId) {
			await ctx.db.patch(args.configId, {
				nome: args.nome,
				canais: args.canais,
				emails: args.emails,
				chatUsers: args.chatUsers,
				severidadeMin: args.severidadeMin,
				tiposAtaque: args.tiposAtaque,
				reenvioMin: args.reenvioMin,
				atualizadoEm: agora
			});
			return { _id: args.configId };
		}
		const id = await ctx.db.insert('alertConfigs', {
			nome: args.nome,
			canais: args.canais,
			emails: args.emails,
			chatUsers: args.chatUsers,
			severidadeMin: args.severidadeMin,
			tiposAtaque: args.tiposAtaque,
			reenvioMin: args.reenvioMin,
			criadoPor: args.criadoPor,
			criadoEm: agora,
			atualizadoEm: agora
		});
		return { _id: id };
	}
});

export const deletarAlertConfig = mutation({
	args: { configId: v.id('alertConfigs') },
	returns: v.null(),
	handler: async (ctx, args) => {
		await ctx.db.delete(args.configId);
		return null;
	}
});
export const dispararAlertasInternos = internalMutation({
	args: {
		eventoId: v.id('securityEvents')
	},
	returns: v.null(),
	handler: async (ctx, args) => {
		const evento = await ctx.db.get(args.eventoId);
		if (!evento) return null;

		const rolesTi = await ctx.db
			.query('roles')
			.withIndex('by_nivel', (q) => q.lte('nivel', 1))
			.collect();

		const usuariosNotificados: Id<'usuarios'>[] = [];

		for (const role of rolesTi) {
			const membros = await ctx.db.query('usuarios').withIndex('by_role', (q) => q.eq('roleId', role._id)).collect();
			for (const usuario of membros) {
				usuariosNotificados.push(usuario._id);
			}
		}

		for (const usuarioId of usuariosNotificados) {
			await ctx.db.insert('notificacoes', {
				usuarioId,
				tipo: 'alerta_seguranca',
				conversaId: undefined,
				mensagemId: undefined,
				remetenteId: undefined,
				titulo: `🚨 ${evento.severidade.toUpperCase()} - ${evento.tipoAtaque.replace(/_/g, ' ')}`,
				descricao: evento.descricao,
				lida: false,
				criadaEm: Date.now()
			});
		}

		return null;
	}
});

export const expirarBloqueiosIpAutomaticos = internalMutation({
	args: {},
	returns: v.null(),
	handler: async (ctx) => {
		const agora = Date.now();
		const bloqueios = await ctx.db
			.query('ipReputation')
			.withIndex('by_blacklist', (q) => q.eq('blacklist', true))
			.collect();

		for (const registro of bloqueios) {
			if (registro.bloqueadoAte && registro.bloqueadoAte <= agora) {
				await ctx.db.patch(registro._id, {
					blacklist: false,
					bloqueadoAte: undefined
				});
			}
		}

		const regras = await ctx.db
			.query('portRules')
			.withIndex('by_expiracao', (q) => q.lte('expiraEm', agora))
			.collect();

		for (const regra of regras) {
			if (regra.temporario && regra.expiraEm && regra.expiraEm <= agora) {
				await ctx.db.patch(regra._id, {
					acao: 'monitorar',
					temporario: false,
					expiraEm: undefined
				});
			}
		}

		return null;
	}
});

export const atualizarThreatIntelFeedsInternal = internalMutation({
	args: {},
	returns: v.null(),
	handler: async (ctx) => {
		const feeds = await ctx.db
			.query('threatIntelFeeds')
			.withIndex('by_ativo', (q) => q.eq('ativo', true))
			.collect();

		for (const feed of feeds) {
			const entradasSimuladas = Math.floor(Math.random() * 25) + 5;
			await ctx.db.patch(feed._id, {
				ultimaSincronizacao: Date.now(),
				entradasProcessadas: (feed.entradasProcessadas ?? 0) + entradasSimuladas,
				errosConsecutivos: 0
			});
		}

		return null;
	}
});

// Helper para aplicar rate limiting baseado em configurações usando @convex-dev/rate-limiter
async function aplicarRateLimit(
	ctx: QueryCtx | MutationCtx,
	tipo: 'ip' | 'usuario' | 'endpoint' | 'global',
	identificador: string,
	endpoint?: string
): Promise<{ permitido: boolean; motivo?: string; retryAfter?: number }> {
	const configs = await ctx.db
		.query('rateLimitConfig')
		.withIndex('by_tipo_identificador', (q) => q.eq('tipo', tipo).eq('identificador', identificador))
		.filter((q) => q.eq(q.field('ativo'), true))
		.collect();

	let config;
	if (configs.length === 0) {
		// Verificar configuração global
		const globalConfigs = await ctx.db
			.query('rateLimitConfig')
			.withIndex('by_tipo_identificador', (q) => q.eq('tipo', 'global').eq('identificador', 'global'))
			.filter((q) => q.eq(q.field('ativo'), true))
			.collect();

		if (globalConfigs.length === 0) {
			return { permitido: true };
		}

		config = globalConfigs.sort((a, b) => b.prioridade - a.prioridade)[0];
	} else {
		config = configs.sort((a, b) => b.prioridade - a.prioridade)[0];
	}

	// Converter janelaSegundos para período do rate-limiter
	const periodo = config.janelaSegundos * SECOND;
	
	// Determinar estratégia baseada na configuração
	// O rate-limiter suporta apenas 'token bucket' e 'fixed window'
	const kind: 'token bucket' | 'fixed window' = config.estrategia === 'token_bucket' ? 'token bucket' : 'fixed window';

	// Criar namespace único para este rate limit
	const namespace = `${tipo}:${identificador}:${endpoint ?? 'default'}`;

	// Criar instância do RateLimiter com configuração dinâmica
	// Usar type assertion para permitir configuração dinâmica
	const rateLimiterConfig = {
		[namespace]: {
			kind,
			rate: config.limite,
			period: periodo,
			...(config.estrategia === 'token_bucket' ? { capacity: config.limite } : {})
		}
	} as Record<string, { kind: 'token bucket' | 'fixed window'; rate: number; period: number; capacity?: number }>;

	const rateLimiter = new RateLimiter(components.rateLimiter, rateLimiterConfig);

	// Verificar rate limit
	const result = await rateLimiter.check(ctx, namespace, {
		key: identificador
	});

	if (!result.ok) {
		const retryAfter = result.retryAfter ?? periodo;
		
		if (config.acaoExcedido === 'bloquear') {
			return {
				permitido: false,
				motivo: `Bloqueado por rate limit: ${config.limite} requisições por ${config.janelaSegundos}s`,
				retryAfter
			};
		} else if (config.acaoExcedido === 'alertar') {
			// Permitir mas registrar alerta
			return { permitido: true };
		}
		// throttle - permitir mas com delay
		return {
			permitido: true,
			retryAfter
		};
	}

	// Aplicar o limite (consumir token) apenas em mutations
	// Verificar se é MutationCtx tentando usar limit (que só funciona em mutations)
	if ('runMutation' in ctx) {
		await rateLimiter.limit(ctx as MutationCtx, namespace, {
			key: identificador,
			throws: false
		});
	}

	return { permitido: true };
}

export const criarConfigRateLimit = mutation({
	args: {
		usuarioId: v.id('usuarios'),
		nome: v.string(),
		tipo: v.union(v.literal('ip'), v.literal('usuario'), v.literal('endpoint'), v.literal('global')),
		identificador: v.optional(v.string()),
		limite: v.number(),
		janelaSegundos: v.number(),
		estrategia: v.union(
			v.literal('fixed_window'),
			v.literal('sliding_window'),
			v.literal('token_bucket')
		),
		acaoExcedido: v.union(v.literal('bloquear'), v.literal('throttle'), v.literal('alertar')),
		bloqueioTemporarioSegundos: v.optional(v.number()),
		prioridade: v.optional(v.number()),
		notas: v.optional(v.string()),
		tags: v.optional(v.array(v.string()))
	},
	returns: v.id('rateLimitConfig'),
	handler: async (ctx, args) => {
		const agora = Date.now();
		const configId = await ctx.db.insert('rateLimitConfig', {
			nome: args.nome,
			tipo: args.tipo,
			identificador: args.identificador ?? (args.tipo === 'global' ? 'global' : undefined),
			limite: args.limite,
			janelaSegundos: args.janelaSegundos,
			estrategia: args.estrategia,
			acaoExcedido: args.acaoExcedido,
			bloqueioTemporarioSegundos: args.bloqueioTemporarioSegundos,
			ativo: true,
			prioridade: args.prioridade ?? 0,
			criadoPor: args.usuarioId,
			atualizadoPor: undefined,
			criadoEm: agora,
			atualizadoEm: agora,
			notas: args.notas,
			tags: args.tags
		});

		return configId;
	}
});

export const atualizarConfigRateLimit = mutation({
	args: {
		configId: v.id('rateLimitConfig'),
		usuarioId: v.id('usuarios'),
		nome: v.optional(v.string()),
		limite: v.optional(v.number()),
		janelaSegundos: v.optional(v.number()),
		estrategia: v.optional(
			v.union(
				v.literal('fixed_window'),
				v.literal('sliding_window'),
				v.literal('token_bucket')
			)
		),
		acaoExcedido: v.optional(v.union(v.literal('bloquear'), v.literal('throttle'), v.literal('alertar'))),
		bloqueioTemporarioSegundos: v.optional(v.number()),
		ativo: v.optional(v.boolean()),
		prioridade: v.optional(v.number()),
		notas: v.optional(v.string()),
		tags: v.optional(v.array(v.string()))
	},
	returns: v.null(),
	handler: async (ctx, args) => {
		const config = await ctx.db.get(args.configId);
		if (!config) {
			throw new Error('Configuração de rate limit não encontrada');
		}

		const atualizacoes: {
			nome?: string;
			limite?: number;
			janelaSegundos?: number;
			estrategia?: 'fixed_window' | 'sliding_window' | 'token_bucket';
			acaoExcedido?: 'bloquear' | 'throttle' | 'alertar';
			bloqueioTemporarioSegundos?: number;
			ativo?: boolean;
			prioridade?: number;
			notas?: string;
			tags?: string[];
			atualizadoPor: Id<'usuarios'>;
			atualizadoEm: number;
		} = {
			atualizadoPor: args.usuarioId,
			atualizadoEm: Date.now()
		};

		if (args.nome !== undefined) atualizacoes.nome = args.nome;
		if (args.limite !== undefined) atualizacoes.limite = args.limite;
		if (args.janelaSegundos !== undefined) atualizacoes.janelaSegundos = args.janelaSegundos;
		if (args.estrategia !== undefined) atualizacoes.estrategia = args.estrategia;
		if (args.acaoExcedido !== undefined) atualizacoes.acaoExcedido = args.acaoExcedido;
		if (args.bloqueioTemporarioSegundos !== undefined)
			atualizacoes.bloqueioTemporarioSegundos = args.bloqueioTemporarioSegundos;
		if (args.ativo !== undefined) atualizacoes.ativo = args.ativo;
		if (args.prioridade !== undefined) atualizacoes.prioridade = args.prioridade;
		if (args.notas !== undefined) atualizacoes.notas = args.notas;
		if (args.tags !== undefined) atualizacoes.tags = args.tags;

		await ctx.db.patch(args.configId, atualizacoes);
		return null;
	}
});

export const listarConfigsRateLimit = query({
	args: {
		tipo: v.optional(v.union(v.literal('ip'), v.literal('usuario'), v.literal('endpoint'), v.literal('global'))),
		ativo: v.optional(v.boolean()),
		limit: v.optional(v.number())
	},
	returns: v.array(
		v.object({
			_id: v.id('rateLimitConfig'),
			nome: v.string(),
			tipo: v.union(v.literal('ip'), v.literal('usuario'), v.literal('endpoint'), v.literal('global')),
			identificador: v.optional(v.string()),
			limite: v.number(),
			janelaSegundos: v.number(),
			estrategia: v.union(
				v.literal('fixed_window'),
				v.literal('sliding_window'),
				v.literal('token_bucket')
			),
			acaoExcedido: v.union(v.literal('bloquear'), v.literal('throttle'), v.literal('alertar')),
			bloqueioTemporarioSegundos: v.optional(v.number()),
			ativo: v.boolean(),
			prioridade: v.number(),
			notas: v.optional(v.string()),
			tags: v.optional(v.array(v.string()))
		})
	),
	handler: async (ctx, args) => {
		let builder;
		if (args.tipo !== undefined) {
			const tipo = args.tipo;
			builder = ctx.db
				.query('rateLimitConfig')
				.withIndex('by_tipo_identificador', (q) => q.eq('tipo', tipo));
		} else if (args.ativo !== undefined) {
			const ativo = args.ativo;
			builder = ctx.db.query('rateLimitConfig').withIndex('by_ativo', (q) => q.eq('ativo', ativo));
		} else {
			builder = ctx.db.query('rateLimitConfig');
		}

		const configs = await builder.order('desc').take(args.limit ?? 100);
		return configs.map((config) => ({
			_id: config._id,
			nome: config.nome,
			tipo: config.tipo,
			identificador: config.identificador,
			limite: config.limite,
			janelaSegundos: config.janelaSegundos,
			estrategia: config.estrategia,
			acaoExcedido: config.acaoExcedido,
			bloqueioTemporarioSegundos: config.bloqueioTemporarioSegundos,
			ativo: config.ativo,
			prioridade: config.prioridade,
			notas: config.notas,
			tags: config.tags
		}));
	}
});

// ============================================
// DETECÇÃO AUTOMÁTICA DE ATAQUES
// ============================================

/**
 * Analisa uma requisição HTTP e detecta possíveis ataques
 * Esta função pode ser chamada de interceptores HTTP ou middlewares
 */
export const analisarRequisicaoHTTP = mutation({
	args: {
		url: v.string(),
		method: v.string(),
		headers: v.optional(v.record(v.string(), v.string())),
		body: v.optional(v.string()),
		queryParams: v.optional(v.record(v.string(), v.string())),
		ipOrigem: v.optional(v.string()),
		userAgent: v.optional(v.string())
	},
	returns: v.object({
		ataqueDetectado: v.boolean(),
		tipoAtaque: v.optional(ataqueValidator),
		severidade: v.optional(severidadeValidator),
		eventoId: v.optional(v.id('securityEvents'))
	}),
	handler: async (ctx, args) => {
		// Combinar todos os dados da requisição para análise
		const dadosParaAnalise = [
			args.url,
			args.method,
			args.body ?? '',
			Object.entries(args.queryParams ?? {}).map(([k, v]) => `${k}=${v}`).join('&'),
			Object.entries(args.headers ?? {}).map(([k, v]) => `${k}:${v}`).join('\n'),
			args.userAgent ?? ''
		].join('\n');

		// Detectar tipo de ataque
		const tipoAtaque = analisarStringParaAtaques(dadosParaAnalise);

		if (!tipoAtaque) {
			return {
				ataqueDetectado: false,
				tipoAtaque: undefined,
				severidade: undefined,
				eventoId: undefined
			};
		}

		// Calcular severidade
		const severidade = calcularSeveridade(tipoAtaque, undefined, undefined);

		// Permitir que o chamador informe o destino/protocolo via query string em cenários de dev/teste
		const destinoIp =
			(args.queryParams && (args.queryParams['dst'] || args.queryParams['dest'] || args.queryParams['destino'])) ||
			undefined;
		const protocolo = (args.queryParams && (args.queryParams['proto'] as string)) || 'http';

		// Registrar evento de segurança
		const referencia = `http_${Date.now()}_${Math.random().toString(36).substring(7)}`;
		const agora = Date.now();
		const eventoId = await ctx.db.insert('securityEvents', {
			referencia,
			timestamp: agora,
			tipoAtaque,
			severidade,
			status: statusInicial(severidade),
			descricao: `Ataque ${tipoAtaque} detectado na requisição HTTP ${args.method} ${args.url}`,
			origemIp: args.ipOrigem,
			protocolo,
			transporte: 'tcp',
			detectadoPor: 'analisador_http_automatico',
			fingerprint: args.userAgent ? {
				userAgent: args.userAgent
			} : undefined,
			destinoIp: destinoIp ?? undefined,
			tags: ['detecção_automática', 'http', tipoAtaque],
			atualizadoEm: agora
		});

		// Ajustar reputação do IP se fornecido
		if (args.ipOrigem) {
			const delta = SEVERIDADE_SCORE[severidade] * -10; // Penalidade baseada na severidade
			await ajustarReputacao(
				ctx,
				args.ipOrigem,
				'ip',
				delta,
				severidade,
				severidade === 'critico' || severidade === 'alto' ? { blacklist: true } : undefined
			);
		}

		return {
			ataqueDetectado: true,
			tipoAtaque,
			severidade,
			eventoId
		};
	}
});

/**
 * Detecta ataques de brute force baseado em logs de login
 * Esta função deve ser chamada periodicamente ou após múltiplas tentativas falhas
 */
export const detectarBruteForce = internalMutation({
	args: {
		ipAddress: v.optional(v.string()),
		usuarioId: v.optional(v.id('usuarios')),
		janelaMinutos: v.optional(v.number()) // padrão 15 minutos
	},
	returns: v.object({
		ataqueDetectado: v.boolean(),
		tentativasFalhas: v.number(),
		eventoId: v.optional(v.id('securityEvents'))
	}),
	handler: async (ctx, args) => {
		// Sensibilidade maior em dev: janela menor
		const janelaMinutos = args.janelaMinutos ?? 10;
		const dataLimite = Date.now() - janelaMinutos * 60 * 1000;

		// Buscar tentativas de login falhas
		let tentativasFalhas;
		if (args.ipAddress) {
			tentativasFalhas = await ctx.db
				.query('logsLogin')
				.withIndex('by_ip', (q) => q.eq('ipAddress', args.ipAddress))
				.filter((q) => 
					q.gte(q.field('timestamp'), dataLimite) &&
					q.eq(q.field('sucesso'), false)
				)
				.collect();
		} else if (args.usuarioId) {
			tentativasFalhas = await ctx.db
				.query('logsLogin')
				.withIndex('by_usuario', (q) => q.eq('usuarioId', args.usuarioId))
				.filter((q) => 
					q.gte(q.field('timestamp'), dataLimite) &&
					q.eq(q.field('sucesso'), false)
				)
				.collect();
		} else {
			// Buscar todas as tentativas falhas na janela
			tentativasFalhas = await ctx.db
				.query('logsLogin')
				.withIndex('by_sucesso', (q) => q.eq('sucesso', false))
				.filter((q) => q.gte(q.field('timestamp'), dataLimite))
				.collect();
		}

		// Agrupar por IP para detectar padrões
		const tentativasPorIP: Record<string, number> = {};
		tentativasFalhas.forEach((t) => {
			if (t.ipAddress) {
				tentativasPorIP[t.ipAddress] = (tentativasPorIP[t.ipAddress] || 0) + 1;
			}
		});

		// Detectar IPs suspeitos (3+ tentativas falhas em dev)
		const ipsSuspeitos = Object.entries(tentativasPorIP)
			.filter(([, count]) => count >= 3)
			.map(([ip, count]) => ({ ip, count }));

		if (ipsSuspeitos.length === 0) {
			return {
				ataqueDetectado: false,
				tentativasFalhas: tentativasFalhas.length,
				eventoId: undefined
			};
		}

		// Registrar eventos para cada IP suspeito
		const eventosIds: Id<'securityEvents'>[] = [];

		for (const { ip, count } of ipsSuspeitos) {
			const severidade: SeveridadeSeguranca = count >= 8 ? 'alto' : count >= 5 ? 'moderado' : 'baixo';
			const referencia = `brute_force_${ip}_${Date.now()}`;
			const agora = Date.now();

			const eventoId = await ctx.db.insert('securityEvents', {
				referencia,
				timestamp: agora,
				tipoAtaque: 'brute_force',
				severidade,
				status: statusInicial(severidade),
				descricao: `Ataque de brute force detectado: ${count} tentativas de login falhas do IP ${ip} em ${janelaMinutos} minutos`,
				origemIp: ip,
				protocolo: 'http',
				transporte: 'tcp',
				detectadoPor: 'detector_brute_force',
				metricas: {
					rpm: Math.round((count / janelaMinutos) * 60)
				},
				tags: ['detecção_automática', 'brute_force', 'login'],
				atualizadoEm: agora
			});

			eventosIds.push(eventoId);

			// Ajustar reputação do IP
			const delta = count * -5; // Penalidade baseada no número de tentativas
			await ajustarReputacao(
				ctx,
				ip,
				'ip',
				delta,
				severidade,
				severidade === 'alto' ? { 
					blacklist: true,
					bloqueadoAte: agora + (60 * 60 * 1000) // Bloquear por 1 hora
				} : undefined
			);
		}

		return {
			ataqueDetectado: true,
			tentativasFalhas: tentativasFalhas.length,
			eventoId: eventosIds[0] // Retornar o primeiro evento criado
		};
	}
});

/**
 * Monitora logs de login e detecta brute force automaticamente
 * Esta função deve ser chamada periodicamente (ex: a cada 5 minutos)
 */
/**
 * Função de teste para criar eventos de segurança de exemplo
 * Útil para validar se o dashboard está funcionando corretamente
 */
export const criarEventosTeste = mutation({
	args: {
		quantidade: v.optional(v.number())
	},
	returns: v.object({
		eventosCriados: v.number(),
		eventosIds: v.array(v.id('securityEvents'))
	}),
	handler: async (ctx, args) => {
		const quantidade = args.quantidade ?? 10;
		const eventosIds: Id<'securityEvents'>[] = [];
		const agora = Date.now();

		// Tipos de ataque para teste
		const tiposAtaque: Array<{ tipo: AtaqueCiberneticoTipo; severidade: SeveridadeSeguranca }> = [
			{ tipo: 'sql_injection', severidade: 'alto' },
			{ tipo: 'xss', severidade: 'moderado' },
			{ tipo: 'brute_force', severidade: 'alto' },
			{ tipo: 'path_traversal', severidade: 'alto' },
			{ tipo: 'command_injection', severidade: 'critico' },
			{ tipo: 'nosql_injection', severidade: 'alto' },
			{ tipo: 'xxe', severidade: 'alto' },
			{ tipo: 'ddos', severidade: 'critico' },
			{ tipo: 'phishing', severidade: 'moderado' },
			{ tipo: 'malware', severidade: 'alto' }
		];

		// IPs de teste
		const ipsTeste = [
			'192.168.1.100',
			'10.0.0.50',
			'172.16.0.25',
			'203.0.113.42',
			'198.51.100.15'
		];

		for (let i = 0; i < quantidade; i++) {
			const tipoAtaque = tiposAtaque[i % tiposAtaque.length];
			const ip = ipsTeste[i % ipsTeste.length];
			const referencia = `teste_${Date.now()}_${i}_${Math.random().toString(36).substring(7)}`;

			const eventoId = await ctx.db.insert('securityEvents', {
				referencia,
				timestamp: agora - (i * 60000), // Espaçar eventos em 1 minuto
				tipoAtaque: tipoAtaque.tipo,
				severidade: tipoAtaque.severidade,
				status: statusInicial(tipoAtaque.severidade),
				descricao: `[TESTE] Evento de teste: ${tipoAtaque.tipo} detectado do IP ${ip}. Este é um evento gerado para validação do sistema.`,
				origemIp: ip,
				destinoIp: '192.168.1.1',
				destinoPorta: 443,
				protocolo: 'http',
				transporte: 'tcp',
				detectadoPor: 'sistema_teste',
				metricas: {
					rpm: Math.floor(Math.random() * 1000),
					pps: Math.floor(Math.random() * 50000)
				},
				tags: ['teste', 'validação', tipoAtaque.tipo],
				atualizadoEm: agora - (i * 60000)
			});

			eventosIds.push(eventoId);

			// Ajustar reputação do IP
			const delta = SEVERIDADE_SCORE[tipoAtaque.severidade] * -10;
			await ajustarReputacao(
				ctx,
				ip,
				'ip',
				delta,
				tipoAtaque.severidade,
				tipoAtaque.severidade === 'critico' || tipoAtaque.severidade === 'alto' ? {
					blacklist: true
				} : undefined
			);
		}

		return {
			eventosCriados: eventosIds.length,
			eventosIds
		};
	}
});

export const monitorarLogsLogin = internalMutation({
	args: {},
	returns: v.object({
		ataquesDetectados: v.number(),
		ipsBloqueados: v.number()
	}),
	handler: async (ctx) => {
		// Duplicar lógica de detecção aqui para evitar chamada circular
		// Sensibilidade maior em dev
		const janelaMinutos = 10;
		const dataLimite = Date.now() - janelaMinutos * 60 * 1000;

		// Buscar todas as tentativas falhas na janela
		const tentativasFalhas = await ctx.db
			.query('logsLogin')
			.withIndex('by_sucesso', (q) => q.eq('sucesso', false))
			.filter((q) => q.gte(q.field('timestamp'), dataLimite))
			.collect();

		// Agrupar por IP para detectar padrões
		const tentativasPorIP: Record<string, number> = {};
		tentativasFalhas.forEach((t) => {
			if (t.ipAddress) {
				tentativasPorIP[t.ipAddress] = (tentativasPorIP[t.ipAddress] || 0) + 1;
			}
		});

		// Detectar IPs suspeitos (3+ tentativas falhas)
		const ipsSuspeitos = Object.entries(tentativasPorIP)
			.filter(([, count]) => count >= 3)
			.map(([ip, count]) => ({ ip, count }));

		if (ipsSuspeitos.length === 0) {
			return {
				ataquesDetectados: 0,
				ipsBloqueados: 0
			};
		}

		// Registrar eventos para cada IP suspeito
		let ipsBloqueados = 0;
		for (const { ip, count } of ipsSuspeitos) {
			const severidade: SeveridadeSeguranca = count >= 8 ? 'alto' : count >= 5 ? 'moderado' : 'baixo';
			const referencia = `brute_force_${ip}_${Date.now()}`;
			const agora = Date.now();

			await ctx.db.insert('securityEvents', {
				referencia,
				timestamp: agora,
				tipoAtaque: 'brute_force',
				severidade,
				status: statusInicial(severidade),
				descricao: `Ataque de brute force detectado: ${count} tentativas de login falhas do IP ${ip} em ${janelaMinutos} minutos`,
				origemIp: ip,
				protocolo: 'http',
				transporte: 'tcp',
				detectadoPor: 'monitor_logs_login',
				metricas: {
					rpm: Math.round((count / janelaMinutos) * 60)
				},
				tags: ['detecção_automática', 'brute_force', 'login'],
				atualizadoEm: agora
			});

			// Ajustar reputação do IP
			const delta = count * -5;
			await ajustarReputacao(
				ctx,
				ip,
				'ip',
				delta,
				severidade,
				severidade === 'alto' ? { 
					blacklist: true,
					bloqueadoAte: agora + (60 * 60 * 1000)
				} : undefined
			);

			if (severidade === 'alto') {
				ipsBloqueados++;
			}
		}

		return {
			ataquesDetectados: ipsSuspeitos.length,
			ipsBloqueados
		};
	}
});

export const deletarConfigRateLimit = mutation({
	args: {
		configId: v.id('rateLimitConfig'),
		usuarioId: v.id('usuarios')
	},
	returns: v.null(),
	handler: async (ctx, args) => {
		const config = await ctx.db.get(args.configId);
		if (!config) {
			throw new Error('Configuração de rate limit não encontrada');
		}

		await ctx.db.delete(args.configId);
		return null;
	}
});

// Semeia configurações de rate limit para ambiente de desenvolvimento
export const seedRateLimitDev = mutation({
	args: {},
	returns: v.object({
		criadosOuAtualizados: v.number()
	}),
	handler: async (ctx) => {
		let count = 0;
		// Obter um usuário existente para campos de auditoria
		const algumUsuario = await ctx.db.query('usuarios').order('asc').take(1);
		if (algumUsuario.length === 0) {
			throw new Error('Seed de rate limit: nenhum usuário encontrado para auditoria (criadoPor).');
		}
		const usuarioId = algumUsuario[0]._id;
		// Utilitário para upsert por (tipo, identificador)
		async function upsertConfig(params: {
			nome: string;
			tipo: 'ip' | 'usuario' | 'endpoint' | 'global';
			identificador?: string;
			limite: number;
			janelaSegundos: number;
			estrategia: 'fixed_window' | 'token_bucket';
			acaoExcedido: 'bloquear' | 'throttle' | 'alertar';
			prioridade?: number;
			notas?: string;
		}) {
			const existing = await ctx.db
				.query('rateLimitConfig')
				.withIndex('by_tipo_identificador', (q) =>
					q.eq('tipo', params.tipo).eq('identificador', params.identificador ?? (params.tipo === 'global' ? 'global' : undefined)),
				)
				.collect();
			const agora = Date.now();
			if (existing.length > 0) {
				const doc = existing[0];
				await ctx.db.patch(doc._id, {
					nome: params.nome,
					limite: params.limite,
					janelaSegundos: params.janelaSegundos,
					estrategia: params.estrategia,
					acaoExcedido: params.acaoExcedido,
					ativo: true,
					prioridade: params.prioridade ?? (doc.prioridade ?? 0),
					atualizadoEm: agora,
					notas: params.notas,
				});
			} else {
				await ctx.db.insert('rateLimitConfig', {
					nome: params.nome,
					tipo: params.tipo,
					identificador: params.identificador ?? (params.tipo === 'global' ? 'global' : undefined),
					limite: params.limite,
					janelaSegundos: params.janelaSegundos,
					estrategia: params.estrategia,
					acaoExcedido: params.acaoExcedido,
					ativo: true,
					prioridade: params.prioridade ?? 0,
					criadoPor: usuarioId,
					atualizadoPor: usuarioId,
					criadoEm: agora,
					atualizadoEm: agora,
					notas: params.notas,
					tags: ['dev', 'seed']
				});
			}
			count++;
		}

		// Endpoint de login: limite baixo para evidenciar bloqueios
		await upsertConfig({
			nome: 'Bloqueio Login Dev',
			tipo: 'endpoint',
			identificador: 'api/auth/sign-in/email',
			limite: 5,
			janelaSegundos: 20,
			estrategia: 'token_bucket',
			acaoExcedido: 'bloquear',
			prioridade: 2,
			notas: 'Dev: evidenciar bloqueio no login'
		});

		// Global: limitar rajadas gerais
		await upsertConfig({
			nome: 'Global Dev',
			tipo: 'global',
			limite: 120,
			janelaSegundos: 60,
			estrategia: 'fixed_window',
			acaoExcedido: 'bloquear',
			prioridade: 1,
			notas: 'Dev: limitação global'
		});

		// Analisador: manter alta capacidade para não bloquear testes
		await upsertConfig({
			nome: 'Analyzer Alto Throughput',
			tipo: 'endpoint',
			identificador: 'http/security/analyze',
			limite: 1000,
			janelaSegundos: 10,
			estrategia: 'token_bucket',
			acaoExcedido: 'throttle',
			prioridade: 3,
			notas: 'Dev: não bloquear analisador'
		});

		return { criadosOuAtualizados: count };
	}
});

// Remover eventos de teste (tag 'teste')
export const limparEventosTeste = mutation({
	args: {},
	returns: v.object({ removidos: v.number() }),
	handler: async (ctx) => {
		const docs = await ctx.db
			.query('securityEvents')
			.withIndex('by_timestamp', (q) => q.gte('timestamp', 0))
			.order('desc')
			.take(1000);
		let removidos = 0;
		for (const doc of docs) {
			if (doc.tags && doc.tags.includes('teste')) {
				await ctx.db.delete(doc._id);
				removidos++;
			}
		}
		return { removidos };
	}
});

// Deletar regra de porta
export const deletarRegraPorta = mutation({
	args: {
		regraId: v.id('portRules'),
		usuarioId: v.id('usuarios')
	},
	returns: v.null(),
	handler: async (ctx, args) => {
		const regra = await ctx.db.get(args.regraId);
		if (!regra) {
			throw new Error('Regra de porta não encontrada');
		}
		await ctx.db.delete(args.regraId);
		return null;
	}
});

