import { v } from 'convex/values';
import { mutation, query } from './_generated/server';
import { getCurrentUserFunction } from './auth';
import { Id, Doc } from './_generated/dataModel';
import type { QueryCtx, MutationCtx } from './_generated/server';
import { registrarAtividade } from './logsAtividades';
import { api } from './_generated/api';

/**
 * Verificar se usuário aceitou o termo de consentimento
 */
export const verificarConsentimento = query({
	args: {
		tipo: v.optional(
			v.union(
				v.literal('termo_uso'),
				v.literal('politica_privacidade'),
				v.literal('comunicacoes'),
				v.literal('compartilhamento_dados')
			)
		)
	},
	returns: v.union(
		v.object({
			aceito: v.boolean(),
			versao: v.string(),
			aceitoEm: v.number(),
			termoObrigatorio: v.boolean(),
			versaoTermoAtual: v.string()
		}),
		v.null()
	),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			return null;
		}

		const tipo = args.tipo || 'termo_uso';

		// Buscar configuração para verificar se termo é obrigatório
		const config = await ctx.db
			.query('configuracaoLGPD')
			.withIndex('by_ativo', (q) => q.eq('ativo', true))
			.first();

		const termoObrigatorio = config?.termoObrigatorio ?? false;
		const versaoTermoAtual = config?.versaoTermoAtual ?? '1.0';

		const consentimento = await ctx.db
			.query('consentimentos')
			.withIndex('by_usuario_tipo', (q) => q.eq('usuarioId', usuario._id).eq('tipo', tipo))
			.order('desc')
			.first();

		if (!consentimento || !consentimento.aceito || consentimento.revogadoEm) {
			return {
				aceito: false,
				versao: '',
				aceitoEm: 0,
				termoObrigatorio,
				versaoTermoAtual
			};
		}

		return {
			aceito: consentimento.aceito,
			versao: consentimento.versao,
			aceitoEm: consentimento.aceitoEm,
			termoObrigatorio,
			versaoTermoAtual
		};
	}
});

/**
 * Registrar consentimento do usuário
 */
export const registrarConsentimento = mutation({
	args: {
		tipo: v.union(
			v.literal('termo_uso'),
			v.literal('politica_privacidade'),
			v.literal('comunicacoes'),
			v.literal('compartilhamento_dados')
		),
		aceito: v.boolean(),
		versao: v.string(),
		ipAddress: v.optional(v.string()),
		userAgent: v.optional(v.string())
	},
	returns: v.object({ sucesso: v.boolean(), consentimentoId: v.id('consentimentos') }),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		// Verificar se já existe consentimento ativo
		const existente = await ctx.db
			.query('consentimentos')
			.withIndex('by_usuario_tipo', (q) => q.eq('usuarioId', usuario._id).eq('tipo', args.tipo))
			.order('desc')
			.first();

		if (existente && existente.aceito && !existente.revogadoEm) {
			// Atualizar consentimento existente
			await ctx.db.patch(existente._id, {
				aceito: args.aceito,
				versao: args.versao,
				aceitoEm: Date.now(),
				ipAddress: args.ipAddress,
				userAgent: args.userAgent,
				revogadoEm: undefined,
				revogadoPor: undefined
			});

			return { sucesso: true, consentimentoId: existente._id };
		}

		// Criar novo consentimento
		const consentimentoId = await ctx.db.insert('consentimentos', {
			usuarioId: usuario._id,
			tipo: args.tipo,
			aceito: args.aceito,
			versao: args.versao,
			ipAddress: args.ipAddress,
			userAgent: args.userAgent,
			aceitoEm: Date.now()
		});

		// Log de atividade
		await registrarAtividade(
			ctx,
			usuario._id,
			'aceitar_consentimento',
			'consentimentos',
			JSON.stringify({ tipo: args.tipo, versao: args.versao }),
			consentimentoId.toString()
		);

		return { sucesso: true, consentimentoId };
	}
});

/**
 * Revogar consentimento
 */
export const revogarConsentimento = mutation({
	args: {
		tipo: v.union(
			v.literal('termo_uso'),
			v.literal('politica_privacidade'),
			v.literal('comunicacoes'),
			v.literal('compartilhamento_dados')
		)
	},
	returns: v.object({ sucesso: v.boolean() }),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		const consentimento = await ctx.db
			.query('consentimentos')
			.withIndex('by_usuario_tipo', (q) => q.eq('usuarioId', usuario._id).eq('tipo', args.tipo))
			.order('desc')
			.first();

		if (!consentimento) {
			throw new Error('Consentimento não encontrado');
		}

		await ctx.db.patch(consentimento._id, {
			revogadoEm: Date.now(),
			revogadoPor: usuario._id
		});

		// Log de atividade
		await registrarAtividade(
			ctx,
			usuario._id,
			'revogar_consentimento',
			'consentimentos',
			JSON.stringify({ tipo: args.tipo }),
			consentimento._id.toString()
		);

		return { sucesso: true };
	}
});

