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

/**
 * Listar todos os setores
 */
export const list = query({
	args: {},
	returns: v.array(
		v.object({
			_id: v.id('setores'),
			_creationTime: v.number(),
			nome: v.string(),
			sigla: v.string(),
			criadoPor: v.id('usuarios'),
			createdAt: v.number()
		})
	),
	handler: async (ctx) => {
		const setores = await ctx.db.query('setores').order('asc').collect();
		return setores;
	}
});

/**
 * Obter um setor pelo ID
 */
export const getById = query({
	args: { id: v.id('setores') },
	returns: v.union(
		v.object({
			_id: v.id('setores'),
			_creationTime: v.number(),
			nome: v.string(),
			sigla: v.string(),
			criadoPor: v.id('usuarios'),
			createdAt: v.number()
		}),
		v.null()
	),
	handler: async (ctx, args) => {
		const setor = await ctx.db.get(args.id);
		return setor;
	}
});

/**
 * Criar um novo setor
 */
export const create = mutation({
	args: {
		nome: v.string(),
		sigla: v.string()
	},
	returns: v.id('setores'),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		// Verificar se já existe setor com mesmo nome ou sigla
		const existenteNome = await ctx.db
			.query('setores')
			.withIndex('by_nome', (q) => q.eq('nome', args.nome))
			.first();
		if (existenteNome) {
			throw new Error('Já existe um setor com este nome');
		}

		const existenteSigla = await ctx.db
			.query('setores')
			.withIndex('by_sigla', (q) => q.eq('sigla', args.sigla))
			.first();
		if (existenteSigla) {
			throw new Error('Já existe um setor com esta sigla');
		}

		const setorId = await ctx.db.insert('setores', {
			nome: args.nome,
			sigla: args.sigla.toUpperCase(),
			criadoPor: usuario._id,
			createdAt: Date.now()
		});

		return setorId;
	}
});

/**
 * Atualizar um setor existente
 */
export const update = mutation({
	args: {
		id: v.id('setores'),
		nome: v.string(),
		sigla: v.string()
	},
	returns: v.null(),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		const setor = await ctx.db.get(args.id);
		if (!setor) {
			throw new Error('Setor não encontrado');
		}

		// Verificar se já existe outro setor com mesmo nome
		const existenteNome = await ctx.db
			.query('setores')
			.withIndex('by_nome', (q) => q.eq('nome', args.nome))
			.first();
		if (existenteNome && existenteNome._id !== args.id) {
			throw new Error('Já existe um setor com este nome');
		}

		// Verificar se já existe outro setor com mesma sigla
		const existenteSigla = await ctx.db
			.query('setores')
			.withIndex('by_sigla', (q) => q.eq('sigla', args.sigla))
			.first();
		if (existenteSigla && existenteSigla._id !== args.id) {
			throw new Error('Já existe um setor com esta sigla');
		}

		await ctx.db.patch(args.id, {
			nome: args.nome,
			sigla: args.sigla.toUpperCase()
		});

		return null;
	}
});

/**
 * Obter funcionários de um setor específico
 */
export const getFuncionariosBySetor = query({
	args: { setorId: v.id('setores') },
	returns: v.array(
		v.object({
			_id: v.id('funcionarios'),
			_creationTime: v.number(),
			nome: v.string(),
			matricula: v.optional(v.string()),
			email: v.string(),
			cpf: v.string()
		})
	),
	handler: async (ctx, args) => {
		// Buscar todas as relações funcionarioSetores para este setor
		const funcionarioSetores = await ctx.db
			.query('funcionarioSetores')
			.withIndex('by_setorId', (q) => q.eq('setorId', args.setorId))
			.collect();

		// Buscar os funcionários correspondentes
		const funcionarios = [];
		for (const relacao of funcionarioSetores) {
			const funcionario = await ctx.db.get(relacao.funcionarioId);
			if (funcionario) {
				funcionarios.push({
					_id: funcionario._id,
					_creationTime: funcionario._creationTime,
					nome: funcionario.nome,
					matricula: funcionario.matricula,
					email: funcionario.email,
					cpf: funcionario.cpf
				});
			}
		}

		return funcionarios;
	}
});

/**
 * Obter setores de um funcionário
 */
export const getSetoresByFuncionario = query({
	args: { funcionarioId: v.id('funcionarios') },
	returns: v.array(
		v.object({
			_id: v.id('setores'),
			_creationTime: v.number(),
			nome: v.string(),
			sigla: v.string(),
			criadoPor: v.id('usuarios'),
			createdAt: v.number()
		})
	),
	handler: async (ctx, args) => {
		// Buscar todas as relações funcionarioSetores para este funcionário
		const funcionarioSetores = await ctx.db
			.query('funcionarioSetores')
			.withIndex('by_funcionarioId', (q) => q.eq('funcionarioId', args.funcionarioId))
			.collect();

		// Buscar os setores correspondentes
		const setores = [];
		for (const relacao of funcionarioSetores) {
			const setor = await ctx.db.get(relacao.setorId);
			if (setor) {
				setores.push(setor);
			}
		}

		return setores;
	}
});

/**
 * Atualizar setores de um funcionário
 */
export const atualizarSetoresFuncionario = mutation({
	args: {
		funcionarioId: v.id('funcionarios'),
		setorIds: v.array(v.id('setores'))
	},
	returns: v.null(),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		// Verificar se o funcionário existe
		const funcionario = await ctx.db.get(args.funcionarioId);
		if (!funcionario) {
			throw new Error('Funcionário não encontrado');
		}

		// Verificar se todos os setores existem
		for (const setorId of args.setorIds) {
			const setor = await ctx.db.get(setorId);
			if (!setor) {
				throw new Error(`Setor ${setorId} não encontrado`);
			}
		}

		// Remover todas as relações existentes do funcionário
		const funcionarioSetoresExistentes = await ctx.db
			.query('funcionarioSetores')
			.withIndex('by_funcionarioId', (q) => q.eq('funcionarioId', args.funcionarioId))
			.collect();

		for (const relacao of funcionarioSetoresExistentes) {
			await ctx.db.delete(relacao._id);
		}

		// Criar novas relações para os setores selecionados
		const now = Date.now();
		for (const setorId of args.setorIds) {
			// Verificar se já existe relação (evitar duplicatas)
			const existe = await ctx.db
				.query('funcionarioSetores')
				.withIndex('by_funcionarioId_and_setorId', (q) =>
					q.eq('funcionarioId', args.funcionarioId).eq('setorId', setorId)
				)
				.first();

			if (!existe) {
				await ctx.db.insert('funcionarioSetores', {
					funcionarioId: args.funcionarioId,
					setorId,
					createdAt: now
				});
			}
		}

		return null;
	}
});

/**
 * Excluir um setor
 */
export const remove = mutation({
	args: { id: v.id('setores') },
	returns: v.null(),
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		const setor = await ctx.db.get(args.id);
		if (!setor) {
			throw new Error('Setor não encontrado');
		}

		// Verificar se há funcionários vinculados
		const funcionariosVinculados = await ctx.db
			.query('funcionarioSetores')
			.withIndex('by_setorId', (q) => q.eq('setorId', args.id))
			.first();
		if (funcionariosVinculados) {
			throw new Error('Não é possível excluir um setor com funcionários vinculados');
		}

		// Verificar se há passos de fluxo vinculados
		const passosVinculados = await ctx.db.query('flowSteps').collect();
		const temPassosVinculados = passosVinculados.some((p) => p.setorId === args.id);
		if (temPassosVinculados) {
			throw new Error('Não é possível excluir um setor vinculado a passos de fluxo');
		}

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