import { query, mutation, internalQuery } from './_generated/server';
import { v } from 'convex/values';
import type { Doc } from './_generated/dataModel';
import { getCurrentUserFunction } from './auth';

// Catálogo de permissões base para seed controlado via mutation
const PERMISSOES_BASE = {
	permissoes: [
		// Funcionários
		{
			nome: 'funcionarios.dashboard',
			recurso: 'funcionarios',
			acao: 'dashboard',
			descricao: 'Acessar o painel de funcionários'
		},
		{
			nome: 'funcionarios.ver',
			recurso: 'funcionarios',
			acao: 'ver',
			descricao: 'Visualizar detalhes de funcionários'
		},
		{
			nome: 'funcionarios.listar',
			recurso: 'funcionarios',
			acao: 'listar',
			descricao: 'Listar funcionários'
		},
		{
			nome: 'funcionarios.criar',
			recurso: 'funcionarios',
			acao: 'criar',
			descricao: 'Criar novos funcionários'
		},
		{
			nome: 'funcionarios.editar',
			recurso: 'funcionarios',
			acao: 'editar',
			descricao: 'Editar dados de funcionários'
		},
		{
			nome: 'funcionarios.excluir',
			recurso: 'funcionarios',
			acao: 'excluir',
			descricao: 'Excluir funcionários'
		},
		{
			nome: 'funcionarios.aprovar_ausencias',
			recurso: 'funcionarios',
			acao: 'aprovar_ausencias',
			descricao: 'Aprovar ausências de funcionários'
		},
		{
			nome: 'funcionarios.aprovar_ferias',
			recurso: 'funcionarios',
			acao: 'aprovar_ferias',
			descricao: 'Aprovar férias de funcionários'
		},
		// Símbolos
		{
			nome: 'simbolos.dashboard',
			recurso: 'simbolos',
			acao: 'dashboard',
			descricao: 'Acessar o painel de símbolos'
		},
		{
			nome: 'simbolos.ver',
			recurso: 'simbolos',
			acao: 'ver',
			descricao: 'Visualizar detalhes de símbolos'
		},
		{
			nome: 'simbolos.listar',
			recurso: 'simbolos',
			acao: 'listar',
			descricao: 'Listar símbolos'
		},
		{
			nome: 'simbolos.criar',
			recurso: 'simbolos',
			acao: 'criar',
			descricao: 'Criar novos símbolos'
		},
		{
			nome: 'simbolos.editar',
			recurso: 'simbolos',
			acao: 'editar',
			descricao: 'Editar símbolos'
		},
		{
			nome: 'simbolos.excluir',
			recurso: 'simbolos',
			acao: 'excluir',
			descricao: 'Excluir símbolos'
		},
		// TI - Usuários
		{
			nome: 'ti_usuarios.listar',
			recurso: 'ti_usuarios',
			acao: 'listar',
			descricao: 'Listar usuários do sistema'
		},
		{
			nome: 'ti_usuarios.criar',
			recurso: 'ti_usuarios',
			acao: 'criar',
			descricao: 'Criar novos usuários de acesso'
		},
		{
			nome: 'ti_usuarios.editar',
			recurso: 'ti_usuarios',
			acao: 'editar',
			descricao: 'Editar usuários de acesso'
		},
		{
			nome: 'ti_usuarios.bloquear',
			recurso: 'ti_usuarios',
			acao: 'bloquear',
			descricao: 'Bloquear ou desbloquear usuários'
		},
		// TI - Perfis
		{
			nome: 'ti_perfis.listar',
			recurso: 'ti_perfis',
			acao: 'listar',
			descricao: 'Listar perfis de acesso'
		},
		{
			nome: 'ti_perfis.criar',
			recurso: 'ti_perfis',
			acao: 'criar',
			descricao: 'Criar novos perfis de acesso'
		},
		{
			nome: 'ti_perfis.editar',
			recurso: 'ti_perfis',
			acao: 'editar',
			descricao: 'Editar perfis de acesso'
		},
		// TI - Painel de Permissões
		{
			nome: 'ti_painel_permissoes.gerenciar',
			recurso: 'ti_painel_permissoes',
			acao: 'gerenciar',
			descricao: 'Gerenciar matriz de permissões por perfil'
		},
		// TI - Solicitações de Acesso
		{
			nome: 'ti_solicitacoes_acesso.ver',
			recurso: 'ti_solicitacoes_acesso',
			acao: 'ver',
			descricao: 'Visualizar solicitações de acesso'
		},
		{
			nome: 'ti_solicitacoes_acesso.aprovar',
			recurso: 'ti_solicitacoes_acesso',
			acao: 'aprovar',
			descricao: 'Aprovar solicitações de acesso'
		},
		{
			nome: 'ti_solicitacoes_acesso.reprovar',
			recurso: 'ti_solicitacoes_acesso',
			acao: 'reprovar',
			descricao: 'Reprovar solicitações de acesso'
		},
		// TI - Configurações de E-mail
		{
			nome: 'ti_configuracoes_email.configurar',
			recurso: 'ti_configuracoes_email',
			acao: 'configurar',
			descricao: 'Configurar parâmetros de envio de e-mail'
		},
		// TI - Monitoramento
		{
			nome: 'ti_monitoramento.ver',
			recurso: 'ti_monitoramento',
			acao: 'ver',
			descricao: 'Acessar painel de monitoramento geral'
		},
		{
			nome: 'ti_monitoramento_emails.ver',
			recurso: 'ti_monitoramento_emails',
			acao: 'ver',
			descricao: 'Acessar monitoramento de envio de e-mails'
		},
		// TI - Notificações
		{
			nome: 'ti_notificacoes.configurar',
			recurso: 'ti_notificacoes',
			acao: 'configurar',
			descricao: 'Configurar notificações do sistema'
		},
		// TI - Times
		{
			nome: 'ti_times.gerenciar',
			recurso: 'ti_times',
			acao: 'gerenciar',
			descricao: 'Gerenciar times/equipes de TI'
		},
		// TI - Painel Administrativo
		{
			nome: 'ti_painel_administrativo.ver',
			recurso: 'ti_painel_administrativo',
			acao: 'ver',
			descricao: 'Acessar painel administrativo de TI'
		},
		// Financeiro
		{
			nome: 'financeiro.ver',
			recurso: 'financeiro',
			acao: 'ver',
			descricao: 'Acessar telas do módulo de financeiro'
		},
		// Controladoria
		{
			nome: 'controladoria.ver',
			recurso: 'controladoria',
			acao: 'ver',
			descricao: 'Acessar telas do módulo de controladoria'
		},
		// Licitações
		{
			nome: 'licitacoes.ver',
			recurso: 'licitacoes',
			acao: 'ver',
			descricao: 'Acessar telas do módulo de licitações'
		},
		{
			nome: 'contratos.listar',
			recurso: 'contratos',
			acao: 'listar',
			descricao: 'Listar contratos'
		},
		{
			nome: 'contratos.criar',
			recurso: 'contratos',
			acao: 'criar',
			descricao: 'Criar novos contratos'
		},
		{
			nome: 'contratos.editar',
			recurso: 'contratos',
			acao: 'editar',
			descricao: 'Editar contratos'
		},
		{
			nome: 'contratos.excluir',
			recurso: 'contratos',
			acao: 'excluir',
			descricao: 'Excluir contratos'
		},
		{
			nome: 'contratos.ver',
			recurso: 'contratos',
			acao: 'ver',
			descricao: 'Visualizar detalhes de contratos'
		},
		// Compras
		{
			nome: 'compras.ver',
			recurso: 'compras',
			acao: 'ver',
			descricao: 'Acessar telas do módulo de compras'
		},
		// Jurídico
		{
			nome: 'juridico.ver',
			recurso: 'juridico',
			acao: 'ver',
			descricao: 'Acessar telas do módulo jurídico'
		},
		// Comunicação
		{
			nome: 'comunicacao.ver',
			recurso: 'comunicacao',
			acao: 'ver',
			descricao: 'Acessar telas do módulo de comunicação'
		},
		// Programas Esportivos
		{
			nome: 'programas_esportivos.ver',
			recurso: 'programas_esportivos',
			acao: 'ver',
			descricao: 'Acessar telas do módulo de programas esportivos'
		},
		// Secretaria Executiva
		{
			nome: 'secretaria_executiva.ver',
			recurso: 'secretaria_executiva',
			acao: 'ver',
			descricao: 'Acessar telas do módulo de secretaria executiva'
		},
		// Gestão de Pessoas
		{
			nome: 'gestao_pessoas.ver',
			recurso: 'gestao_pessoas',
			acao: 'ver',
			descricao: 'Acessar telas do módulo de gestão de pessoas'
		},
		// Setores
		{
			nome: 'setores.listar',
			recurso: 'setores',
			acao: 'listar',
			descricao: 'Listar setores'
		},
		{
			nome: 'setores.criar',
			recurso: 'setores',
			acao: 'criar',
			descricao: 'Criar novos setores'
		},
		{
			nome: 'setores.editar',
			recurso: 'setores',
			acao: 'editar',
			descricao: 'Editar setores'
		},
		{
			nome: 'setores.excluir',
			recurso: 'setores',
			acao: 'excluir',
			descricao: 'Excluir setores'
		},
		// Flow Templates
		{
			nome: 'fluxos.templates.listar',
			recurso: 'fluxos_templates',
			acao: 'listar',
			descricao: 'Listar templates de fluxo'
		},
		{
			nome: 'fluxos.templates.criar',
			recurso: 'fluxos_templates',
			acao: 'criar',
			descricao: 'Criar templates de fluxo'
		},
		{
			nome: 'fluxos.templates.editar',
			recurso: 'fluxos_templates',
			acao: 'editar',
			descricao: 'Editar templates de fluxo'
		},
		{
			nome: 'fluxos.templates.excluir',
			recurso: 'fluxos_templates',
			acao: 'excluir',
			descricao: 'Excluir templates de fluxo'
		},
		// Flow Instances
		{
			nome: 'fluxos.instancias.listar',
			recurso: 'fluxos_instancias',
			acao: 'listar',
			descricao: 'Listar instâncias de fluxo'
		},
		{
			nome: 'fluxos.instancias.criar',
			recurso: 'fluxos_instancias',
			acao: 'criar',
			descricao: 'Criar instâncias de fluxo'
		},
		{
			nome: 'fluxos.instancias.ver',
			recurso: 'fluxos_instancias',
			acao: 'ver',
			descricao: 'Visualizar detalhes de instâncias de fluxo'
		},
		{
			nome: 'fluxos.instancias.atualizar_status',
			recurso: 'fluxos_instancias',
			acao: 'atualizar_status',
			descricao: 'Atualizar status de instâncias de fluxo'
		},
		{
			nome: 'fluxos.instancias.atribuir',
			recurso: 'fluxos_instancias',
			acao: 'atribuir',
			descricao: 'Atribuir responsáveis em instâncias de fluxo'
		},
		// Flow Documents
		{
			nome: 'fluxos.documentos.listar',
			recurso: 'fluxos_documentos',
			acao: 'listar',
			descricao: 'Listar documentos de fluxo'
		},
		{
			nome: 'fluxos.documentos.upload',
			recurso: 'fluxos_documentos',
			acao: 'upload',
			descricao: 'Fazer upload de documentos em fluxos'
		},
		{
			nome: 'fluxos.documentos.excluir',
			recurso: 'fluxos_documentos',
			acao: 'excluir',
			descricao: 'Excluir documentos de fluxos'
		}
	]
} as const;