/**
 * Listar consentimentos do usuário
 */
export const listarConsentimentos = query({
	args: {},
	returns: v.array(
		v.object({
			_id: v.id('consentimentos'),
			tipo: v.string(),
			aceito: v.boolean(),
			versao: v.string(),
			aceitoEm: v.number(),
			revogadoEm: v.union(v.number(), v.null())
		})
	),
	handler: async (ctx) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			return [];
		}

		const consentimentos = await ctx.db
			.query('consentimentos')
			.withIndex('by_usuario', (q) => q.eq('usuarioId', usuario._id))
			.order('desc')
			.collect();

		return consentimentos.map((c) => ({
			_id: c._id,
			tipo: c.tipo,
			aceito: c.aceito,
			versao: c.versao,
			aceitoEm: c.aceitoEm,
			revogadoEm: c.revogadoEm ?? null
		}));
	}
});

/**
 * Criar solicitação de direito LGPD
 */
export const criarSolicitacao = mutation({
	args: {
		tipo: v.union(
			v.literal('acesso'),
			v.literal('correcao'),
			v.literal('exclusao'),
			v.literal('portabilidade'),
			v.literal('revogacao_consentimento'),
			v.literal('informacao_compartilhamento')
		),
		dadosSolicitados: v.optional(v.string()),
		observacoes: v.optional(v.string())
	},
	returns: v.object({ sucesso: v.boolean(), solicitacaoId: v.id('solicitacoesLGPD') }),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		// Prazo de resposta: 15 dias (conforme LGPD)
		const prazoResposta = Date.now() + 15 * 24 * 60 * 60 * 1000;

		const solicitacaoId = await ctx.db.insert('solicitacoesLGPD', {
			tipo: args.tipo,
			usuarioId: usuario._id,
			funcionarioId: usuario.funcionarioId,
			status: 'pendente',
			dadosSolicitados: args.dadosSolicitados,
			observacoes: args.observacoes,
			criadoEm: Date.now(),
			prazoResposta
		});

		// Log de atividade
		await registrarAtividade(
			ctx,
			usuario._id,
			'criar_solicitacao_lgpd',
			'solicitacoesLGPD',
			JSON.stringify({ tipo: args.tipo }),
			solicitacaoId.toString()
		);

		// Notificações (email + opcional chat) para o titular
		if (usuario.email) {
			let urlSistema = process.env.FRONTEND_URL || 'http://localhost:5173';
			if (!urlSistema.match(/^https?:\/\//i)) {
				urlSistema = `http://${urlSistema}`;
			}

			const tipoSolicitacaoLabelMap: Record<string, string> = {
				acesso: 'Acesso aos Dados',
				correcao: 'Correção de Dados',
				exclusao: 'Exclusão de Dados',
				portabilidade: 'Portabilidade dos Dados',
				revogacao_consentimento: 'Revogação de Consentimento',
				informacao_compartilhamento: 'Informação sobre Compartilhamento'
			};

			const tipoSolicitacaoLabel = tipoSolicitacaoLabelMap[args.tipo] ?? args.tipo;

			// Email usando template LGPD
			try {
				await ctx.scheduler.runAfter(0, api.email.enviarEmailComTemplate, {
					destinatario: usuario.email,
					destinatarioId: usuario._id,
					templateCodigo: 'lgpd_solicitacao_criada',
					variaveis: {
						nomeTitular: usuario.nome,
						tipoSolicitacaoLabel,
						prazoResposta: new Date(prazoResposta).toLocaleDateString('pt-BR'),
						urlPortalLGPD: `${urlSistema}/privacidade/meus-dados`
					},
					enviadoPor: usuario._id
				});
			} catch (error) {
				console.error('Erro ao agendar email lgpd_solicitacao_criada:', error);
			}
		}

		return { sucesso: true, solicitacaoId };
	}
});

/**
 * Listar solicitações do usuário
 */
export const listarMinhasSolicitacoes = query({
	args: {
		status: v.optional(
			v.union(
				v.literal('pendente'),
				v.literal('em_analise'),
				v.literal('concluida'),
				v.literal('rejeitada'),
				v.literal('cancelada')
			)
		),
		_refresh: v.optional(v.number()) // Parâmetro para forçar atualização no frontend
	},
	returns: v.array(
		v.object({
			_id: v.id('solicitacoesLGPD'),
			tipo: v.string(),
			status: v.string(),
			criadoEm: v.number(),
			prazoResposta: v.number(),
			respondidoEm: v.union(v.number(), v.null()),
			resposta: v.union(v.string(), v.null()),
			arquivoResposta: v.union(v.string(), v.null())
		})
	),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			return [];
		}

		try {
			let solicitacoes = await ctx.db
				.query('solicitacoesLGPD')
				.withIndex('by_usuario', (q) => q.eq('usuarioId', usuario._id))
				.collect();

			// Filtrar por status se especificado
			if (args.status) {
				solicitacoes = solicitacoes.filter((s) => s.status === args.status);
			}

			// Ordenar por data de criação (mais recentes primeiro)
			solicitacoes.sort((a, b) => b.criadoEm - a.criadoEm);

			const resultado = solicitacoes.map((s) => ({
				_id: s._id,
				tipo: s.tipo,
				status: s.status,
				criadoEm: s.criadoEm,
				prazoResposta: s.prazoResposta,
				respondidoEm: s.respondidoEm ?? null,
				resposta: s.resposta ?? null,
				arquivoResposta: s.arquivoResposta ? s.arquivoResposta.toString() : null
			}));

			console.log(
				`[listarMinhasSolicitacoes] Usuário: ${usuario._id}, Solicitações encontradas: ${resultado.length}`
			);
			return resultado;
		} catch (error) {
			console.error('[listarMinhasSolicitacoes] Erro ao listar minhas solicitações:', error);
			return [];
		}
	}
});

