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

/**
 * Lista todas as associações de endereços para um funcionário
 */
export const listarAssociacoesFuncionario = query({
	args: {
		funcionarioId: v.id('funcionarios'),
		incluirInativos: v.optional(v.boolean())
	},
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		let associacoes;
		if (args.incluirInativos) {
			associacoes = await ctx.db
				.query('funcionarioEnderecosMarcacao')
				.withIndex('by_funcionario', (q) => q.eq('funcionarioId', args.funcionarioId))
				.collect();
		} else {
			associacoes = await ctx.db
				.query('funcionarioEnderecosMarcacao')
				.withIndex('by_funcionario_ativo', (q) =>
					q.eq('funcionarioId', args.funcionarioId).eq('ativo', true)
				)
				.collect();
		}

		// Buscar dados completos dos endereços
		const associacoesCompletas = await Promise.all(
			associacoes.map(async (associacao) => {
				const endereco = await ctx.db.get(associacao.enderecoMarcacaoId);
				if (!endereco) return null;

				// Usar raio personalizado se disponível, senão usar o raio padrão do endereço
				const raioMetros = associacao.raioMetrosPersonalizado ?? endereco.raioMetros;

				return {
					...associacao,
					raioMetros, // Raio usado (personalizado ou padrão)
					endereco: {
						_id: endereco._id,
						nome: endereco.nome,
						descricao: endereco.descricao,
						latitude: endereco.latitude,
						longitude: endereco.longitude,
						endereco: endereco.endereco,
						cep: endereco.cep,
						cidade: endereco.cidade,
						estado: endereco.estado,
						pais: endereco.pais,
						raioMetros: endereco.raioMetros, // Raio padrão do endereço
						tipo: endereco.tipo,
						ativo: endereco.ativo
					}
				};
			})
		);

		return associacoesCompletas.filter((item): item is NonNullable<typeof item> => item !== null);
	}
});

/**
 * Associa um endereço a um funcionário
 */
export const associarEnderecoFuncionario = mutation({
	args: {
		funcionarioId: v.id('funcionarios'),
		enderecoMarcacaoId: v.id('enderecosMarcacao'),
		raioMetrosPersonalizado: v.optional(v.number()),
		dataInicio: v.optional(v.string()), // YYYY-MM-DD
		dataFim: v.optional(v.string()) // YYYY-MM-DD
	},
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		// TODO: Verificar permissões (apenas TI ou admin)

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

		// Validar que o endereço existe e está ativo
		const endereco = await ctx.db.get(args.enderecoMarcacaoId);
		if (!endereco) {
			throw new Error('Endereço não encontrado');
		}
		if (!endereco.ativo) {
			throw new Error('Endereço não está ativo');
		}

		// Validar raio personalizado se fornecido
		if (args.raioMetrosPersonalizado !== undefined) {
			if (args.raioMetrosPersonalizado < 0 || args.raioMetrosPersonalizado > 50000) {
				throw new Error('Raio deve estar entre 0 e 50000 metros');
			}
		}

		// Validar datas se fornecidas
		if (args.dataInicio && args.dataFim) {
			if (args.dataInicio > args.dataFim) {
				throw new Error('Data de início deve ser anterior à data de fim');
			}
		}

		// Verificar se já existe uma associação ativa
		const associacaoExistente = await ctx.db
			.query('funcionarioEnderecosMarcacao')
			.withIndex('by_funcionario_ativo', (q) =>
				q.eq('funcionarioId', args.funcionarioId).eq('ativo', true)
			)
			.filter((q) => q.eq(q.field('enderecoMarcacaoId'), args.enderecoMarcacaoId))
			.first();

		if (associacaoExistente) {
			// Atualizar associação existente
			await ctx.db.patch(associacaoExistente._id, {
				raioMetrosPersonalizado: args.raioMetrosPersonalizado,
				dataInicio: args.dataInicio,
				dataFim: args.dataFim,
				ativo: true
			});

			return { associacaoId: associacaoExistente._id, atualizado: true };
		}

		// Criar nova associação
		const associacaoId = await ctx.db.insert('funcionarioEnderecosMarcacao', {
			funcionarioId: args.funcionarioId,
			enderecoMarcacaoId: args.enderecoMarcacaoId,
			raioMetrosPersonalizado: args.raioMetrosPersonalizado,
			dataInicio: args.dataInicio,
			dataFim: args.dataFim,
			ativo: true,
			criadoPor: usuario._id as Id<'usuarios'>,
			criadoEm: Date.now()
		});

		return { associacaoId, atualizado: false };
	}
});

/**
 * Atualiza uma associação de endereço com funcionário
 */
export const atualizarAssociacao = mutation({
	args: {
		associacaoId: v.id('funcionarioEnderecosMarcacao'),
		raioMetrosPersonalizado: v.optional(v.number()),
		dataInicio: v.optional(v.string()),
		dataFim: v.optional(v.string()),
		ativo: v.optional(v.boolean())
	},
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		// TODO: Verificar permissões (apenas TI ou admin)

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

		const atualizacoes: {
			raioMetrosPersonalizado?: number;
			dataInicio?: string;
			dataFim?: string;
			ativo?: boolean;
		} = {};

		if (args.raioMetrosPersonalizado !== undefined) {
			if (args.raioMetrosPersonalizado < 0 || args.raioMetrosPersonalizado > 50000) {
				throw new Error('Raio deve estar entre 0 e 50000 metros');
			}
			atualizacoes.raioMetrosPersonalizado = args.raioMetrosPersonalizado;
		}

		if (args.dataInicio !== undefined) {
			atualizacoes.dataInicio = args.dataInicio || undefined;
		}

		if (args.dataFim !== undefined) {
			atualizacoes.dataFim = args.dataFim || undefined;
		}

		if (args.dataInicio && args.dataFim) {
			if (args.dataInicio > args.dataFim) {
				throw new Error('Data de início deve ser anterior à data de fim');
			}
		}

		if (args.ativo !== undefined) {
			atualizacoes.ativo = args.ativo;
		}

		await ctx.db.patch(args.associacaoId, atualizacoes);

		return { sucesso: true };
	}
});

/**
 * Remove uma associação de endereço com funcionário (desativa)
 */
export const removerAssociacao = mutation({
	args: {
		associacaoId: v.id('funcionarioEnderecosMarcacao')
	},
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		// TODO: Verificar permissões (apenas TI ou admin)

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

		// Desativar ao invés de deletar
		await ctx.db.patch(args.associacaoId, {
			ativo: false
		});

		return { sucesso: true };
	}
});