export const listarRecursosEAcoes = query({
	args: {},
	returns: v.array(
		v.object({
			recurso: v.string(),
			acoes: v.array(v.string())
		})
	),
	handler: async (ctx) => {
		const permissoes = await ctx.db.query('permissoes').collect();

		const recursos: Record<string, Set<string>> = {};
		for (const perm of permissoes) {
			const set = (recursos[perm.recurso] ||= new Set<string>());
			set.add(perm.acao);
		}

		return Object.entries(recursos).map(([recurso, acoes]) => ({
			recurso,
			acoes: Array.from(acoes).sort()
		}));
	}
});

export const listarPermissoesAcoesPorRole = query({
	args: { roleId: v.id('roles') },
	returns: v.array(
		v.object({
			recurso: v.string(),
			acoes: v.array(v.string())
		})
	),
	handler: async (ctx, args) => {
		// Buscar vínculos permissao<-role
		const rolePerms = await ctx.db
			.query('rolePermissoes')
			.withIndex('by_role', (q) => q.eq('roleId', args.roleId))
			.collect();

		// Carregar documentos de permissões vinculadas a este role
		const actionsByResource: Record<string, Set<string>> = {};
		for (const rp of rolePerms) {
			const perm = await ctx.db.get(rp.permissaoId);
			if (!perm) continue;
			const set = (actionsByResource[perm.recurso] ||= new Set<string>());
			set.add(perm.acao);
		}

		return Object.entries(actionsByResource).map(([recurso, acoes]) => ({
			recurso,
			acoes: Array.from(acoes).sort()
		}));
	}
});