/**
 * Listar todas as solicitações (apenas TI)
 */
export const listarSolicitacoes = query({
	args: {
		status: v.optional(
			v.union(
				v.literal('pendente'),
				v.literal('em_analise'),
				v.literal('concluida'),
				v.literal('rejeitada'),
				v.literal('cancelada')
			)
		),
		tipo: v.optional(
			v.union(
				v.literal('acesso'),
				v.literal('correcao'),
				v.literal('exclusao'),
				v.literal('portabilidade'),
				v.literal('revogacao_consentimento'),
				v.literal('informacao_compartilhamento')
			)
		),
		limite: v.optional(v.number())
	},
		returns: v.array(
			v.object({
				_id: v.id('solicitacoesLGPD'),
				tipo: v.string(),
				status: v.string(),
				usuarioNome: v.string(),
				usuarioEmail: v.string(),
				usuarioMatricula: v.union(v.string(), v.null()),
				dadosSolicitados: v.union(v.string(), v.null()),
				observacoes: v.union(v.string(), v.null()),
				resposta: v.union(v.string(), v.null()),
				arquivoResposta: v.union(v.string(), v.null()),
				criadoEm: v.number(),
				prazoResposta: v.number(),
				respondidoEm: v.union(v.number(), v.null()),
				respondidoPorNome: v.union(v.string(), v.null()),
				consentimentoTermo: v.union(
					v.object({
						aceito: v.boolean(),
						versao: v.string(),
						aceitoEm: v.number(),
						revogadoEm: v.union(v.number(), v.null())
					}),
					v.null()
				)
			})
		),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			return [];
		}

		// Verificar se é TI (simplificado - pode melhorar com verificação de role)
		// Por enquanto, qualquer usuário autenticado pode ver (será melhorado)

		// Buscar TODAS as solicitações sem filtros iniciais
		let solicitacoes = await ctx.db.query('solicitacoesLGPD').collect();

		// Filtrar por status
		if (args.status) {
			solicitacoes = solicitacoes.filter((s) => s.status === args.status);
		}

		// Filtrar por tipo
		if (args.tipo) {
			solicitacoes = solicitacoes.filter((s) => s.tipo === args.tipo);
		}

		// Ordenar por data de criação (mais recentes primeiro)
		solicitacoes.sort((a, b) => b.criadoEm - a.criadoEm);

		// Aplicar limite se especificado
		if (args.limite) {
			solicitacoes = solicitacoes.slice(0, args.limite);
		}

		// Tipo do resultado enriquecido
		type SolicitacaoEnriquecida = {
			_id: Id<'solicitacoesLGPD'>;
			tipo: string;
			status: string;
			usuarioNome: string;
			usuarioEmail: string;
			usuarioMatricula: string | null;
			dadosSolicitados: string | null;
			observacoes: string | null;
			resposta: string | null;
			arquivoResposta: string | null;
			criadoEm: number;
			prazoResposta: number;
			respondidoEm: number | null;
			respondidoPorNome: string | null;
			consentimentoTermo: {
				aceito: boolean;
				versao: string;
				aceitoEm: number;
				revogadoEm: number | null;
			} | null;
		};

		// Enriquecer com dados do usuário
		// Usar Promise.allSettled para garantir que todas as solicitações sejam processadas,
		// mesmo se houver erro ao buscar dados de algum usuário
		const resultados = await Promise.allSettled(
			solicitacoes.map(async (s): Promise<SolicitacaoEnriquecida> => {
				try {
					const usuarioSolicitante = await ctx.db.get(s.usuarioId);
					let matricula: string | null = null;

					if (usuarioSolicitante?.funcionarioId) {
						const funcionario = await ctx.db.get(usuarioSolicitante.funcionarioId);
						matricula = funcionario?.matricula ?? null;
					}

					let respondidoPorNome: string | null = null;
					if (s.respondidoPor) {
						const respondente = await ctx.db.get(s.respondidoPor);
						respondidoPorNome = respondente?.nome ?? null;
					}

					// Buscar consentimento do termo de uso
					let consentimentoTermo: {
						aceito: boolean;
						versao: string;
						aceitoEm: number;
						revogadoEm: number | null;
					} | null = null;

					if (usuarioSolicitante) {
						try {
							const consentimento = await ctx.db
								.query('consentimentos')
								.withIndex('by_usuario_tipo', (q) =>
									q.eq('usuarioId', usuarioSolicitante._id).eq('tipo', 'termo_uso')
								)
								.order('desc')
								.first();

							if (consentimento && consentimento.aceito && !consentimento.revogadoEm) {
								consentimentoTermo = {
									aceito: consentimento.aceito,
									versao: consentimento.versao,
									aceitoEm: consentimento.aceitoEm,
									revogadoEm: consentimento.revogadoEm ?? null
								};
							}
						} catch (error) {
							// Se houver erro ao buscar consentimento, continua sem ele
							console.error('Erro ao buscar consentimento:', error);
						}
					}

					// Buscar URL do arquivo de resposta se existir
					let arquivoRespostaUrl: string | null = null;
					if (s.arquivoResposta) {
						arquivoRespostaUrl = await ctx.storage.getUrl(s.arquivoResposta);
					}

					return {
						_id: s._id,
						tipo: s.tipo,
						status: s.status,
						usuarioNome: usuarioSolicitante?.nome ?? 'Usuário Desconhecido',
						usuarioEmail: usuarioSolicitante?.email ?? '',
						usuarioMatricula: matricula,
						dadosSolicitados: s.dadosSolicitados ?? null,
						observacoes: s.observacoes ?? null,
						resposta: s.resposta ?? null,
						arquivoResposta: arquivoRespostaUrl,
						criadoEm: s.criadoEm,
						prazoResposta: s.prazoResposta,
						respondidoEm: s.respondidoEm ?? null,
						respondidoPorNome,
						consentimentoTermo
					};
				} catch (error) {
					// Se houver erro ao processar uma solicitação, retorna com dados mínimos
					console.error('Erro ao processar solicitação:', s._id, error);
					return {
						_id: s._id,
						tipo: s.tipo,
						status: s.status,
						usuarioNome: 'Erro ao carregar',
						usuarioEmail: '',
						usuarioMatricula: null,
						dadosSolicitados: s.dadosSolicitados ?? null,
						observacoes: s.observacoes ?? null,
						resposta: s.resposta ?? null,
						arquivoResposta: null,
						criadoEm: s.criadoEm,
						prazoResposta: s.prazoResposta,
						respondidoEm: s.respondidoEm ?? null,
						respondidoPorNome: null,
						consentimentoTermo: null
					};
				}
			})
		);

		// Filtrar apenas resultados bem-sucedidos e converter para o tipo correto
		const resultado = resultados
			.filter((r): r is PromiseFulfilledResult<SolicitacaoEnriquecida> => r.status === 'fulfilled')
			.map((r) => r.value);

		return resultado;
	}
});

