<script lang="ts">
	import { onMount } from 'svelte';
	import { useConvexClient, useQuery } from 'convex-svelte';
	import { api } from '@sgse-app/backend/convex/_generated/api';
	import RelogioSincronizado from './RelogioSincronizado.svelte';
	import WebcamCapture from './WebcamCapture.svelte';
	import ComprovantePonto from './ComprovantePonto.svelte';
	import ErrorModal from '../ErrorModal.svelte';
	import { obterTempoServidor } from '$lib/utils/sincronizacaoTempo';
	import { obterInformacoesDispositivo } from '$lib/utils/deviceInfo';
	import {
		formatarHoraPonto,
		getTipoRegistroLabel,
		getProximoTipoRegistro
	} from '$lib/utils/ponto';
	import {
		LogIn,
		LogOut,
		Clock,
		CheckCircle2,
		XCircle,
		TrendingUp,
		TrendingDown,
		Printer,
		Camera,
		AlertTriangle,
		Image,
		Info
	} from 'lucide-svelte';
	import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
	import jsPDF from 'jspdf';
	import logoGovPE from '$lib/assets/logo_governo_PE.png';
	import { formatarDataHoraCompleta } from '$lib/utils/ponto';

	const client = useConvexClient();

	// Chave de refresh para forçar atualização das queries após registro
	let refreshKey = $state(0);

	// Queries
	const currentUser = useQuery(api.auth.getCurrentUser, {});
	const configQuery = useQuery(api.configuracaoPonto.obterConfiguracao, {});

	// Query para histórico e saldo do dia
	const funcionarioId = $derived(currentUser?.data?.funcionarioId ?? null);
	const dataHoje = $derived(new Date().toISOString().split('T')[0]!);

	// Usar refreshKey para forçar atualização após registro
	const registrosHojeQuery = useQuery(api.pontos.listarRegistrosDia, {
		data: dataHoje,
		_refresh: refreshKey
	});

	const historicoSaldoQuery = useQuery(
		api.pontos.obterHistoricoESaldoDia,
		funcionarioId && dataHoje ? { funcionarioId, data: dataHoje, _refresh: refreshKey } : 'skip'
	);

	// Query para verificar dispensa ativa
	const dispensaQuery = useQuery(
		api.pontos.verificarDispensaAtiva,
		funcionarioId && dataHoje ? { funcionarioId, data: dataHoje } : 'skip'
	);

	// Estados
	let mostrandoWebcam = $state(false);
	let registrando = $state(false);
	let sucesso = $state<string | null>(null);
	let registroId = $state<Id<'registrosPonto'> | null>(null);
	let mostrandoComprovante = $state(false);
	let imagemCapturada = $state<Blob | null>(null);
	let coletandoInfo = $state(false);
	let capturandoAutomaticamente = $state(false);
	let mostrarModalErro = $state(false);
	let mensagemErroModal = $state('');
	let detalhesErroModal = $state('');
	let justificativa = $state('');
	let mostrandoModalConfirmacao = $state(false);
	let mostrandoTransicao = $state(false); // Novo estado para transição
	let dataHoraAtual = $state<{ data: string; hora: string } | null>(null);
	let aguardandoProcessamento = $state(false);
	let etapaProcessamento = $state<'coletando' | 'sincronizando' | 'upload' | 'registrando' | null>(
		null
	);

	const registrosHoje = $derived(registrosHojeQuery?.data || []);
	const config = $derived(configQuery?.data);

	const proximoTipo = $derived.by(() => {
		if (registrosHoje.length === 0) {
			return 'entrada';
		}
		const ultimoRegistro = registrosHoje[registrosHoje.length - 1];
		return getProximoTipoRegistro(ultimoRegistro?.tipo || null);
	});

	const tipoLabel = $derived.by(() => {
		if (config) {
			return getTipoRegistroLabel(proximoTipo, {
				nomeEntrada: config.nomeEntrada,
				nomeSaidaAlmoco: config.nomeSaidaAlmoco,
				nomeRetornoAlmoco: config.nomeRetornoAlmoco,
				nomeSaida: config.nomeSaida
			});
		}
		return getTipoRegistroLabel(proximoTipo);
	});

	async function uploadImagem(blob: Blob): Promise<Id<'_storage'> | undefined> {
		try {
			// Obter URL de upload
			const uploadUrl = await client.mutation(api.pontos.generateUploadUrl, {});

			// Criar File a partir do Blob
			const file = new File([blob], 'ponto.jpg', { type: 'image/jpeg' });

			// Fazer upload
			const response = await fetch(uploadUrl, {
				method: 'POST',
				headers: { 'Content-Type': file.type },
				body: file
			});

			if (!response.ok) {
				throw new Error('Falha no upload da imagem');
			}

			// A resposta do Convex storage retorna JSON com storageId
			const { storageId } = (await response.json()) as { storageId: string };
			return storageId as Id<'_storage'>;
		} catch (error) {
			console.error('Erro ao fazer upload da imagem:', error);
			return undefined;
		}
	}

	// Verificar permissões de localização e webcam
	async function verificarPermissoes(): Promise<{
		localizacao: boolean;
		webcam: boolean;
		permissoesNecessarias: string[];
	}> {
		let localizacaoAutorizada = false;
		let webcamAutorizada = false;
		const permissoesNecessarias: string[] = [];

		// Verificar permissão de geolocalização
		if (navigator.geolocation) {
			try {
				await new Promise<void>((resolve, reject) => {
					const timeoutId = setTimeout(() => {
						reject(new Error('Timeout'));
					}, 5000);

					navigator.geolocation.getCurrentPosition(
						() => {
							clearTimeout(timeoutId);
							localizacaoAutorizada = true;
							resolve();
						},
						(error) => {
							clearTimeout(timeoutId);
							if (error.code === error.PERMISSION_DENIED) {
								permissoesNecessarias.push('localização');
							}
							reject(new Error('Permissão de localização negada'));
						},
						{ timeout: 5000, maximumAge: 0, enableHighAccuracy: false }
					);
				});
			} catch (error) {
				console.warn('Permissão de localização não concedida:', error);
			}
		}

		// Verificar permissão de webcam
		if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
			try {
				const stream = await navigator.mediaDevices.getUserMedia({ video: true });
				webcamAutorizada = true;
				// Parar o stream imediatamente, apenas verificamos a permissão
				stream.getTracks().forEach((track) => track.stop());
			} catch (error) {
				console.warn('Permissão de webcam não concedida:', error);
				permissoesNecessarias.push('câmera');
			}
		}

		return { localizacao: localizacaoAutorizada, webcam: webcamAutorizada, permissoesNecessarias };
	}

	async function registrarPonto() {
		if (registrando) return;

		// Verificar se tem funcionário associado
		if (!temFuncionarioAssociado) {
			mensagemErroModal = 'Usuário não possui funcionário associado';
			detalhesErroModal =
				'Você não possui um funcionário associado à sua conta. Entre em contato com o administrador do sistema.';
			mostrarModalErro = true;
			return;
		}

		// Verificar se está dispensado antes de registrar
		if (estaDispensado) {
			mensagemErroModal = 'Registro dispensado pelo gestor';
			detalhesErroModal = motivoDispensa || 'Você está dispensado de registrar ponto no momento.';
			mostrarModalErro = true;
			return;
		}

		// Verificar permissões antes de registrar
		const permissoes = await verificarPermissoes();
		if (!permissoes.localizacao || !permissoes.webcam) {
			mensagemErroModal = 'Permissões necessárias';
			const permissoesLista = permissoes.permissoesNecessarias.join(', ');
			detalhesErroModal = `Para registrar o ponto, é necessário autorizar o compartilhamento de localização e a captura de foto.\n\nPermissões negadas: ${permissoesLista || 'localização e/ou câmera'}`;
			mostrarModalErro = true;
			return;
		}

		registrando = true;
		sucesso = null;
		coletandoInfo = true;
		aguardandoProcessamento = true;
		etapaProcessamento = 'coletando';

		try {
			// Coletar informações do dispositivo
			etapaProcessamento = 'coletando';
			const informacoesDispositivo = await obterInformacoesDispositivo();
			// Nota: A permissão de sensor não é impeditiva - apenas câmera e localização são obrigatórias

			coletandoInfo = false;

			// Obter tempo sincronizado e aplicar GMT offset (igual ao relógio)
			etapaProcessamento = 'sincronizando';
			const configRelogio = await client.query(api.configuracaoRelogio.obterConfiguracao, {});
			// Usar gmtOffset da configuração, sem valor padrão, pois 0 é um valor válido
			const gmtOffset = configRelogio.gmtOffset ?? 0;

			let timestampBase: number;

			if (configRelogio.usarServidorExterno) {
				try {
					const resultado = await client.action(api.configuracaoRelogio.sincronizarTempo, {});
					if (resultado.sucesso && resultado.timestamp) {
						timestampBase = resultado.timestamp;
					} else {
						timestampBase = await obterTempoServidor(client);
					}
				} catch (error) {
					console.warn('Erro ao sincronizar com servidor externo:', error);
					if (configRelogio.fallbackParaPC) {
						timestampBase = Date.now();
					} else {
						timestampBase = await obterTempoServidor(client);
					}
				}
			} else {
				// Usar relógio do PC (sem sincronização com servidor)
				timestampBase = Date.now();
			}

			// Aplicar GMT offset ao timestamp
			// Quando GMT é 0, compensar o timezone local do navegador para que o timestamp
			// represente o horário local (não UTC), evitando que apareça 3 horas a mais
			let timestamp: number;
			if (gmtOffset !== 0) {
				// Aplicar offset configurado
				timestamp = timestampBase + gmtOffset * 60 * 60 * 1000;
			} else {
				// Quando GMT = 0, ajustar para horário local do navegador
				// getTimezoneOffset() retorna minutos POSITIVOS para fusos ATRÁS de UTC
				// Exemplo: Brasil (UTC-3) retorna 180 minutos
				// Subtrair esses minutos para que o timestamp represente o horário local
				const timezoneOffset = new Date().getTimezoneOffset(); // Offset em minutos
				timestamp = timestampBase - timezoneOffset * 60 * 1000; // Subtrair minutos em milissegundos
			}
			// Sincronizado apenas se usar servidor externo e sincronização foi bem-sucedida
			const sincronizadoComServidor =
				configRelogio.usarServidorExterno && timestampBase !== Date.now();

			// Upload da imagem (obrigatória agora)
			let imagemId: Id<'_storage'> | undefined = undefined;
			if (imagemCapturada) {
				try {
					etapaProcessamento = 'upload';
					imagemId = await uploadImagem(imagemCapturada);
				} catch (error) {
					console.error('Erro ao fazer upload da imagem:', error);
					throw new Error('Erro ao fazer upload da imagem. Tente novamente.');
				}
			} else {
				throw new Error('É necessário capturar uma foto para registrar o ponto.');
			}

			// Registrar ponto
			etapaProcessamento = 'registrando';
			const resultado = await client.mutation(api.pontos.registrarPonto, {
				imagemId,
				informacoesDispositivo,
				timestamp,
				sincronizadoComServidor,
				justificativa: justificativa.trim() || undefined
			});

			registroId = resultado.registroId;
			const tipoLabelSucesso = config
				? getTipoRegistroLabel(resultado.tipo, {
						nomeEntrada: config.nomeEntrada,
						nomeSaidaAlmoco: config.nomeSaidaAlmoco,
						nomeRetornoAlmoco: config.nomeRetornoAlmoco,
						nomeSaida: config.nomeSaida
					})
				: getTipoRegistroLabel(resultado.tipo);
			sucesso = `Ponto registrado com sucesso! Tipo: ${tipoLabelSucesso}`;
			imagemCapturada = null;
			justificativa = ''; // Limpar justificativa após registro
			mostrandoModalConfirmacao = false;

			// Forçar atualização das queries para mostrar o novo registro
			refreshKey++;

			if (import.meta.env.DEV) {
				console.log('[RegistroPonto] Registro bem-sucedido, refreshKey incrementado:', refreshKey);
			}

			// Aguardar um pouco para garantir que o backend processou o registro
			await new Promise((resolve) => setTimeout(resolve, 500));

			// Forçar mais uma atualização após o delay para garantir sincronização
			refreshKey++;

			// Mostrar comprovante após 1 segundo
			setTimeout(() => {
				mostrandoComprovante = true;
			}, 1000);
		} catch (error) {
			console.error('Erro ao registrar ponto:', error);
			aguardandoProcessamento = false;
			etapaProcessamento = null;
			let mensagemErro = 'Erro desconhecido ao registrar ponto';
			let detalhesErro = 'Tente novamente em alguns instantes.';

			if (error instanceof Error) {
				const erroMessage = error.message || '';

				// Erro de registro duplicado
				if (
					erroMessage.includes('Já existe um registro neste minuto') ||
					erroMessage.includes('já existe um registro')
				) {
					mensagemErro = 'Registro de ponto duplicado';
					const tipoLabelErro = config
						? getTipoRegistroLabel(proximoTipo, {
								nomeEntrada: config.nomeEntrada,
								nomeSaidaAlmoco: config.nomeSaidaAlmoco,
								nomeRetornoAlmoco: config.nomeRetornoAlmoco,
								nomeSaida: config.nomeSaida
							})
						: getTipoRegistroLabel(proximoTipo);
					detalhesErro = `Não é possível registrar o ponto no mesmo minuto.\n\nVocê já possui um registro de ${tipoLabelErro} para este minuto.\n\nPor favor, aguarde pelo menos 1 minuto antes de tentar registrar novamente.`;
				}
				// Erro de validação de argumentos
				else if (
					erroMessage.includes('ArgumentValidationError') ||
					erroMessage.includes('Object contains extra field') ||
					erroMessage.includes('validation')
				) {
					mensagemErro = 'Erro na validação dos dados';
					detalhesErro =
						'Ocorreu um erro ao validar as informações do dispositivo.\n\nPor favor, tente novamente ou recarregue a página.';
				}
				// Erro de autenticação
				else if (
					erroMessage.includes('não autenticado') ||
					erroMessage.includes('autenticado') ||
					erroMessage.includes('auth')
				) {
					mensagemErro = 'Erro de autenticação';
					detalhesErro = 'Sua sessão pode ter expirado. Por favor, faça login novamente.';
				}
				// Erro de permissão/validação de localização
				else if (
					erroMessage.includes('localização') ||
					erroMessage.includes('Localização') ||
					erroMessage.includes('location')
				) {
					mensagemErro = 'Erro na validação de localização';
					detalhesErro =
						'Não foi possível validar sua localização.\n\nPor favor, verifique se você autorizou o compartilhamento de localização e tente novamente.';
				}
				// Erro genérico do servidor
				else if (erroMessage.includes('Server Error') || erroMessage.includes('Server')) {
					mensagemErro = 'Erro no servidor';
					detalhesErro =
						'Ocorreu um erro no servidor ao processar seu registro.\n\nPor favor, tente novamente em alguns instantes.';
				}
				// Outros erros - mostrar mensagem simplificada
				else {
					mensagemErro = 'Erro ao registrar ponto';
					// Se a mensagem de erro for muito técnica, mostrar mensagem genérica
					if (
						erroMessage.includes('Error:') ||
						erroMessage.includes('TypeError') ||
						erroMessage.includes('ReferenceError') ||
						erroMessage.length > 200
					) {
						detalhesErro =
							'Ocorreu um erro ao processar o registro.\n\nPor favor, tente novamente ou recarregue a página.';
					} else {
						detalhesErro = erroMessage;
					}
				}
			}

			mensagemErroModal = mensagemErro;
			detalhesErroModal = detalhesErro;
			mostrarModalErro = true;
		} finally {
			registrando = false;
			coletandoInfo = false;
			aguardandoProcessamento = false;
			etapaProcessamento = null;
		}
	}

	async function handleWebcamCapture(blob: Blob | null) {
		if (blob) {
			imagemCapturada = blob;
		}
		mostrandoWebcam = false;

		// Se capturou a foto, mostrar modal de confirmação
		if (blob && capturandoAutomaticamente) {
			capturandoAutomaticamente = false;
			// Obter data e hora sincronizada do servidor com GMT offset (igual ao relógio)
			try {
				const configRelogio = await client.query(api.configuracaoRelogio.obterConfiguracao, {});
				// Usar gmtOffset da configuração, sem valor padrão, pois 0 é um valor válido
				const gmtOffset = configRelogio.gmtOffset ?? 0;

				let timestampBase: number;

				if (configRelogio.usarServidorExterno) {
					try {
						const resultado = await client.action(api.configuracaoRelogio.sincronizarTempo, {});
						if (resultado.sucesso && resultado.timestamp) {
							timestampBase = resultado.timestamp;
						} else {
							timestampBase = await obterTempoServidor(client);
						}
					} catch (error) {
						console.warn('Erro ao sincronizar com servidor externo:', error);
						if (configRelogio.fallbackParaPC) {
							timestampBase = Date.now();
						} else {
							timestampBase = await obterTempoServidor(client);
						}
					}
				} else {
					// Usar relógio do PC (sem sincronização com servidor)
					timestampBase = Date.now();
				}

				// Aplicar GMT offset ao timestamp
				// Quando GMT é 0, usar timestamp UTC puro e deixar toLocaleTimeString() fazer a conversão automática
				// Quando GMT ≠ 0, aplicar offset configurado ao timestamp
				let timestamp: number;
				if (gmtOffset !== 0) {
					// Aplicar offset configurado
					timestamp = timestampBase + gmtOffset * 60 * 60 * 1000;
				} else {
					// Quando GMT = 0, manter timestamp UTC puro
					// O toLocaleTimeString() converterá automaticamente para o timezone local do navegador
					timestamp = timestampBase;
				}
				const dataObj = new Date(timestamp);
				const data = dataObj.toLocaleDateString('pt-BR');
				const hora = dataObj.toLocaleTimeString('pt-BR', {
					hour: '2-digit',
					minute: '2-digit',
					second: '2-digit'
				});
				dataHoraAtual = { data, hora };
			} catch (error) {
				console.warn('Erro ao obter tempo do servidor, usando tempo local:', error);
				atualizarDataHoraAtual();
			}

			// Mostrar transição antes da confirmação
			mostrandoTransicao = true;
			setTimeout(() => {
				mostrandoTransicao = false;
				mostrandoModalConfirmacao = true;
			}, 1500);
		}
	}

	function handleWebcamCancel() {
		mostrandoWebcam = false;
		capturandoAutomaticamente = false;
		imagemCapturada = null;
		mostrandoModalConfirmacao = false;
	}

	function handleWebcamError() {
		// Em caso de erro na captura, fechar tudo
		mostrandoWebcam = false;
		capturandoAutomaticamente = false;
		imagemCapturada = null;
		mostrandoModalConfirmacao = false;
		mensagemErroModal = 'Erro ao capturar foto';
		detalhesErroModal = 'Não foi possível acessar a webcam. Verifique as permissões do navegador.';
		mostrarModalErro = true;
	}

	function atualizarDataHoraAtual() {
		const agora = new Date();
		const data = agora.toLocaleDateString('pt-BR');
		const hora = agora.toLocaleTimeString('pt-BR', {
			hour: '2-digit',
			minute: '2-digit',
			second: '2-digit'
		});
		dataHoraAtual = { data, hora };
	}

	async function iniciarRegistroComFoto() {
		if (registrando || coletandoInfo) return;

		// Verificar se tem funcionário associado
		if (!temFuncionarioAssociado) {
			mensagemErroModal = 'Usuário não possui funcionário associado';
			detalhesErroModal =
				'Você não possui um funcionário associado à sua conta. Entre em contato com o administrador do sistema.';
			mostrarModalErro = true;
			return;
		}

		// Verificar se está dispensado antes de abrir webcam
		if (estaDispensado) {
			mensagemErroModal = 'Registro dispensado pelo gestor';
			detalhesErroModal = motivoDispensa || 'Você está dispensado de registrar ponto no momento.';
			mostrarModalErro = true;
			return;
		}

		// Verificar permissões antes de abrir webcam
		const permissoes = await verificarPermissoes();
		if (!permissoes.localizacao || !permissoes.webcam) {
			mensagemErroModal = 'Permissões necessárias';
			detalhesErroModal =
				'Para registrar o ponto, é necessário autorizar o compartilhamento de localização e a captura de foto.';
			mostrarModalErro = true;
			return;
		}

		// Abrir webcam
		capturandoAutomaticamente = true;
		mostrandoWebcam = true;
	}

	function confirmarRegistro() {
		mostrandoModalConfirmacao = false;
		mostrandoTransicao = true; // Mostrar transição antes do processamento

		setTimeout(() => {
			mostrandoTransicao = false;
			aguardandoProcessamento = true;
			etapaProcessamento = 'coletando';
			// Usar setTimeout para garantir que o modal de processamento apareça antes de iniciar o registro
			setTimeout(() => {
				registrarPonto();
			}, 100);
		}, 1500);
	}

	function cancelarRegistro() {
		mostrandoModalConfirmacao = false;
		imagemCapturada = null;
	}

	function fecharComprovante() {
		mostrandoComprovante = false;
		registroId = null;
	}

	function fecharModalErro() {
		mostrarModalErro = false;
		mensagemErroModal = '';
		detalhesErroModal = '';
	}

	async function imprimirComprovante(registroId: Id<'registrosPonto'>) {
		try {
			// Buscar dados completos do registro
			const registro = await client.query(api.pontos.obterRegistro, { registroId });

			if (!registro) {
				alert('Registro não encontrado');
				return;
			}

			// Buscar configuração para usar nomes personalizados
			const configComprovante = await client.query(api.configuracaoPonto.obterConfiguracao, {});

			const doc = new jsPDF();

			// Logo
			let yPosition = 20;
			try {
				const logoImg = new Image();
				logoImg.src = logoGovPE;
				await new Promise<void>((resolve, reject) => {
					logoImg.onload = () => resolve();
					logoImg.onerror = () => reject();
					setTimeout(() => reject(), 3000);
				});

				const logoWidth = 25;
				const aspectRatio = logoImg.height / logoImg.width;
				const logoHeight = logoWidth * aspectRatio;

				doc.addImage(logoImg, 'PNG', 15, 10, logoWidth, logoHeight);
				yPosition = Math.max(20, 10 + logoHeight / 2);
			} catch (err) {
				console.warn('Não foi possível carregar a logo:', err);
			}

			// Cabeçalho
			doc.setFontSize(16);
			doc.setTextColor(41, 128, 185);
			doc.text('COMPROVANTE DE REGISTRO DE PONTO', 105, yPosition, { align: 'center' });

			yPosition += 15;

			// Informações do Funcionário
			doc.setFontSize(12);
			doc.setTextColor(0, 0, 0);
			doc.setFont('helvetica', 'bold');
			doc.text('DADOS DO FUNCIONÁRIO', 15, yPosition);
			doc.setFont('helvetica', 'normal');

			yPosition += 8;
			doc.setFontSize(10);

			if (registro.funcionario) {
				if (registro.funcionario.matricula) {
					doc.text(`Matrícula: ${registro.funcionario.matricula}`, 15, yPosition);
					yPosition += 6;
				}
				doc.text(`Nome: ${registro.funcionario.nome}`, 15, yPosition);
				yPosition += 6;
				if (registro.funcionario.descricaoCargo) {
					doc.text(`Cargo/Função: ${registro.funcionario.descricaoCargo}`, 15, yPosition);
					yPosition += 6;
				}
			}

			yPosition += 5;

			// Informações do Registro
			doc.setFont('helvetica', 'bold');
			doc.text('DADOS DO REGISTRO', 15, yPosition);
			doc.setFont('helvetica', 'normal');

			yPosition += 8;
			doc.setFontSize(10);

			const tipoLabelComprovante = configComprovante
				? getTipoRegistroLabel(registro.tipo, {
						nomeEntrada: configComprovante.nomeEntrada,
						nomeSaidaAlmoco: configComprovante.nomeSaidaAlmoco,
						nomeRetornoAlmoco: configComprovante.nomeRetornoAlmoco,
						nomeSaida: configComprovante.nomeSaida
					})
				: getTipoRegistroLabel(registro.tipo);
			doc.text(`Tipo: ${tipoLabelComprovante}`, 15, yPosition);
			yPosition += 6;

			const dataHora = formatarDataHoraCompleta(
				registro.data,
				registro.hora,
				registro.minuto,
				registro.segundo
			);
			doc.text(`Data e Hora: ${dataHora}`, 15, yPosition);
			yPosition += 6;

			doc.text(
				`Status: ${registro.dentroDoPrazo ? 'Dentro do Prazo' : 'Fora do Prazo'}`,
				15,
				yPosition
			);
			yPosition += 6;

			doc.text(`Tolerância: ${registro.toleranciaMinutos} minutos`, 15, yPosition);
			yPosition += 6;

			doc.text(
				`Sincronizado: ${registro.sincronizadoComServidor ? 'Sim (Servidor)' : 'Não (PC Local)'}`,
				15,
				yPosition
			);
			yPosition += 10;

			// Imagem capturada (se disponível)
			if (registro.imagemUrl) {
				// Verificar se precisa de nova página
				if (yPosition > 200) {
					doc.addPage();
					yPosition = 20;
				}

				doc.setFont('helvetica', 'bold');
				doc.text('FOTO CAPTURADA', 105, yPosition, { align: 'center' });
				doc.setFont('helvetica', 'normal');
				yPosition += 10;

				try {
					// Carregar imagem usando fetch para evitar problemas de CORS
					const response = await fetch(registro.imagemUrl);
					if (!response.ok) {
						throw new Error('Erro ao carregar imagem');
					}

					const blob = await response.blob();
					const reader = new FileReader();

					// Converter blob para base64
					const base64 = await new Promise<string>((resolve, reject) => {
						reader.onloadend = () => {
							if (typeof reader.result === 'string') {
								resolve(reader.result);
							} else {
								reject(new Error('Erro ao converter imagem'));
							}
						};
						reader.onerror = () => reject(new Error('Erro ao ler imagem'));
						reader.readAsDataURL(blob);
					});

					// Criar elemento de imagem para obter dimensões
					const img = new Image();
					await new Promise<void>((resolve, reject) => {
						img.onload = () => resolve();
						img.onerror = () => reject(new Error('Erro ao processar imagem'));
						img.src = base64;
						setTimeout(() => reject(new Error('Timeout ao processar imagem')), 10000);
					});

					// Calcular dimensões para caber na página (largura máxima 80mm, manter proporção)
					const maxWidth = 80;
					const maxHeight = 60;
					let imgWidth = img.width;
					let imgHeight = img.height;
					const aspectRatio = imgWidth / imgHeight;

					if (imgWidth > maxWidth || imgHeight > maxHeight) {
						if (aspectRatio > 1) {
							// Imagem horizontal
							imgWidth = maxWidth;
							imgHeight = maxWidth / aspectRatio;
						} else {
							// Imagem vertical
							imgHeight = maxHeight;
							imgWidth = maxHeight * aspectRatio;
						}
					}

					// Centralizar imagem
					const xPosition = (doc.internal.pageSize.getWidth() - imgWidth) / 2;

					// Verificar se cabe na página atual
					if (yPosition + imgHeight > doc.internal.pageSize.getHeight() - 20) {
						doc.addPage();
						yPosition = 20;
					}

					// Adicionar imagem ao PDF usando base64
					doc.addImage(base64, 'JPEG', xPosition, yPosition, imgWidth, imgHeight);
					yPosition += imgHeight + 10;
				} catch (error) {
					console.warn('Erro ao adicionar imagem ao PDF:', error);
					doc.setFontSize(10);
					doc.text('Foto não disponível para impressão', 105, yPosition, { align: 'center' });
					yPosition += 6;
				}
			}

			// Rodapé
			const pageCount = doc.getNumberOfPages();
			for (let i = 1; i <= pageCount; i++) {
				doc.setPage(i);
				doc.setFontSize(8);
				doc.setTextColor(128, 128, 128);
				doc.text(
					`SGSE - Sistema de Gerenciamento de Secretaria | Página ${i} de ${pageCount}`,
					doc.internal.pageSize.getWidth() / 2,
					doc.internal.pageSize.getHeight() - 10,
					{ align: 'center' }
				);
			}

			// Salvar
			const nomeArquivo = `comprovante-ponto-${registro.data}-${registro.hora.toString().padStart(2, '0')}${registro.minuto.toString().padStart(2, '0')}.pdf`;
			doc.save(nomeArquivo);
		} catch (error) {
			console.error('Erro ao gerar comprovante PDF:', error);
			alert('Erro ao gerar comprovante PDF. Tente novamente.');
		}
	}

	const dispensaAtiva = $derived(dispensaQuery?.data);
	const estaDispensado = $derived(dispensaAtiva?.dispensado ?? false);
	const motivoDispensa = $derived(dispensaAtiva?.motivo ?? null);
	const temFuncionarioAssociado = $derived(funcionarioId !== null);

	const podeRegistrar = $derived.by(() => {
		return (
			!registrando &&
			!coletandoInfo &&
			config !== undefined &&
			!estaDispensado &&
			temFuncionarioAssociado
		);
	});

	// Os modais agora são centralizados automaticamente via CSS (fixed inset-0 flex items-center justify-center)

	// Solicitar permissões automaticamente ao montar o componente
	onMount(async () => {
		// Solicitar permissão de webcam
		if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
			try {
				// Solicitar apenas permissão, sem iniciar o stream ainda
				await navigator.mediaDevices.getUserMedia({ video: true });
			} catch (error) {
				// Ignorar erro silenciosamente - a permissão será solicitada quando necessário
				console.log('Permissão de webcam não concedida ainda');
			}
		}

		// Solicitar permissão de geolocalização
		if (navigator.geolocation) {
			try {
				// Solicitar permissão de geolocalização (timeout curto para não bloquear)
				await new Promise<void>((resolve) => {
					const timeoutId = setTimeout(() => resolve(), 2000); // Timeout de 2 segundos
					navigator.geolocation.getCurrentPosition(
						() => {
							clearTimeout(timeoutId);
							resolve();
						},
						() => {
							clearTimeout(timeoutId);
							resolve(); // Resolver mesmo se negado
						},
						{ timeout: 2000, maximumAge: 0, enableHighAccuracy: false } // enableHighAccuracy false para ser mais rápido
					);
				});
			} catch (error) {
				// Ignorar erro silenciosamente
				console.log('Permissão de geolocalização não concedida ainda');
			}
		}
	});

	const mapaHorarios = $derived.by(() => {
		if (!config) return [];

		const horarios = [
			{ tipo: 'entrada', horario: config.horarioEntrada, label: config.nomeEntrada || 'Entrada 1' },
			{
				tipo: 'saida_almoco',
				horario: config.horarioSaidaAlmoco,
				label: config.nomeSaidaAlmoco || 'Saída 1'
			},
			{
				tipo: 'retorno_almoco',
				horario: config.horarioRetornoAlmoco,
				label: config.nomeRetornoAlmoco || 'Entrada 2'
			},
			{ tipo: 'saida', horario: config.horarioSaida, label: config.nomeSaida || 'Saída 2' }
		];

		const resultado = horarios.map((h) => {
			const registro = registrosHoje.find((r) => r.tipo === h.tipo);
			return {
				...h,
				registrado: !!registro,
				horarioRegistrado: registro ? formatarHoraPonto(registro.hora, registro.minuto) : null,
				dentroDoPrazo: registro?.dentroDoPrazo ?? null
			};
		});

		// Log para debug (apenas em desenvolvimento)
		if (import.meta.env.DEV) {
			console.log('[RegistroPonto] mapaHorarios atualizado:', {
				totalRegistrosHoje: registrosHoje.length,
				horariosComRegistro: resultado.filter((h) => h.registrado).length,
				registrosHoje: registrosHoje.map((r) => ({ tipo: r.tipo, hora: `${r.hora}:${r.minuto}` }))
			});
		}

		return resultado;
	});

	// Dados do histórico e saldo
	const historicoSaldo = $derived(historicoSaldoQuery?.data);
	const registrosOrdenados = $derived.by(() => {
		if (!historicoSaldo?.registros) return [];
		return [...historicoSaldo.registros].sort((a, b) => {
			const minutosA = a.hora * 60 + a.minuto;
			const minutosB = b.hora * 60 + b.minuto;
			return minutosA - minutosB;
		});
	});

	// Formatação do saldo
	const saldoFormatado = $derived.by(() => {
		if (!historicoSaldo) return null;
		const minutos = historicoSaldo.saldoMinutos;
		const horas = Math.floor(Math.abs(minutos) / 60);
		const mins = Math.abs(minutos) % 60;
		const sinal = minutos >= 0 ? '+' : '-';
		return `${sinal}${horas}h ${mins}min`;
	});

	const saldoPositivo = $derived(historicoSaldo ? historicoSaldo.saldoMinutos >= 0 : false);

	// Posicionamento dos modais baseado no texto "Registrar Ponto"
	let modalPosition = $state<{ top: number; left: number } | null>(null);

	// Função para calcular a posição do modal baseada no card de registro de ponto
	function calcularPosicaoModal() {
		const cardRef = document.getElementById('card-registro-ponto-ref');

		if (cardRef) {
			const rect = cardRef.getBoundingClientRect();
			const viewportHeight = window.innerHeight;

			// Posicionar o modal na mesma altura Y do card (top do card)
			// getBoundingClientRect() já retorna posição relativa à viewport quando usado com position: fixed
			const top = rect.top;

			// Garantir que o modal não saia da viewport
			// Considerar uma altura mínima do modal (aproximadamente 300px)
			const minTop = 20;
			const maxTop = viewportHeight - 350; // Deixar espaço para o modal
			const finalTop = Math.max(minTop, Math.min(top, maxTop));

			return {
				top: finalTop,
				left: window.innerWidth / 2
			};
		}

		// Se não encontrar, usar posição padrão (centro da tela)
		return null;
	}

	// Atualizar posição quando os modais forem abertos
	$effect(() => {
		if (
			mostrandoWebcam ||
			mostrandoTransicao ||
			aguardandoProcessamento ||
			mostrandoModalConfirmacao
		) {
			// Usar requestAnimationFrame para garantir que o DOM está completamente renderizado
			const updatePosition = () => {
				requestAnimationFrame(() => {
					const pos = calcularPosicaoModal();
					if (pos) {
						modalPosition = pos;
					} else {
						// Fallback para centralização
						modalPosition = {
							top: window.innerHeight / 2,
							left: window.innerWidth / 2
						};
					}
				});
			};

			// Aguardar um pouco para garantir que o DOM está atualizado
			setTimeout(updatePosition, 50);

			// Adicionar listener de scroll para atualizar posição
			const handleScroll = () => {
				updatePosition();
			};

			window.addEventListener('scroll', handleScroll, true);
			window.addEventListener('resize', handleScroll);

			return () => {
				window.removeEventListener('scroll', handleScroll, true);
				window.removeEventListener('resize', handleScroll);
			};
		} else {
			// Limpar posição quando o modal for fechado
			modalPosition = null;
		}
	});

	// Função para obter estilo do modal
	function getModalStyle() {
		if (modalPosition) {
			// Posicionar na altura do card, centralizado horizontalmente
			// position: fixed já é relativo à viewport, então podemos usar diretamente
			return `position: fixed; top: ${modalPosition.top}px; left: 50%; transform: translateX(-50%); width: 100%; max-width: 800px;`;
		}
		// Fallback para centralização padrão
		return 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 100%; max-width: 800px;';
	}