export const atualizarPermissaoAcao = mutation({
	args: {
		roleId: v.id('roles'),
		recurso: v.string(),
		acao: v.string(),
		conceder: v.boolean()
	},
	returns: v.null(),
	handler: async (ctx, args) => {
		// Buscar documento de permissão (recurso+acao)
		const permissao = await ctx.db
			.query('permissoes')
			.withIndex('by_recurso_e_acao', (q) => q.eq('recurso', args.recurso).eq('acao', args.acao))
			.first();

		if (!permissao) return null;

		// Verificar vínculo atual
		const existente = await ctx.db
			.query('rolePermissoes')
			.withIndex('by_role', (q) => q.eq('roleId', args.roleId))
			.collect();

		const vinculo = existente.find((rp) => rp.permissaoId === permissao!._id);

		if (args.conceder) {
			if (!vinculo) {
				await ctx.db.insert('rolePermissoes', {
					roleId: args.roleId,
					permissaoId: permissao._id
				});
			}
		} else {
			if (vinculo) {
				await ctx.db.delete(vinculo._id);
			}
		}
		return null;
	}
});

export const seedPermissoesBase = mutation({
	args: {},
	returns: v.null(),
	handler: async (ctx) => {
		console.log('🔐 Seed de permissões base...');

		for (const perm of PERMISSOES_BASE.permissoes) {
			const existente = await ctx.db
				.query('permissoes')
				.withIndex('by_nome', (q) => q.eq('nome', perm.nome))
				.first();

			if (existente) {
				console.log(`  ℹ️ Permissão já existe: ${perm.nome}`);
				continue;
			}

			await ctx.db.insert('permissoes', {
				nome: perm.nome,
				descricao: perm.descricao,
				recurso: perm.recurso,
				acao: perm.acao
			});
			console.log(`  ✅ Permissão criada: ${perm.nome}`);
		}

		return null;
	}
});