/**
 * Responder solicitação (apenas TI)
 */
export const responderSolicitacao = mutation({
	args: {
		solicitacaoId: v.id('solicitacoesLGPD'),
		resposta: v.string(),
		status: v.union(v.literal('concluida'), v.literal('rejeitada'), v.literal('em_analise')),
		arquivoResposta: v.optional(v.id('_storage'))
	},
	returns: v.object({ sucesso: v.boolean() }),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		const solicitacao = await ctx.db.get(args.solicitacaoId);
		if (!solicitacao) {
			throw new Error('Solicitação não encontrada');
		}

		// Atualizar resposta da solicitação
		await ctx.db.patch(args.solicitacaoId, {
			status: args.status,
			resposta: args.resposta,
			arquivoResposta: args.arquivoResposta,
			respondidoPor: usuario._id,
			respondidoEm: Date.now()
		});

		// Se for uma solicitação de "Revogar Consentimento" concluída,
		// revogar todos os consentimentos ativos do titular que fez a solicitação.
		if (solicitacao.tipo === 'revogacao_consentimento' && args.status === 'concluida') {
			// Garantir que temos o titular associado
			if (!solicitacao.usuarioId) {
				throw new Error(
					'Solicitação de revogação de consentimento sem usuário associado. Verifique os dados.'
				);
			}

			// Buscar consentimentos ativos do usuário
			const consentimentosAtivos = await ctx.db
				.query('consentimentos')
				.withIndex('by_usuario', (q) => q.eq('usuarioId', solicitacao.usuarioId))
				.filter((q) => q.eq(q.field('aceito'), true))
				.collect();

			for (const consentimento of consentimentosAtivos) {
				// Pular consentimentos já revogados por segurança
				if (consentimento.revogadoEm) continue;

				await ctx.db.patch(consentimento._id, {
					revogadoEm: Date.now(),
					revogadoPor: usuario._id
				});

				// Registrar atividade individual por consentimento revogado
				await registrarAtividade(
					ctx,
					usuario._id,
					'revogar_consentimento_por_solicitacao',
					'consentimentos',
					JSON.stringify({
						tipo: consentimento.tipo,
						origem: 'solicitacao_lgpd',
						solicitacaoId: args.solicitacaoId
					}),
					consentimento._id.toString()
				);
			}
		}

		// Log de atividade
		await registrarAtividade(
			ctx,
			usuario._id,
			'responder_solicitacao_lgpd',
			'solicitacoesLGPD',
			JSON.stringify({ solicitacaoId: args.solicitacaoId, status: args.status }),
			args.solicitacaoId.toString()
		);

		// Notificações para o titular (email + chat)
		const usuarioTitular = await ctx.db.get(solicitacao.usuarioId);
		if (usuarioTitular) {
			let urlSistema = process.env.FRONTEND_URL || 'http://localhost:5173';
			if (!urlSistema.match(/^https?:\/\//i)) {
				urlSistema = `http://${urlSistema}`;
			}

			const tipoSolicitacaoLabelMap: Record<string, string> = {
				acesso: 'Acesso aos Dados',
				correcao: 'Correção de Dados',
				exclusao: 'Exclusão de Dados',
				portabilidade: 'Portabilidade dos Dados',
				revogacao_consentimento: 'Revogação de Consentimento',
				informacao_compartilhamento: 'Informação sobre Compartilhamento'
			};

			const statusLabelMap: Record<string, string> = {
				concluida: 'Concluída',
				rejeitada: 'Rejeitada',
				em_analise: 'Em Análise'
			};

			const tipoSolicitacaoLabel = tipoSolicitacaoLabelMap[solicitacao.tipo] ?? solicitacao.tipo;
			const statusLabel = statusLabelMap[args.status] ?? args.status;
			const resumoResposta = args.resposta.length > 500 ? `${args.resposta.slice(0, 500)}...` : args.resposta;

			// Escolher template conforme o tipo
			const tipoToTemplate: Record<string, string> = {
				acesso: 'lgpd_resposta_acesso',
				correcao: 'lgpd_resposta_correcao',
				exclusao: 'lgpd_resposta_exclusao',
				portabilidade: 'lgpd_resposta_portabilidade',
				revogacao_consentimento: 'lgpd_resposta_revogacao_consentimento',
				informacao_compartilhamento: 'lgpd_resposta_informacao_compartilhamento'
			};

			const templateCodigo = tipoToTemplate[solicitacao.tipo] ?? 'lgpd_resposta_acesso';

			// Email para o titular
			if (usuarioTitular.email) {
				try {
					await ctx.scheduler.runAfter(0, api.email.enviarEmailComTemplate, {
						destinatario: usuarioTitular.email,
						destinatarioId: usuarioTitular._id,
						templateCodigo,
						variaveis: {
							nomeTitular: usuarioTitular.nome,
							tipoSolicitacaoLabel,
							statusLabel,
							resumoResposta,
							urlPortalLGPD: `${urlSistema}/privacidade/meus-dados`
						},
						enviadoPor: usuario._id
					});
				} catch (error) {
					console.error(`Erro ao agendar email ${templateCodigo}:`, error);
				}
			}

			// Mensagem simples no chat entre TI (respondente) e o titular
			try {
				// Buscar conversa individual existente
				const conversas = await ctx.db
					.query('conversas')
					.filter((q) => q.eq(q.field('tipo'), 'individual'))
					.collect();

				let conversaId: Id<'conversas'> | null = null;
				for (const conversa of conversas) {
					if (
						conversa.participantes.length === 2 &&
						conversa.participantes.includes(usuario._id) &&
						conversa.participantes.includes(usuarioTitular._id)
					) {
						conversaId = conversa._id;
						break;
					}
				}

				if (!conversaId) {
					conversaId = await ctx.db.insert('conversas', {
						tipo: 'individual',
						participantes: [usuario._id, usuarioTitular._id],
						criadoPor: usuario._id,
						criadoEm: Date.now()
					});
				}

				await ctx.db.insert('mensagens', {
					conversaId,
					remetenteId: usuario._id,
					tipo: 'texto',
					conteudo: `Respondi sua solicitação LGPD (${tipoSolicitacaoLabel}) com status ${statusLabel}. Resumo: ${resumoResposta}`,
					enviadaEm: Date.now()
				});
			} catch (error) {
				console.error('Erro ao criar mensagem de chat para resposta LGPD:', error);
			}
		}

		return { sucesso: true };
	}
});

