import { defineTable } from 'convex/server';
import { v } from 'convex/values';

export const pontoTables = {
	// Sistema de Controle de Ponto
	registrosPonto: defineTable({
		funcionarioId: v.id('funcionarios'),
		tipo: v.union(
			v.literal('entrada'),
			v.literal('saida_almoco'),
			v.literal('retorno_almoco'),
			v.literal('saida')
		),
		data: v.string(), // YYYY-MM-DD
		hora: v.number(),
		minuto: v.number(),
		segundo: v.number(),
		timestamp: v.number(), // Timestamp completo para ordenação
		imagemId: v.optional(v.id('_storage')),
		sincronizadoComServidor: v.boolean(),
		toleranciaMinutos: v.number(),
		dentroDoPrazo: v.boolean(),

		// Informações de Rede
		ipAddress: v.optional(v.string()),
		ipPublico: v.optional(v.string()),
		ipLocal: v.optional(v.string()),

		// Informações do Navegador
		userAgent: v.optional(v.string()),
		browser: v.optional(v.string()),
		browserVersion: v.optional(v.string()),
		engine: v.optional(v.string()),

		// Informações do Sistema
		sistemaOperacional: v.optional(v.string()),
		osVersion: v.optional(v.string()),
		arquitetura: v.optional(v.string()),
		plataforma: v.optional(v.string()),

		// Informações de Localização
		latitude: v.optional(v.number()),
		longitude: v.optional(v.number()),
		precisao: v.optional(v.number()),
		altitude: v.optional(v.union(v.number(), v.null())),
		altitudeAccuracy: v.optional(v.union(v.number(), v.null())),
		heading: v.optional(v.union(v.number(), v.null())),
		speed: v.optional(v.union(v.number(), v.null())),
		confiabilidadeGPS: v.optional(v.number()), // 0-1 (frontend)
		scoreConfiancaBackend: v.optional(v.number()), // 0-1 (backend)
		suspeitaSpoofing: v.optional(v.boolean()),
		motivoSuspeita: v.optional(v.string()),
		avisosValidacao: v.optional(v.array(v.string())), // Array de avisos detalhados da validação
		distanciaIPvsGPS: v.optional(v.number()), // Distância em metros entre IP geolocation e GPS
		velocidadeUltimoRegistro: v.optional(v.number()), // Velocidade em km/h do último registro
		distanciaUltimoRegistro: v.optional(v.number()), // Distância em metros do último registro
		tempoDecorridoHoras: v.optional(v.number()), // Tempo em horas desde o último registro
		// Informações de Geofencing
		enderecoMarcacaoEsperado: v.optional(v.id('enderecosMarcacao')), // Endereço mais próximo esperado
		distanciaEnderecoEsperado: v.optional(v.number()), // Distância em metros do endereço esperado
		dentroRaioPermitido: v.optional(v.boolean()), // Se está dentro do raio permitido
		enderecoMarcacaoUsado: v.optional(v.id('enderecosMarcacao')), // Qual endereço foi usado na validação
		raioToleranciaUsado: v.optional(v.number()), // Raio usado na validação em metros
		endereco: v.optional(v.string()),
		cidade: v.optional(v.string()),
		estado: v.optional(v.string()),
		pais: v.optional(v.string()),
		timezone: v.optional(v.string()),

		// Informações do Dispositivo
		deviceType: v.optional(v.string()),
		deviceModel: v.optional(v.string()),
		screenResolution: v.optional(v.string()),
		coresTela: v.optional(v.number()),
		idioma: v.optional(v.string()),

		// Informações Adicionais
		isMobile: v.optional(v.boolean()),
		isTablet: v.optional(v.boolean()),
		isDesktop: v.optional(v.boolean()),
		connectionType: v.optional(v.string()),
		memoryInfo: v.optional(v.string()),

		// Informações de Sensores (Acelerômetro e Giroscópio)
		acelerometroX: v.optional(v.number()),
		acelerometroY: v.optional(v.number()),
		acelerometroZ: v.optional(v.number()),
		movimentoDetectado: v.optional(v.boolean()),
		magnitudeMovimento: v.optional(v.number()),
		variacaoAcelerometro: v.optional(v.number()),
		giroscopioAlpha: v.optional(v.number()),
		giroscopioBeta: v.optional(v.number()),
		giroscopioGamma: v.optional(v.number()),
		sensorDisponivel: v.optional(v.boolean()),
		permissaoSensorNegada: v.optional(v.boolean()),

		// Justificativa opcional para o registro
		justificativa: v.optional(v.string()),

		// Campos para homologação
		editadoPorGestor: v.optional(v.boolean()),
		homologacaoId: v.optional(v.id('homologacoesPonto')),

		criadoEm: v.number()
	})
		.index('by_funcionario_data', ['funcionarioId', 'data'])
		.index('by_data', ['data'])
		.index('by_dentro_prazo', ['dentroDoPrazo', 'data'])
		.index('by_funcionario_timestamp', ['funcionarioId', 'timestamp']),

	// Endereços de Marcação - Locais permitidos para registro de ponto
	enderecosMarcacao: defineTable({
		nome: v.string(), // Ex: "Sede Principal", "Home Office João Silva", "Cliente ABC"
		descricao: v.optional(v.string()), // Descrição opcional
		// Coordenadas (obrigatórias)
		latitude: v.number(),
		longitude: v.number(),
		// Endereço físico (para exibição)
		endereco: v.string(), // Ex: "Rua Exemplo, 123"
		bairro: v.optional(v.string()), // Bairro do endereço
		cep: v.optional(v.string()),
		cidade: v.string(),
		estado: v.string(),
		pais: v.optional(v.string()), // Padrão: "Brasil"
		// Configurações
		raioMetros: v.number(), // Raio de tolerância em metros (ex: 100m, 500m, 1000m)
		ativo: v.boolean(),
		// Tipos de uso
		tipo: v.union(
			v.literal('sede'), // Sede principal (para todos)
			v.literal('home_office'), // Home office específico
			v.literal('deslocamento'), // Deslocamento temporário
			v.literal('cliente') // Local de cliente
		),
		// Metadados
		criadoPor: v.id('usuarios'),
		criadoEm: v.number(),
		atualizadoPor: v.optional(v.id('usuarios')),
		atualizadoEm: v.optional(v.number())
	})
		.index('by_ativo', ['ativo'])
		.index('by_tipo', ['tipo'])
		.index('by_cidade', ['cidade']),

	// Associação Funcionário ↔ Endereço de Marcação
	funcionarioEnderecosMarcacao: defineTable({
		funcionarioId: v.id('funcionarios'),
		enderecoMarcacaoId: v.id('enderecosMarcacao'),
		// Configurações específicas do funcionário
		raioMetrosPersonalizado: v.optional(v.number()), // Pode ter raio diferente do padrão
		// Período de validade (para deslocamentos temporários)
		dataInicio: v.optional(v.string()), // YYYY-MM-DD
		dataFim: v.optional(v.string()), // YYYY-MM-DD
		// Status
		ativo: v.boolean(),
		// Metadados
		criadoPor: v.id('usuarios'),
		criadoEm: v.number()
	})
		.index('by_funcionario', ['funcionarioId'])
		.index('by_endereco', ['enderecoMarcacaoId'])
		.index('by_funcionario_ativo', ['funcionarioId', 'ativo'])
		.index('by_endereco_ativo', ['enderecoMarcacaoId', 'ativo']),

	configuracaoPonto: defineTable({
		horarioEntrada: v.string(), // HH:mm
		horarioSaidaAlmoco: v.string(), // HH:mm
		horarioRetornoAlmoco: v.string(), // HH:mm
		horarioSaida: v.string(), // HH:mm
		toleranciaMinutos: v.number(),
		// Nomes personalizados dos tipos de registro
		nomeEntrada: v.optional(v.string()), // Padrão: "Entrada 1"
		nomeSaidaAlmoco: v.optional(v.string()), // Padrão: "Saída 1"
		nomeRetornoAlmoco: v.optional(v.string()), // Padrão: "Entrada 2"
		nomeSaida: v.optional(v.string()), // Padrão: "Saída 2"
		// Ajuste de fuso horário (GMT offset em horas)
		gmtOffset: v.optional(v.number()), // Padrão: 0 (UTC)
		// Configurações de geofencing
		validarLocalizacao: v.optional(v.boolean()), // Habilitar/desabilitar validação de localização
		toleranciaDistanciaMetros: v.optional(v.number()), // Raio padrão global em metros
		ativo: v.boolean(),
		atualizadoPor: v.id('usuarios'),
		atualizadoEm: v.number()
	}).index('by_ativo', ['ativo']),

	configuracaoRelogio: defineTable({
		servidorNTP: v.optional(v.string()),
		portaNTP: v.optional(v.number()),
		usarServidorExterno: v.boolean(),
		fallbackParaPC: v.boolean(),
		ultimaSincronizacao: v.optional(v.number()),
		offsetSegundos: v.optional(v.number()),
		// Ajuste de fuso horário (GMT offset em horas)
		gmtOffset: v.optional(v.number()), // Padrão: 0 (UTC)
		atualizadoPor: v.id('usuarios'),
		atualizadoEm: v.number()
	}).index('by_ativo', ['usarServidorExterno']),

	// Banco de Horas - Saldo diário de horas trabalhadas
	bancoHoras: defineTable({
		funcionarioId: v.id('funcionarios'),
		data: v.string(), // YYYY-MM-DD
		cargaHorariaDiaria: v.number(), // Horas esperadas do dia (em minutos)
		horasTrabalhadas: v.number(), // Horas realmente trabalhadas (em minutos)
		saldoMinutos: v.number(), // Saldo do dia (positivo = horas extras, negativo = déficit)
		registrosPontoIds: v.array(v.id('registrosPonto')), // IDs dos registros do dia
		// Novos campos para sistema avançado
		ajustesIds: v.optional(v.array(v.id('ajustesBancoHoras'))), // IDs dos ajustes aplicados no dia
		motivoAbono: v.optional(v.string()), // Motivo do abono (atestado, licença, ausência, etc.)
		tipoDia: v.optional(
			v.union(
				v.literal('normal'),
				v.literal('atestado'),
				v.literal('licenca'),
				v.literal('ausencia'),
				v.literal('abonado'),
				v.literal('descontado')
			)
		), // Tipo do dia
		inconsistenciasIds: v.optional(v.array(v.id('inconsistenciasBancoHoras'))), // IDs de inconsistências detectadas
		calculadoEm: v.number()
	})
		.index('by_funcionario_data', ['funcionarioId', 'data'])
		.index('by_funcionario', ['funcionarioId'])
		.index('by_data', ['data'])
		.index('by_tipo_dia', ['tipoDia']),

	// Banco de Horas Mensal - Agregação mensal do banco de horas
	bancoHorasMensal: defineTable({
		funcionarioId: v.id('funcionarios'),
		mes: v.string(), // YYYY-MM (ex: "2024-01")
		saldoInicialMinutos: v.number(), // Saldo acumulado do mês anterior (pode ser negativo)
		saldoFinalMinutos: v.number(), // Saldo acumulado ao final do mês
		saldoMesMinutos: v.number(), // Saldo apenas do mês atual (sem acumular)
		diasTrabalhados: v.number(), // Quantidade de dias com registros no mês
		horasExtras: v.number(), // Total de minutos positivos do mês
		horasDeficit: v.number(), // Total de minutos negativos do mês (valor absoluto)
		// Novos campos para sistema avançado
		totalAjustes: v.optional(v.number()), // Total de ajustes aplicados no mês (em minutos)
		totalAbonos: v.optional(v.number()), // Total de abonos no mês (em minutos)
		totalDescontos: v.optional(v.number()), // Total de descontos no mês (em minutos)
		inconsistenciasResolvidas: v.optional(v.number()), // Quantidade de inconsistências resolvidas
		calculadoEm: v.number(),
		atualizadoEm: v.number()
	})
		.index('by_funcionario_mes', ['funcionarioId', 'mes'])
		.index('by_funcionario', ['funcionarioId'])
		.index('by_mes', ['mes']),

	// Homologações de Ponto - Edições e ajustes realizados pelo gestor
	homologacoesPonto: defineTable({
		registroId: v.optional(v.id('registrosPonto')), // ID do registro editado (se for edição)
		funcionarioId: v.id('funcionarios'),
		gestorId: v.id('usuarios'),
		// Dados do registro original (se for edição)
		horaAnterior: v.optional(v.number()),
		minutoAnterior: v.optional(v.number()),
		// Dados do registro novo (se for edição)
		horaNova: v.optional(v.number()),
		minutoNova: v.optional(v.number()),
		// Motivo e observações
		motivoId: v.optional(v.string()), // ID do motivo (referência a atestados/declarações)
		motivoTipo: v.optional(v.string()), // Tipo do motivo (atestado, declaracao, etc)
		motivoDescricao: v.optional(v.string()), // Descrição do motivo
		observacoes: v.optional(v.string()),
		// Tipo de ajuste (se for ajuste de banco de horas)
		tipoAjuste: v.optional(
			v.union(v.literal('compensar'), v.literal('abonar'), v.literal('descontar'))
		),
		// Período do ajuste (se for ajuste de banco de horas)
		periodoDias: v.optional(v.number()),
		periodoHoras: v.optional(v.number()),
		periodoMinutos: v.optional(v.number()),
		// Ajuste em minutos (calculado)
		ajusteMinutos: v.optional(v.number()),
		criadoEm: v.number()
	})
		.index('by_funcionario', ['funcionarioId'])
		.index('by_gestor', ['gestorId'])
		.index('by_registro', ['registroId'])
		.index('by_data', ['criadoEm']),

	// Dispensas de Registro - Períodos onde funcionário está dispensado de registrar ponto
	dispensasRegistro: defineTable({
		funcionarioId: v.id('funcionarios'),
		gestorId: v.id('usuarios'),
		dataInicio: v.string(), // YYYY-MM-DD
		horaInicio: v.number(),
		minutoInicio: v.number(),
		dataFim: v.string(), // YYYY-MM-DD
		horaFim: v.number(),
		minutoFim: v.number(),
		motivo: v.string(),
		isento: v.boolean(), // Se true, não expira (casos excepcionais)
		ativo: v.boolean(),
		criadoEm: v.number()
	})
		.index('by_funcionario', ['funcionarioId'])
		.index('by_gestor', ['gestorId'])
		.index('by_ativo', ['ativo'])
		.index('by_data_inicio', ['dataInicio'])
		.index('by_data_fim', ['dataFim']),

	// Configuração de Banco de Horas - Configurações gerais do sistema
	configuracaoBancoHoras: defineTable({
		// Limites de saldo
		limiteSaldoPositivoMinutos: v.optional(v.number()), // Limite máximo de saldo positivo (em minutos)
		limiteSaldoNegativoMinutos: v.optional(v.number()), // Limite máximo de saldo negativo (em minutos)
		// Regras de cálculo
		considerarAjustesAutomaticos: v.optional(v.boolean()), // Se deve considerar ajustes automáticos (atestados, licenças, ausências)
		// Periodicidade de verificação
		periodicidadeVerificacao: v.optional(
			v.union(v.literal('diario'), v.literal('semanal'), v.literal('mensal'))
		),
		// Metadados
		atualizadoPor: v.id('usuarios'),
		atualizadoEm: v.number()
	}).index('by_ativo', ['atualizadoEm']),

	// Alertas de Banco de Horas - Configuração de alertas por tipo
	alertasBancoHoras: defineTable({
		tipoAlerta: v.union(
			v.literal('saldo_negativo'),
			v.literal('saldo_negativo_critico'),
			v.literal('inconsistencia_detectada'),
			v.literal('dias_sem_registro'),
			v.literal('limite_saldo_excedido')
		),
		// Periodicidade
		periodicidade: v.union(v.literal('diario'), v.literal('semanal'), v.literal('mensal')),
		// Canais de envio
		enviarEmail: v.boolean(),
		enviarChat: v.boolean(),
		// Destinatários específicos (opcional - se vazio, envia para gestor padrão)
		destinatariosEmail: v.optional(v.array(v.id('usuarios'))), // IDs de usuários que receberão email
		destinatariosChat: v.optional(v.array(v.id('usuarios'))), // IDs de usuários que receberão chat
		// Thresholds e limites
		threshold: v.optional(v.number()), // Valor limite para disparar alerta
		limiteMinutos: v.optional(v.number()), // Limite em minutos (para saldo negativo)
		// Status
		ativo: v.boolean(),
		// Metadados
		criadoPor: v.id('usuarios'),
		criadoEm: v.number(),
		atualizadoPor: v.optional(v.id('usuarios')),
		atualizadoEm: v.optional(v.number())
	})
		.index('by_tipo', ['tipoAlerta'])
		.index('by_ativo', ['ativo'])
		.index('by_tipo_ativo', ['tipoAlerta', 'ativo']),

	// Ajustes de Banco de Horas - Registro de ajustes manuais e automáticos
	ajustesBancoHoras: defineTable({
		funcionarioId: v.id('funcionarios'),
		tipo: v.union(v.literal('abonar'), v.literal('descontar'), v.literal('compensar')),
		// Motivo vinculado
		motivoTipo: v.optional(
			v.union(
				v.literal('atestado'),
				v.literal('licenca'),
				v.literal('ausencia'),
				v.literal('manual')
			)
		),
		motivoId: v.optional(v.string()), // ID do atestado, licença, ausência ou null para manual
		motivoDescricao: v.optional(v.string()), // Descrição do motivo
		// Valor do ajuste
		valorMinutos: v.number(), // Valor em minutos (positivo para abonar, negativo para descontar)
		// Data de aplicação
		dataAplicacao: v.string(), // YYYY-MM-DD
		// Gestor responsável (null se automático)
		gestorId: v.optional(v.id('usuarios')),
		// Observações
		observacoes: v.optional(v.string()),
		// Status
		aplicado: v.boolean(), // Se já foi aplicado ao banco de horas
		// Metadados
		criadoEm: v.number(),
		aplicadoEm: v.optional(v.number())
	})
		.index('by_funcionario', ['funcionarioId'])
		.index('by_data_aplicacao', ['dataAplicacao'])
		.index('by_funcionario_data', ['funcionarioId', 'dataAplicacao'])
		.index('by_tipo', ['tipo'])
		.index('by_aplicado', ['aplicado'])
		.index('by_gestor', ['gestorId']),

	// Inconsistências de Banco de Horas - Registro de inconsistências detectadas
	inconsistenciasBancoHoras: defineTable({
		funcionarioId: v.id('funcionarios'),
		tipo: v.union(
			v.literal('ponto_com_atestado'),
			v.literal('ponto_com_licenca'),
			v.literal('ponto_com_ausencia'),
			v.literal('registro_duplicado'),
			v.literal('sequencia_invalida'),
			v.literal('saldo_inconsistente')
		),
		descricao: v.string(), // Descrição detalhada da inconsistência
		dataDetectada: v.string(), // YYYY-MM-DD
		dataInconsistencia: v.string(), // YYYY-MM-DD (data do dia com inconsistência)
		// Status
		status: v.union(v.literal('pendente'), v.literal('resolvida'), v.literal('ignorada')),
		// Resolução
		resolucao: v.optional(v.string()), // Descrição da resolução
		resolvidoPor: v.optional(v.id('usuarios')), // Usuário que resolveu
		resolvidoEm: v.optional(v.number()), // Timestamp da resolução
		// Metadados
		criadoEm: v.number()
	})
		.index('by_funcionario', ['funcionarioId'])
		.index('by_status', ['status'])
		.index('by_funcionario_status', ['funcionarioId', 'status'])
		.index('by_data_detectada', ['dataDetectada'])
		.index('by_tipo', ['tipo'])
		.index('by_data_inconsistencia', ['dataInconsistencia'])
};