</script>

<div class="space-y-6">
	<!-- Alerta de Funcionário Não Associado -->
	{#if !temFuncionarioAssociado}
		<div class="alert alert-error shadow-lg">
			<XCircle class="h-6 w-6 shrink-0 stroke-current" />
			<div>
				<h3 class="font-bold">Funcionário Não Associado</h3>
				<div class="text-sm">
					Você não possui um funcionário associado à sua conta.
					<br />
					Entre em contato com o administrador do sistema para associar um funcionário à sua conta.
				</div>
			</div>
		</div>
	{/if}

	<!-- Alerta de Dispensa -->
	{#if estaDispensado && motivoDispensa && temFuncionarioAssociado}
		<div class="alert alert-warning shadow-lg">
			<AlertTriangle class="h-6 w-6 shrink-0 stroke-current" />
			<div>
				<h3 class="font-bold">Registro de Ponto Dispensado</h3>
				<div class="text-sm">
					Você está dispensado de registrar ponto no momento.
					<br />
					<strong>Motivo:</strong>
					{motivoDispensa}
				</div>
			</div>
		</div>
	{/if}

	<!-- Card de Registro de Ponto Modernizado -->
	<div
		class="card from-base-100 via-base-100 to-primary/5 border-base-300 mx-auto max-w-2xl border bg-gradient-to-br shadow-2xl"
	>
		<div id="card-registro-ponto-ref" class="card-body p-6">
			<!-- Cabeçalho -->
			<div class="mb-6 flex items-center justify-center gap-3">
				<div class="bg-primary/10 rounded-xl p-2.5">
					<Clock class="text-primary h-6 w-6" strokeWidth={2.5} />
				</div>
				<h2 class="card-title text-base-content text-2xl font-black">Registrar Ponto</h2>
			</div>

			<!-- Relógio Sincronizado -->
			<div class="mb-5 flex justify-center">
				<div
					id="relogio-sincronizado-ref"
					class="card from-primary/10 to-primary/5 border-primary/20 w-full max-w-sm rounded-2xl border-2 bg-gradient-to-br p-5 shadow-lg"
				>
					<RelogioSincronizado />
				</div>
			</div>

			<!-- Botão de Registro -->
			<button
				class="btn btn-primary mb-5 w-full gap-2 rounded-xl font-semibold shadow-lg transition-all duration-300 hover:shadow-xl"
				onclick={iniciarRegistroComFoto}
				disabled={!podeRegistrar}
				title={!temFuncionarioAssociado
					? 'Você não possui funcionário associado à sua conta'
					: estaDispensado
						? 'Você está dispensado de registrar ponto no momento'
						: ''}
			>
				{#if registrando}
					<span class="loading loading-spinner loading-sm"></span>
					{#if coletandoInfo}
						Coletando informações...
					{:else}
						Registrando...
					{/if}
				{:else if !temFuncionarioAssociado}
					<XCircle class="h-5 w-5" />
					Funcionário Não Associado
				{:else if estaDispensado}
					<XCircle class="h-5 w-5" />
					Registro Indisponível
				{:else if proximoTipo === 'entrada' || proximoTipo === 'retorno_almoco'}
					<LogIn class="h-5 w-5" />
					Registrar Entrada
				{:else}
					<LogOut class="h-5 w-5" />
					Registrar Saída
				{/if}
			</button>

			<!-- Campo de Justificativa -->
			<div class="mb-5">
				<label for="justificativa" class="label pb-1.5">
					<span class="label-text text-xs font-semibold"
						>Justificativa <span class="text-base-content/50 font-normal">(Opcional)</span></span
					>
				</label>
				<textarea
					id="justificativa"
					class="textarea textarea-bordered focus:textarea-primary focus:ring-primary/20 w-full resize-none rounded-xl text-sm focus:ring-2"
					placeholder="Digite uma justificativa para este registro de ponto (opcional)"
					bind:value={justificativa}
					disabled={registrando}
					rows="2"
				></textarea>
			</div>

			<!-- Mensagem de Sucesso -->
			{#if sucesso}
				<div class="alert alert-success mb-5 rounded-xl shadow-lg">
					<CheckCircle2 class="h-4 w-4" />
					<span class="text-sm font-semibold">{sucesso}</span>
				</div>
			{/if}

			<!-- Próximo Registro -->
			<div
				class="card from-info/10 to-info/5 border-info/20 rounded-xl border-2 bg-gradient-to-br p-4 shadow-md"
			>
				<div class="flex items-center justify-center gap-2">
					<div class="bg-info/20 rounded-lg p-1.5">
						{#if proximoTipo === 'entrada' || proximoTipo === 'retorno_almoco'}
							<LogIn class="text-info h-4 w-4" strokeWidth={2.5} />
						{:else}
							<LogOut class="text-info h-4 w-4" strokeWidth={2.5} />
						{/if}
					</div>
					<div class="text-center">
						<p class="text-base-content/60 mb-0.5 text-xs font-semibold tracking-wide uppercase">
							Próximo Registro
						</p>
						<p class="text-base-content text-base font-bold">{tipoLabel}</p>
					</div>
				</div>
			</div>
		</div>
	</div>

	<!-- Mapa de Horários -->
	<div class="card bg-base-100 shadow-xl">
		<div class="card-body">
			<h2 class="card-title mb-6">
				<Clock class="h-5 w-5" />
				Horário Padrão
			</h2>

			<!-- Linha horizontal com espaçamento uniforme -->
			<div class="flex flex-wrap items-stretch justify-between gap-4 md:gap-6">
				{#each mapaHorarios as horario (horario.tipo)}
					<div class="mx-auto max-w-[220px] min-w-[140px] flex-1">
						<div
							class="relative h-full rounded-xl border-2 transition-all duration-300 hover:shadow-lg {horario.registrado
								? horario.dentroDoPrazo
									? 'from-success/20 to-success/10 border-success bg-gradient-to-br shadow-md'
									: 'from-error/20 to-error/10 border-error bg-gradient-to-br shadow-md'
								: 'from-base-200 to-base-300 border-base-300 bg-gradient-to-br'} p-5"
						>
							<!-- Status Icon -->
							<div class="absolute top-3 right-3">
								{#if horario.registrado}
									{#if horario.dentroDoPrazo}
										<CheckCircle2 class="text-success h-5 w-5" />
									{:else}
										<XCircle class="text-error h-5 w-5" />
									{/if}
								{:else}
									<Clock class="text-base-content/30 h-5 w-5" />
								{/if}
							</div>

							<!-- Label -->
							<div class="mb-3">
								<span class="text-base-content/80 text-sm font-semibold tracking-wide uppercase">
									{horario.label}
								</span>
							</div>

							<!-- Horário Padrão -->
							<div class="mb-2">
								<div class="text-primary font-mono text-3xl font-bold">
									{horario.horario}
								</div>
							</div>

							<!-- Horário Registrado (se houver) -->
							{#if horario.registrado}
								<div class="border-base-content/10 mt-3 border-t pt-3">
									<div class="flex items-center gap-2">
										<div class="text-base-content/60 text-xs font-medium">Registrado:</div>
										<div class="text-base-content text-sm font-bold">
											{horario.horarioRegistrado}
										</div>
									</div>
								</div>
							{:else}
								<div class="border-base-content/10 mt-3 border-t pt-3">
									<div class="text-base-content/40 text-xs italic">Aguardando registro</div>
								</div>
							{/if}
						</div>
					</div>
				{/each}
			</div>
		</div>
	</div>

	<!-- Histórico e Saldo do Dia -->
	{#if historicoSaldo && registrosOrdenados.length > 0}
		<div class="card bg-base-100 shadow-xl">
			<div class="card-body">
				<h2 class="card-title">
					<Clock class="h-5 w-5" />
					Histórico do Dia
				</h2>

				<!-- Saldo de Horas -->
				<div
					class="my-4 rounded-lg border-2 p-4 {saldoPositivo
						? 'border-success bg-success/10'
						: 'border-error bg-error/10'}"
				>
					<div class="flex items-center justify-between">
						<div>
							<p class="text-sm font-semibold opacity-70">Saldo de Horas</p>
							<p class="text-2xl font-bold">
								{saldoFormatado}
							</p>
						</div>
						{#if saldoPositivo}
							<TrendingUp class="text-success h-8 w-8" />
						{:else}
							<TrendingDown class="text-error h-8 w-8" />
						{/if}
					</div>
					<div class="mt-2 text-sm opacity-70">
						<p>
							Carga Horária Diária: {Math.floor(historicoSaldo.cargaHorariaDiaria / 60)}h {historicoSaldo.cargaHorariaDiaria %
								60}min
						</p>
						<p>
							Horas Trabalhadas: {Math.floor(historicoSaldo.horasTrabalhadas / 60)}h {historicoSaldo.horasTrabalhadas %
								60}min
						</p>
					</div>
				</div>

				<!-- Timeline de Registros -->
				<div class="divider"></div>
				<div class="space-y-4">
					<h3 class="font-semibold">Timeline do Dia</h3>

					<!-- Timeline Visual com horários padrão e registros reais -->
					<div class="relative">
						<!-- Linha vertical central da timeline -->
						<div
							class="from-primary/20 via-base-300 to-secondary/20 absolute top-0 bottom-0 left-1/2 w-1 -translate-x-1/2 transform bg-gradient-to-b"
						></div>

						<!-- Container com duas colunas -->
						<div class="relative grid grid-cols-2 gap-4">
							<!-- Coluna Entrada -->
							<div class="space-y-4 pr-2">
								<div class="bg-base-100 border-primary/20 sticky top-0 z-10 mb-2 border-b pb-3">
									<h4
										class="text-primary flex items-center justify-center gap-2 text-center text-lg font-bold"
									>
										<LogIn class="h-5 w-5" />
										Entradas
									</h4>
								</div>

								{#each registrosOrdenados.filter((r) => r.tipo === 'entrada' || r.tipo === 'retorno_almoco') as registro (registro._id)}
									<div class="relative">
										<!-- Linha horizontal conectando à timeline -->
										<div
											class="bg-base-300/50 absolute top-6 right-0 h-0.5 w-full"
											style="width: calc(100% - 0.5rem);"
										></div>

										<!-- Card do registro -->
										<div
											class="card {registro.dentroDoPrazo
												? 'bg-success/5 border-success/30'
												: 'bg-error/5 border-error/30'} border-2 shadow-md transition-all hover:shadow-lg"
										>
											<div class="card-body p-4">
												<!-- Tipo de registro e status -->
												<div class="mb-2 flex items-center gap-2">
													{#if registro.dentroDoPrazo}
														<CheckCircle2 class="text-success h-4 w-4 flex-shrink-0" />
													{:else}
														<XCircle class="text-error h-4 w-4 flex-shrink-0" />
													{/if}
													<span class="text-base-content/80 text-sm font-semibold">
														{config
															? getTipoRegistroLabel(registro.tipo, {
																	nomeEntrada: config.nomeEntrada,
																	nomeRetornoAlmoco: config.nomeRetornoAlmoco
																})
															: getTipoRegistroLabel(registro.tipo)}
													</span>
												</div>

												<!-- Horário registrado -->
												<p class="text-primary mb-1 text-3xl font-bold">
													{formatarHoraPonto(registro.hora, registro.minuto)}
												</p>

												<!-- Comparação com horário esperado -->
												{#if config}
													{@const horarioEsperado =
														registro.tipo === 'entrada'
															? config.horarioEntrada
															: config.horarioRetornoAlmoco}
													{@const [horaEsperada, minutoEsperado] = horarioEsperado
														.split(':')
														.map(Number)}
													{@const minutosEsperados = horaEsperada * 60 + minutoEsperado}
													{@const minutosRegistrados = registro.hora * 60 + registro.minuto}
													{@const diferenca = minutosRegistrados - minutosEsperados}
													{@const diferencaAbs = Math.abs(diferenca)}
													{@const diferencaTexto =
														diferencaAbs >= 60
															? `${Math.floor(diferencaAbs / 60)}h ${diferencaAbs % 60}min`
															: `${diferencaAbs}min`}

													<div class="mb-3 flex items-center gap-2 text-xs">
														<span class="text-base-content/50">Esperado:</span>
														<span class="font-semibold">{horarioEsperado}</span>
														{#if diferencaAbs > 0}
															<span
																class="badge badge-xs {diferenca > 0
																	? 'badge-warning'
																	: 'badge-info'}"
															>
																{diferenca > 0 ? '+' : '-'}{diferencaTexto}
															</span>
														{/if}
													</div>
												{/if}

												{#if registro.justificativa}
													<div class="bg-base-300/50 mt-2 mb-3 rounded-lg p-2 text-xs">
														<p class="mb-1 font-semibold opacity-70">Justificativa:</p>
														<p class="text-base-content/80">{registro.justificativa}</p>
													</div>
												{/if}

												<button
													class="btn btn-sm btn-outline btn-primary w-full gap-2"
													onclick={() => imprimirComprovante(registro._id)}
													title="Imprimir Comprovante"
												>
													<Printer class="h-4 w-4" />
													Imprimir Comprovante
												</button>
											</div>
										</div>
									</div>
								{/each}

								<!-- Mostrar horários esperados que não foram registrados -->
								{#if config}
									{#each [{ tipo: 'entrada', horario: config.horarioEntrada, label: config.nomeEntrada || 'Entrada 1' }, { tipo: 'retorno_almoco', horario: config.horarioRetornoAlmoco, label: config.nomeRetornoAlmoco || 'Entrada 2' }] as horarioEsperado}
										{#if !registrosOrdenados.find((r) => r.tipo === horarioEsperado.tipo)}
											<div class="relative opacity-50">
												<div
													class="bg-base-300/30 absolute top-6 right-0 h-0.5 w-full border-dashed"
													style="width: calc(100% - 0.5rem);"
												></div>
												<div class="card bg-base-200/50 border-base-300 border border-dashed">
													<div class="card-body p-3">
														<p class="text-base-content/50 mb-1 text-xs">
															{horarioEsperado.label} (não registrado)
														</p>
														<p class="text-base-content/40 text-xl font-bold">
															{horarioEsperado.horario}
														</p>
													</div>
												</div>
											</div>
										{/if}
									{/each}
								{/if}
							</div>

							<!-- Coluna Saída -->
							<div class="space-y-4 pl-2">
								<div class="bg-base-100 border-secondary/20 sticky top-0 z-10 mb-2 border-b pb-3">
									<h4
										class="text-secondary flex items-center justify-center gap-2 text-center text-lg font-bold"
									>
										<LogOut class="h-5 w-5" />
										Saídas
									</h4>
								</div>

								{#each registrosOrdenados.filter((r) => r.tipo === 'saida_almoco' || r.tipo === 'saida') as registro (registro._id)}
									<div class="relative">
										<!-- Linha horizontal conectando à timeline -->
										<div
											class="bg-base-300/50 absolute top-6 left-0 h-0.5 w-full"
											style="width: calc(100% - 0.5rem);"
										></div>

										<!-- Card do registro -->
										<div
											class="card {registro.dentroDoPrazo
												? 'bg-success/5 border-success/30'
												: 'bg-error/5 border-error/30'} border-2 shadow-md transition-all hover:shadow-lg"
										>
											<div class="card-body p-4">
												<!-- Tipo de registro e status -->
												<div class="mb-2 flex items-center justify-end gap-2">
													<span class="text-base-content/80 text-sm font-semibold">
														{config
															? getTipoRegistroLabel(registro.tipo, {
																	nomeSaidaAlmoco: config.nomeSaidaAlmoco,
																	nomeSaida: config.nomeSaida
																})
															: getTipoRegistroLabel(registro.tipo)}
													</span>
													{#if registro.dentroDoPrazo}
														<CheckCircle2 class="text-success h-4 w-4 flex-shrink-0" />
													{:else}
														<XCircle class="text-error h-4 w-4 flex-shrink-0" />
													{/if}
												</div>

												<!-- Horário registrado -->
												<p class="text-secondary mb-1 text-right text-3xl font-bold">
													{formatarHoraPonto(registro.hora, registro.minuto)}
												</p>

												<!-- Comparação com horário esperado -->
												{#if config}
													{@const horarioEsperado =
														registro.tipo === 'saida_almoco'
															? config.horarioSaidaAlmoco
															: config.horarioSaida}
													{@const [horaEsperada, minutoEsperado] = horarioEsperado
														.split(':')
														.map(Number)}
													{@const minutosEsperados = horaEsperada * 60 + minutoEsperado}
													{@const minutosRegistrados = registro.hora * 60 + registro.minuto}
													{@const diferenca = minutosRegistrados - minutosEsperados}
													{@const diferencaAbs = Math.abs(diferenca)}
													{@const diferencaTexto =
														diferencaAbs >= 60
															? `${Math.floor(diferencaAbs / 60)}h ${diferencaAbs % 60}min`
															: `${diferencaAbs}min`}

													<div class="mb-3 flex items-center justify-end gap-2 text-xs">
														{#if diferencaAbs > 0}
															<span
																class="badge badge-xs {diferenca > 0
																	? 'badge-warning'
																	: 'badge-info'}"
															>
																{diferenca > 0 ? '+' : '-'}{diferencaTexto}
															</span>
														{/if}
														<span class="font-semibold">{horarioEsperado}</span>
														<span class="text-base-content/50">Esperado:</span>
													</div>
												{/if}

												{#if registro.justificativa}
													<div class="bg-base-300/50 mt-2 mb-3 rounded-lg p-2 text-xs">
														<p class="mb-1 font-semibold opacity-70">Justificativa:</p>
														<p class="text-base-content/80">{registro.justificativa}</p>
													</div>
												{/if}

												<button
													class="btn btn-sm btn-outline btn-primary w-full gap-2"
													onclick={() => imprimirComprovante(registro._id)}
													title="Imprimir Comprovante"
												>
													<Printer class="h-4 w-4" />
													Imprimir Comprovante
												</button>
											</div>
										</div>
									</div>
								{/each}

								<!-- Mostrar horários esperados que não foram registrados -->
								{#if config}
									{#each [{ tipo: 'saida_almoco', horario: config.horarioSaidaAlmoco, label: config.nomeSaidaAlmoco || 'Saída 1' }, { tipo: 'saida', horario: config.horarioSaida, label: config.nomeSaida || 'Saída 2' }] as horarioEsperado}
										{#if !registrosOrdenados.find((r) => r.tipo === horarioEsperado.tipo)}
											<div class="relative opacity-50">
												<div
													class="bg-base-300/30 absolute top-6 left-0 h-0.5 w-full border-dashed"
													style="width: calc(100% - 0.5rem);"
												></div>
												<div class="card bg-base-200/50 border-base-300 border border-dashed">
													<div class="card-body p-3">
														<p class="text-base-content/50 mb-1 text-right text-xs">
															{horarioEsperado.label} (não registrado)
														</p>
														<p class="text-base-content/40 text-right text-xl font-bold">
															{horarioEsperado.horario}
														</p>
													</div>
												</div>
											</div>
										{/if}
									{/each}
								{/if}
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>
	{/if}

	<!-- Modal Webcam -->
	{#if mostrandoWebcam}
		<div
			class="pointer-events-none fixed inset-0 z-50"
			style="animation: fadeIn 0.2s ease-out;"
			role="dialog"
			aria-modal="true"
			aria-labelledby="modal-webcam-title"
		>
			<!-- Backdrop leve -->
			<div
				class="pointer-events-auto absolute inset-0 bg-black/20 transition-opacity duration-200"
				onclick={handleWebcamCancel}
			></div>

			<!-- Modal Box -->
			<div
				class="bg-base-100 pointer-events-auto absolute z-10 flex max-h-[90vh] w-full max-w-2xl transform flex-col overflow-hidden rounded-2xl shadow-2xl transition-all duration-300"
				style="animation: slideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); {getModalStyle()}"
				onclick={(e) => e.stopPropagation()}
			>
				<!-- Header fixo -->
				<div
					class="border-base-300 flex flex-shrink-0 items-center justify-between border-b px-6 py-4"
				>
					<div class="flex items-center gap-3">
						<div class="bg-primary/10 rounded-lg p-2">
							<Camera class="text-primary h-5 w-5" strokeWidth={2} />
						</div>
						<h3 id="modal-webcam-title" class="text-base-content text-xl font-bold">
							Capturar Foto
						</h3>
					</div>
					<button
						class="btn btn-sm btn-circle btn-ghost hover:bg-base-300"
						onclick={handleWebcamCancel}
					>
						<XCircle class="h-5 w-5" />
					</button>
				</div>

				<!-- Conteúdo com rolagem -->
				<div class="modal-scroll flex-1 overflow-y-auto px-6 py-4">
					<div class="flex min-h-[200px] items-center justify-center">
						<WebcamCapture
							onCapture={handleWebcamCapture}
							onCancel={handleWebcamCancel}
							onError={handleWebcamError}
							autoCapture={false}
							fotoObrigatoria={true}
						/>
					</div>
				</div>
			</div>
		</div>
	{/if}

	<!-- Modal de Transição -->
	{#if mostrandoTransicao}
		<div
			class="pointer-events-none fixed inset-0 z-50"
			style="animation: fadeIn 0.2s ease-out;"
			role="dialog"
			aria-modal="true"
			aria-labelledby="modal-transicao-title"
		>
			<!-- Backdrop leve -->
			<div
				class="pointer-events-auto absolute inset-0 bg-black/20 transition-opacity duration-200"
			></div>

			<!-- Modal Box -->
			<div
				class="bg-base-100 pointer-events-auto absolute z-10 flex min-h-[300px] transform flex-col items-center justify-center rounded-2xl p-8 shadow-2xl transition-all duration-300"
				style="animation: slideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); {getModalStyle()}"
			>
				<div class="flex flex-col items-center gap-6 text-center">
					<div class="relative">
						<div class="bg-primary/20 absolute inset-0 animate-ping rounded-full"></div>
						<div class="bg-primary/10 relative rounded-full p-4">
							<Clock class="text-primary h-12 w-12 animate-pulse" strokeWidth={2} />
						</div>
					</div>

					<h3 id="modal-transicao-title" class="text-base-content text-2xl font-black">
						Registro de Ponto em Andamento
					</h3>

					<div class="flex gap-2">
						<span class="loading loading-dots loading-md text-primary"></span>
					</div>
				</div>
			</div>
		</div>
	{/if}

	<!-- Modal de Aguardando Processamento -->
	{#if aguardandoProcessamento}
		<div
			class="pointer-events-none fixed inset-0 z-50"
			style="animation: fadeIn 0.2s ease-out;"
			role="dialog"
			aria-modal="true"
			aria-labelledby="modal-aguardando-title"
		>
			<!-- Backdrop leve -->
			<div
				class="pointer-events-auto absolute inset-0 bg-black/20 transition-opacity duration-200"
			></div>

			<!-- Modal Box -->
			<div
				class="bg-base-100 pointer-events-auto absolute z-10 w-full max-w-md transform rounded-2xl p-8 shadow-2xl transition-all duration-300"
				style="animation: slideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); {getModalStyle()}"
			>
				<div class="flex flex-col items-center gap-4 text-center">
					<span class="loading loading-spinner loading-lg text-primary"></span>
					<h3 id="modal-aguardando-title" class="text-base-content text-xl font-bold">
						{#if etapaProcessamento === 'coletando'}
							Coletando Informações
						{:else if etapaProcessamento === 'sincronizando'}
							Sincronizando Horário
						{:else if etapaProcessamento === 'upload'}
							Enviando Foto
						{:else if etapaProcessamento === 'registrando'}
							Registrando Ponto
						{:else}
							Processando Registro
						{/if}
					</h3>
					<p class="text-base-content/70">
						{#if etapaProcessamento === 'coletando'}
							Coletando informações do dispositivo e localização...
						{:else if etapaProcessamento === 'sincronizando'}
							Sincronizando o horário com o servidor...
						{:else if etapaProcessamento === 'upload'}
							Enviando a foto capturada para o servidor...
						{:else if etapaProcessamento === 'registrando'}
							Finalizando o registro de ponto no sistema...
						{:else}
							Por favor, aguarde enquanto processamos seu registro de ponto...
						{/if}
					</p>
				</div>
			</div>
		</div>
	{/if}

	<!-- Modal de Confirmação -->
	{#if mostrandoModalConfirmacao && imagemCapturada && dataHoraAtual}
		<div
			class="pointer-events-none fixed inset-0 z-50"
			style="animation: fadeIn 0.2s ease-out;"
			role="dialog"
			aria-modal="true"
			aria-labelledby="modal-confirmacao-title"
		>
			<!-- Backdrop leve -->
			<div
				class="pointer-events-auto absolute inset-0 bg-black/20 transition-opacity duration-200"
				onclick={cancelarRegistro}
			></div>

			<!-- Modal Box -->
			<div
				class="bg-base-100 pointer-events-auto absolute z-10 flex max-h-[90vh] w-full max-w-3xl transform flex-col overflow-hidden rounded-2xl shadow-2xl transition-all duration-300"
				style="animation: slideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); {getModalStyle()}"
				onclick={(e) => e.stopPropagation()}
			>
				<!-- Header fixo -->
				<div
					class="border-base-300 flex flex-shrink-0 items-center justify-between border-b px-6 py-4"
				>
					<div class="flex items-center gap-3">
						<div class="bg-primary/10 rounded-lg p-2">
							<Clock class="text-primary h-6 w-6" strokeWidth={2} />
						</div>
						<div>
							<h3 id="modal-confirmacao-title" class="text-base-content text-xl font-bold">
								Confirmar Registro de Ponto
							</h3>
							<p class="text-base-content/70 text-sm">
								Verifique as informações antes de confirmar
							</p>
						</div>
					</div>
					<button
						class="btn btn-sm btn-circle btn-ghost hover:bg-base-300"
						onclick={cancelarRegistro}
						disabled={registrando || aguardandoProcessamento}
					>
						<XCircle class="h-5 w-5" />
					</button>
				</div>

				<!-- Conteúdo com rolagem -->
				<div class="modal-scroll flex-1 space-y-6 overflow-y-auto px-6 py-4">
					<!-- Card da Imagem -->
					<div
						class="card from-base-200 to-base-300 border-primary/20 border-2 bg-gradient-to-br shadow-lg"
					>
						<div class="card-body p-6">
							<div class="mb-4 flex items-center gap-2">
								<div class="bg-primary/10 rounded-lg p-1.5">
									<Image class="text-primary h-5 w-5" strokeWidth={2} />
								</div>
								<h4 class="text-lg font-semibold">Foto Capturada</h4>
							</div>
							<div
								class="bg-base-100 border-primary/30 flex justify-center rounded-xl border-2 p-4"
							>
								<img
									src={URL.createObjectURL(imagemCapturada)}
									alt="Foto capturada do registro de ponto"
									class="max-h-[250px] max-w-full rounded-lg object-contain shadow-md"
								/>
							</div>
						</div>
					</div>

					<!-- Card de Informações -->
					<div
						class="card from-primary/5 to-primary/10 border-primary/20 border-2 bg-gradient-to-br shadow-lg"
					>
						<div class="card-body p-6">
							<div class="mb-4 flex items-center gap-2">
								<div class="bg-primary/20 rounded-lg p-1.5">
									<CheckCircle2 class="text-primary h-5 w-5" strokeWidth={2} />
								</div>
								<h4 class="text-lg font-semibold">Informações do Registro</h4>
							</div>

							<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
								<!-- Tipo de Registro -->
								<div class="bg-base-100 border-base-300 rounded-lg border p-4 shadow-sm">
									<p class="text-base-content/70 mb-1 text-sm font-medium">Tipo de Registro</p>
									<p class="text-primary text-lg font-bold">{tipoLabel}</p>
								</div>

								<!-- Data -->
								<div class="bg-base-100 border-base-300 rounded-lg border p-4 shadow-sm">
									<p class="text-base-content/70 mb-1 text-sm font-medium">Data</p>
									<p class="text-base-content text-lg font-bold">{dataHoraAtual.data}</p>
								</div>

								<!-- Hora -->
								<div class="bg-base-100 border-base-300 rounded-lg border p-4 shadow-sm">
									<p class="text-base-content/70 mb-1 text-sm font-medium">Horário</p>
									<p class="text-base-content text-lg font-bold">{dataHoraAtual.hora}</p>
								</div>

								<!-- Status -->
								<div class="bg-base-100 border-base-300 rounded-lg border p-4 shadow-sm">
									<p class="text-base-content/70 mb-1 text-sm font-medium">Status</p>
									<div class="badge badge-success badge-lg gap-2">
										<CheckCircle2 class="h-4 w-4" />
										Pronto para Registrar
									</div>
								</div>
							</div>

							<!-- Justificativa (se houver) -->
							{#if justificativa.trim()}
								<div class="bg-base-100 border-base-300 mt-4 rounded-lg border p-4 shadow-sm">
									<p class="text-base-content/70 mb-2 text-sm font-medium">Justificativa</p>
									<p class="text-base-content text-base whitespace-pre-wrap">{justificativa}</p>
								</div>
							{/if}
						</div>
					</div>

					<!-- Aviso -->
					<div class="alert alert-info shadow-lg">
						<Info class="h-6 w-6 shrink-0 stroke-current" />
						<div>
							<h3 class="font-bold">Confirme os dados</h3>
							<div class="text-sm">
								Verifique se a foto, data e horário estão corretos antes de confirmar o registro.
							</div>
						</div>
					</div>
				</div>

				<!-- Footer fixo com botões -->
				<div class="border-base-300 flex flex-shrink-0 justify-end gap-3 border-t px-6 py-4">
					<button
						class="btn btn-outline"
						onclick={cancelarRegistro}
						disabled={registrando || aguardandoProcessamento}
					>
						<XCircle class="h-5 w-5" />
						Cancelar
					</button>
					<button
						class="btn btn-primary gap-2"
						onclick={confirmarRegistro}
						disabled={registrando || aguardandoProcessamento}
					>
						{#if registrando || aguardandoProcessamento}
							<span class="loading loading-spinner loading-sm"></span>
							Processando...
						{:else}
							<CheckCircle2 class="h-5 w-5" />
							Confirmar Registro
						{/if}
					</button>
				</div>
			</div>
		</div>
	{/if}

	<!-- Modal Comprovante -->
	{#if mostrandoComprovante && registroId}
		<ComprovantePonto {registroId} onClose={fecharComprovante} />
	{/if}

	<!-- Modal de Erro -->
	<ErrorModal
		open={mostrarModalErro}
		title={mensagemErroModal || 'Erro ao registrar ponto'}
		message={detalhesErroModal ||
			mensagemErroModal ||
			'Ocorreu um erro ao registrar o ponto. Tente novamente.'}
		onClose={fecharModalErro}
	/>
</div>

<style>
	@keyframes fadeIn {
		from {
			opacity: 0;
		}
		to {
			opacity: 1;
		}
	}

	@keyframes slideUp {
		from {
			opacity: 0;
			transform: translateY(20px) scale(0.95);
		}
		to {
			opacity: 1;
			transform: translateY(0) scale(1);
		}
	}

	/* Scrollbar customizada para os modais */
	:global(.modal-scroll) {
		scrollbar-width: thin;
		scrollbar-color: hsl(var(--bc) / 0.3) transparent;
		scroll-behavior: smooth;
		-webkit-overflow-scrolling: touch;
	}

	:global(.modal-scroll::-webkit-scrollbar) {
		width: 8px;
	}

	:global(.modal-scroll::-webkit-scrollbar-track) {
		background: transparent;
		border-radius: 4px;
	}

	:global(.modal-scroll::-webkit-scrollbar-thumb) {
		background-color: hsl(var(--bc) / 0.3);
		border-radius: 4px;
		transition: background-color 0.2s ease;
	}

	:global(.modal-scroll::-webkit-scrollbar-thumb:hover) {
		background-color: hsl(var(--bc) / 0.5);
	}
</style>