/**
 * Cancelar solicitação LGPD (apenas pelo próprio usuário)
 */
export const cancelarSolicitacao = mutation({
	args: {
		solicitacaoId: v.id('solicitacoesLGPD')
	},
	returns: v.object({ sucesso: v.boolean() }),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		const solicitacao = await ctx.db.get(args.solicitacaoId);
		if (!solicitacao) {
			throw new Error('Solicitação não encontrada');
		}

		// Verificar se a solicitação pertence ao usuário
		if (solicitacao.usuarioId !== usuario._id) {
			throw new Error('Você não tem permissão para cancelar esta solicitação');
		}

		// Só pode cancelar se estiver pendente ou em análise
		if (solicitacao.status !== 'pendente' && solicitacao.status !== 'em_analise') {
			throw new Error('Só é possível cancelar solicitações pendentes ou em análise');
		}

		// Atualizar status para cancelada
		await ctx.db.patch(args.solicitacaoId, {
			status: 'cancelada'
		});

		// Log de atividade
		await registrarAtividade(
			ctx,
			usuario._id,
			'cancelar_solicitacao_lgpd',
			'solicitacoesLGPD',
			JSON.stringify({ solicitacaoId: args.solicitacaoId }),
			args.solicitacaoId.toString()
		);

		return { sucesso: true };
	}
});

