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

/**
 * Valida formato de horário HH:mm
 */
function validarHorario(horario: string): boolean {
	const regex = /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/;
	return regex.test(horario);
}

/**
 * Obtém a configuração ativa de ponto
 */
export const obterConfiguracao = query({
	args: {},
	handler: async (ctx) => {
		const config = await ctx.db
			.query('configuracaoPonto')
			.withIndex('by_ativo', (q) => q.eq('ativo', true))
			.first();

		if (!config) {
			// Retornar configuração padrão se não houver
			return {
				horarioEntrada: '08:00',
				horarioSaidaAlmoco: '12:00',
				horarioRetornoAlmoco: '13:00',
				horarioSaida: '17:00',
				toleranciaMinutos: 15,
				nomeEntrada: 'Entrada 1',
				nomeSaidaAlmoco: 'Saída 1',
				nomeRetornoAlmoco: 'Entrada 2',
				nomeSaida: 'Saída 2',
				validarLocalizacao: true,
				toleranciaDistanciaMetros: 100,
				ativo: false
			};
		}

		// Garantir que os nomes padrão e valores padrão estejam definidos
		return {
			...config,
			nomeEntrada: config.nomeEntrada || 'Entrada 1',
			nomeSaidaAlmoco: config.nomeSaidaAlmoco || 'Saída 1',
			nomeRetornoAlmoco: config.nomeRetornoAlmoco || 'Entrada 2',
			nomeSaida: config.nomeSaida || 'Saída 2',
			validarLocalizacao: config.validarLocalizacao ?? true,
			toleranciaDistanciaMetros: config.toleranciaDistanciaMetros ?? 100
		};
	}
});

/**
 * Salva configuração de ponto (apenas TI)
 */
export const salvarConfiguracao = mutation({
	args: {
		horarioEntrada: v.string(),
		horarioSaidaAlmoco: v.string(),
		horarioRetornoAlmoco: v.string(),
		horarioSaida: v.string(),
		toleranciaMinutos: v.number(),
		nomeEntrada: v.optional(v.string()),
		nomeSaidaAlmoco: v.optional(v.string()),
		nomeRetornoAlmoco: v.optional(v.string()),
		nomeSaida: v.optional(v.string()),
		validarLocalizacao: v.optional(v.boolean()),
		toleranciaDistanciaMetros: v.optional(v.number())
	},
	handler: async (ctx, args) => {
		const usuario = await getCurrentUserFunction(ctx);
		if (!usuario) {
			throw new Error('Usuário não autenticado');
		}

		// TODO: Verificar se usuário tem permissão de TI
		// Por enquanto, permitir se tiver roleId

		// Validar horários
		if (!validarHorario(args.horarioEntrada)) {
			throw new Error('Horário de entrada inválido (formato: HH:mm)');
		}
		if (!validarHorario(args.horarioSaidaAlmoco)) {
			throw new Error('Horário de saída para almoço inválido (formato: HH:mm)');
		}
		if (!validarHorario(args.horarioRetornoAlmoco)) {
			throw new Error('Horário de retorno do almoço inválido (formato: HH:mm)');
		}
		if (!validarHorario(args.horarioSaida)) {
			throw new Error('Horário de saída inválido (formato: HH:mm)');
		}

		// Validar tolerância
		if (args.toleranciaMinutos < 0 || args.toleranciaMinutos > 60) {
			throw new Error('Tolerância deve estar entre 0 e 60 minutos');
		}

		// Validar sequência lógica de horários
		const [horaEntrada, minutoEntrada] = args.horarioEntrada.split(':').map(Number);
		const [horaSaidaAlmoco, minutoSaidaAlmoco] = args.horarioSaidaAlmoco.split(':').map(Number);
		const [horaRetornoAlmoco, minutoRetornoAlmoco] = args.horarioRetornoAlmoco
			.split(':')
			.map(Number);
		const [horaSaida, minutoSaida] = args.horarioSaida.split(':').map(Number);

		const minutosEntrada = horaEntrada * 60 + minutoEntrada;
		const minutosSaidaAlmoco = horaSaidaAlmoco * 60 + minutoSaidaAlmoco;
		const minutosRetornoAlmoco = horaRetornoAlmoco * 60 + minutoRetornoAlmoco;
		const minutosSaida = horaSaida * 60 + minutoSaida;

		if (minutosEntrada >= minutosSaidaAlmoco) {
			throw new Error('Horário de entrada deve ser anterior à saída para almoço');
		}
		if (minutosSaidaAlmoco >= minutosRetornoAlmoco) {
			throw new Error('Horário de saída para almoço deve ser anterior ao retorno');
		}
		if (minutosRetornoAlmoco >= minutosSaida) {
			throw new Error('Horário de retorno do almoço deve ser anterior à saída');
		}

		// Validar tolerância de distância se fornecida
		if (args.toleranciaDistanciaMetros !== undefined) {
			if (args.toleranciaDistanciaMetros < 0 || args.toleranciaDistanciaMetros > 50000) {
				throw new Error('Tolerância de distância deve estar entre 0 e 50000 metros');
			}
		}

		// Desativar configurações antigas
		const configsAntigas = await ctx.db
			.query('configuracaoPonto')
			.withIndex('by_ativo', (q) => q.eq('ativo', true))
			.collect();

		for (const configAntiga of configsAntigas) {
			await ctx.db.patch(configAntiga._id, { ativo: false });
		}

		// Criar nova configuração
		const configId = await ctx.db.insert('configuracaoPonto', {
			horarioEntrada: args.horarioEntrada,
			horarioSaidaAlmoco: args.horarioSaidaAlmoco,
			horarioRetornoAlmoco: args.horarioRetornoAlmoco,
			horarioSaida: args.horarioSaida,
			toleranciaMinutos: args.toleranciaMinutos,
			nomeEntrada: args.nomeEntrada || 'Entrada 1',
			nomeSaidaAlmoco: args.nomeSaidaAlmoco || 'Saída 1',
			nomeRetornoAlmoco: args.nomeRetornoAlmoco || 'Entrada 2',
			nomeSaida: args.nomeSaida || 'Saída 2',
			validarLocalizacao: args.validarLocalizacao ?? true,
			toleranciaDistanciaMetros: args.toleranciaDistanciaMetros ?? 100,
			ativo: true,
			atualizadoPor: usuario._id as Id<'usuarios'>,
			atualizadoEm: Date.now()
		});

		return { configId };
	}
});