export const verificarAcao = query({
	args: {
		usuarioId: v.id('usuarios'),
		recurso: v.string(),
		acao: v.string()
	},
	returns: v.null(),
	handler: async (ctx, args) => {
		const usuario = await ctx.db.get(args.usuarioId);
		if (!usuario) throw new Error('acesso_negado');

		const role = await ctx.db.get(usuario.roleId);
		if (!role) throw new Error('acesso_negado');

		// Níveis administrativos têm acesso total
		if (role.nivel <= 1) return null;

		// Encontrar permissão
		const permissao = await ctx.db
			.query('permissoes')
			.withIndex('by_recurso_e_acao', (q) => q.eq('recurso', args.recurso).eq('acao', args.acao))
			.first();
		if (!permissao) throw new Error('acesso_negado');

		const hasLink = await ctx.db
			.query('rolePermissoes')
			.withIndex('by_role', (q) => q.eq('roleId', usuario.roleId))
			.collect();
		const permitido = hasLink.some((rp) => rp.permissaoId === permissao!._id);
		if (!permitido) throw new Error('acesso_negado');
		return null;
	}
});

export const assertPermissaoAcaoAtual = internalQuery({
	args: {
		recurso: v.string(),
		acao: v.string()
	},
	returns: v.null(),
	handler: async (ctx, args) => {
		const usuarioAtual: Doc<'usuarios'> | null = (await getCurrentUserFunction(ctx)) ?? null;
		if (!usuarioAtual) throw new Error('acesso_negado');

		const role = await ctx.db.get(usuarioAtual.roleId);
		if (!role) throw new Error('acesso_negado');
		if (role.nivel <= 1) return null;

		const permissao = await ctx.db
			.query('permissoes')
			.withIndex('by_recurso_e_acao', (q) => q.eq('recurso', args.recurso).eq('acao', args.acao))
			.first();
		if (!permissao) throw new Error('acesso_negado');

		const links = await ctx.db
			.query('rolePermissoes')
			.withIndex('by_role', (q) => q.eq('roleId', role._id))
			.collect();
		const ok = links.some((rp) => rp.permissaoId === permissao!._id);
		if (!ok) throw new Error('acesso_negado');
		return null;
	}
});