/**
 * Excluir solicitação LGPD (apenas pelo próprio usuário e apenas se cancelada ou pendente)
 */
export const excluirSolicitacao = mutation({
	args: {
		solicitacaoId: v.id('solicitacoesLGPD')
	},
	returns: v.object({ sucesso: v.boolean() }),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		const solicitacao = await ctx.db.get(args.solicitacaoId);
		if (!solicitacao) {
			throw new Error('Solicitação não encontrada');
		}

		// Verificar se a solicitação pertence ao usuário
		if (solicitacao.usuarioId !== usuario._id) {
			throw new Error('Você não tem permissão para excluir esta solicitação');
		}

		// Só pode excluir se estiver pendente ou cancelada
		if (solicitacao.status !== 'pendente' && solicitacao.status !== 'cancelada') {
			throw new Error('Só é possível excluir solicitações pendentes ou canceladas');
		}

		// Excluir arquivo de resposta se existir
		if (solicitacao.arquivoResposta) {
			await ctx.storage.delete(solicitacao.arquivoResposta);
		}

		// Excluir a solicitação
		await ctx.db.delete(args.solicitacaoId);

		// Log de atividade
		await registrarAtividade(
			ctx,
			usuario._id,
			'excluir_solicitacao_lgpd',
			'solicitacoesLGPD',
			JSON.stringify({ solicitacaoId: args.solicitacaoId }),
			args.solicitacaoId.toString()
		);

		return { sucesso: true };
	}
});

/**
 * Exportar dados do usuário (portabilidade)
 */
export const exportarDadosUsuario = query({
	args: {},
	returns: v.object({
		dados: v.string() // JSON string com todos os dados do usuário
	}),
	handler: async (ctx) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		// Buscar todos os dados do usuário
		type DadosUsuario = {
			usuario: {
				nome: string;
				email: string;
				setor?: string;
			};
			consentimentos: Array<{
				tipo: string;
				aceito: boolean;
				versao: string;
				aceitoEm: number;
				revogadoEm?: number;
			}>;
			solicitacoes: Array<{
				tipo: string;
				status: string;
				criadoEm: number;
				respondidoEm?: number;
			}>;
			funcionario?: {
				nome: string;
				matricula?: string;
				cpf: string;
				email: string;
				telefone: string;
				descricaoCargo?: string;
			};
		};

		const dadosUsuario: DadosUsuario = {
			usuario: {
				nome: usuario.nome,
				email: usuario.email,
				setor: usuario.setor
			},
			consentimentos: [],
			solicitacoes: []
		};

		// Consentimentos
		const consentimentos = await ctx.db
			.query('consentimentos')
			.withIndex('by_usuario', (q) => q.eq('usuarioId', usuario._id))
			.collect();
		dadosUsuario.consentimentos = consentimentos.map((c) => ({
			tipo: c.tipo,
			aceito: c.aceito,
			versao: c.versao,
			aceitoEm: c.aceitoEm,
			revogadoEm: c.revogadoEm
		}));

		// Solicitações LGPD
		const solicitacoes = await ctx.db
			.query('solicitacoesLGPD')
			.withIndex('by_usuario', (q) => q.eq('usuarioId', usuario._id))
			.collect();
		dadosUsuario.solicitacoes = solicitacoes.map((s) => ({
			tipo: s.tipo,
			status: s.status,
			criadoEm: s.criadoEm,
			respondidoEm: s.respondidoEm
		}));

		// Dados do funcionário (se houver)
		if (usuario.funcionarioId) {
			const funcionario = await ctx.db.get(usuario.funcionarioId);
			if (funcionario) {
				dadosUsuario.funcionario = {
					nome: funcionario.nome,
					matricula: funcionario.matricula,
					cpf: funcionario.cpf,
					email: funcionario.email,
					telefone: funcionario.telefone,
					descricaoCargo: funcionario.descricaoCargo
				};
			}
		}

		return {
			dados: JSON.stringify(dadosUsuario, null, 2)
		};
	}
});

/**
 * Criar Registro de Operação de Tratamento (ROT)
 */
export const criarRegistroTratamento = mutation({
	args: {
		finalidade: v.string(),
		baseLegal: v.string(),
		categoriasDados: v.array(v.string()),
		categoriasTitulares: v.array(v.string()),
		medidasSeguranca: v.array(v.string()),
		prazoRetencao: v.number(),
		compartilhamentoTerceiros: v.boolean(),
		terceiros: v.optional(v.array(v.string())),
		descricao: v.optional(v.string())
	},
	returns: v.object({ sucesso: v.boolean(), registroId: v.id('registrosTratamento') }),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		const agora = Date.now();

		const registroId = await ctx.db.insert('registrosTratamento', {
			finalidade: args.finalidade,
			baseLegal: args.baseLegal,
			categoriasDados: args.categoriasDados,
			categoriasTitulares: args.categoriasTitulares,
			medidasSeguranca: args.medidasSeguranca,
			prazoRetencao: args.prazoRetencao,
			compartilhamentoTerceiros: args.compartilhamentoTerceiros,
			terceiros: args.terceiros,
			responsavel: usuario._id,
			descricao: args.descricao,
			criadoEm: agora,
			atualizadoEm: agora,
			ativo: true
		});

		// Log de atividade
		await registrarAtividade(
			ctx,
			usuario._id,
			'criar_rot',
			'registrosTratamento',
			JSON.stringify({ finalidade: args.finalidade }),
			registroId.toString()
		);

		return { sucesso: true, registroId };
	}
});

/**
 * Listar Registros de Tratamento
 */
export const listarRegistrosTratamento = query({
	args: {
		ativo: v.optional(v.boolean())
	},
	returns: v.array(
		v.object({
			_id: v.id('registrosTratamento'),
			finalidade: v.string(),
			baseLegal: v.string(),
			categoriasDados: v.array(v.string()),
			categoriasTitulares: v.array(v.string()),
			medidasSeguranca: v.array(v.string()),
			prazoRetencao: v.number(),
			compartilhamentoTerceiros: v.boolean(),
			terceiros: v.union(v.array(v.string()), v.null()),
			responsavelNome: v.string(),
			criadoEm: v.number(),
			atualizadoEm: v.number(),
			ativo: v.boolean()
		})
	),
	handler: async (ctx, args) => {
		let registros = await ctx.db.query('registrosTratamento').collect();

		if (args.ativo !== undefined) {
			registros = registros.filter((r) => r.ativo === args.ativo);
		}

		// Enriquecer com nome do responsável
		const resultado = await Promise.all(
			registros.map(async (r) => {
				const responsavel = await ctx.db.get(r.responsavel);
				return {
					_id: r._id,
					finalidade: r.finalidade,
					baseLegal: r.baseLegal,
					categoriasDados: r.categoriasDados,
					categoriasTitulares: r.categoriasTitulares,
					medidasSeguranca: r.medidasSeguranca,
					prazoRetencao: r.prazoRetencao,
					compartilhamentoTerceiros: r.compartilhamentoTerceiros,
					terceiros: r.terceiros ?? null,
					responsavelNome: responsavel?.nome ?? 'Desconhecido',
					criadoEm: r.criadoEm,
					atualizadoEm: r.atualizadoEm,
					ativo: r.ativo
				};
			})
		);

		return resultado;
	}
});

/**
 * Obter configurações LGPD
 */
export const obterConfiguracaoLGPD = query({
	args: {},
	returns: v.union(
		v.object({
			encarregadoNome: v.union(v.string(), v.null()),
			encarregadoEmail: v.union(v.string(), v.null()),
			encarregadoTelefone: v.union(v.string(), v.null()),
			encarregadoHorarioAtendimento: v.union(v.string(), v.null()),
			prazoRespostaPadrao: v.number(),
			diasAlertaVencimento: v.number(),
			termoObrigatorio: v.boolean(),
			versaoTermoAtual: v.string()
		}),
		v.null()
	),
	handler: async (ctx) => {
		const config = await ctx.db
			.query('configuracaoLGPD')
			.withIndex('by_ativo', (q) => q.eq('ativo', true))
			.first();

		if (!config) {
			// Retornar valores padrão
			return {
				encarregadoNome: null,
				encarregadoEmail: null,
				encarregadoTelefone: null,
				encarregadoHorarioAtendimento: null,
				prazoRespostaPadrao: 15,
				diasAlertaVencimento: 3,
				termoObrigatorio: false,
				versaoTermoAtual: '1.0'
			};
		}

		return {
			encarregadoNome: config.encarregadoNome ?? null,
			encarregadoEmail: config.encarregadoEmail ?? null,
			encarregadoTelefone: config.encarregadoTelefone ?? null,
			encarregadoHorarioAtendimento: config.encarregadoHorarioAtendimento ?? null,
			prazoRespostaPadrao: config.prazoRespostaPadrao,
			diasAlertaVencimento: config.diasAlertaVencimento,
			termoObrigatorio: config.termoObrigatorio,
			versaoTermoAtual: config.versaoTermoAtual
		};
	}
});

/**
 * Atualizar configurações LGPD (apenas TI)
 */
export const atualizarConfiguracaoLGPD = mutation({
	args: {
		encarregadoNome: v.optional(v.string()),
		encarregadoEmail: v.optional(v.string()),
		encarregadoTelefone: v.optional(v.string()),
		encarregadoHorarioAtendimento: v.optional(v.string()),
		prazoRespostaPadrao: v.optional(v.number()),
		diasAlertaVencimento: v.optional(v.number()),
		termoObrigatorio: v.optional(v.boolean()),
		versaoTermoAtual: v.optional(v.string())
	},
	returns: v.object({ sucesso: v.boolean() }),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		// Buscar configuração ativa ou criar nova
		let config = await ctx.db
			.query('configuracaoLGPD')
			.withIndex('by_ativo', (q) => q.eq('ativo', true))
			.first();

		if (config) {
			// Desativar configuração antiga
			await ctx.db.patch(config._id, { ativo: false });
		}

		// Buscar valores atuais para manter os que não foram atualizados
		const valoresAtuais = config || {
			encarregadoNome: undefined,
			encarregadoEmail: undefined,
			encarregadoTelefone: undefined,
			encarregadoHorarioAtendimento: undefined,
			prazoRespostaPadrao: 15,
			diasAlertaVencimento: 3,
			termoObrigatorio: false,
			versaoTermoAtual: '1.0'
		};

		// Criar nova configuração
		await ctx.db.insert('configuracaoLGPD', {
			encarregadoNome: args.encarregadoNome ?? valoresAtuais.encarregadoNome ?? undefined,
			encarregadoEmail: args.encarregadoEmail ?? valoresAtuais.encarregadoEmail ?? undefined,
			encarregadoTelefone:
				args.encarregadoTelefone ?? valoresAtuais.encarregadoTelefone ?? undefined,
			encarregadoHorarioAtendimento:
				args.encarregadoHorarioAtendimento ??
				valoresAtuais.encarregadoHorarioAtendimento ??
				undefined,
			prazoRespostaPadrao: args.prazoRespostaPadrao ?? valoresAtuais.prazoRespostaPadrao,
			diasAlertaVencimento: args.diasAlertaVencimento ?? valoresAtuais.diasAlertaVencimento,
			termoObrigatorio: args.termoObrigatorio ?? valoresAtuais.termoObrigatorio ?? false,
			versaoTermoAtual: args.versaoTermoAtual ?? valoresAtuais.versaoTermoAtual ?? '1.0',
			ativo: true,
			atualizadoPor: usuario._id,
			atualizadoEm: Date.now()
		});

		// Log de atividade
		await registrarAtividade(
			ctx,
			usuario._id,
			'atualizar_config_lgpd',
			'configuracaoLGPD',
			JSON.stringify(args),
			''
		);

		return { sucesso: true };
	}
});

/**
 * Obter estatísticas LGPD (apenas TI)
 */
export const obterEstatisticasLGPD = query({
	args: {},
	returns: v.object({
		totalSolicitacoes: v.number(),
		solicitacoesPendentes: v.number(),
		solicitacoesVencendo: v.number(),
		solicitacoesPorTipo: v.record(v.string(), v.number()),
		totalConsentimentos: v.number(),
		consentimentosAtivos: v.number(),
		totalROTs: v.number(),
		rotsAtivos: v.number()
	}),
	handler: async (ctx) => {
		const solicitacoes = await ctx.db.query('solicitacoesLGPD').collect();
		const consentimentos = await ctx.db.query('consentimentos').collect();
		const rots = await ctx.db.query('registrosTratamento').collect();

		const agora = Date.now();
		const tresDias = 3 * 24 * 60 * 60 * 1000;

		const solicitacoesVencendo = solicitacoes.filter((s) =>
			s.status === 'pendente' || s.status === 'em_analise'
				? s.prazoResposta - agora <= tresDias && s.prazoResposta > agora
				: false
		).length;

		const solicitacoesPorTipo: Record<string, number> = {};
		solicitacoes.forEach((s) => {
			solicitacoesPorTipo[s.tipo] = (solicitacoesPorTipo[s.tipo] || 0) + 1;
		});

		const consentimentosAtivos = consentimentos.filter((c) => c.aceito && !c.revogadoEm).length;

		return {
			totalSolicitacoes: solicitacoes.length,
			solicitacoesPendentes: solicitacoes.filter((s) => s.status === 'pendente').length,
			solicitacoesVencendo,
			solicitacoesPorTipo,
			totalConsentimentos: consentimentos.length,
			consentimentosAtivos,
			totalROTs: rots.length,
			rotsAtivos: rots.filter((r) => r.ativo).length
		};
	}
});
