<script lang="ts">
	import { Image as ImageIcon, Upload, X, Camera } from 'lucide-svelte';

	interface Props {
		value?: string | null;
		onChange?: (base64: string | null) => void;
		maxSizeMB?: number;
		maxWidth?: number;
		maxHeight?: number;
	}

	let {
		value = $bindable(null),
		onChange,
		maxSizeMB = 5,
		maxWidth = 1200,
		maxHeight = 1200
	}: Props = $props();

	let preview = $state<string | null>(value);
	let error = $state<string | null>(null);
	let inputElement: HTMLInputElement | null = null;
	let showCamera = $state(false);
	let videoElement: HTMLVideoElement | null = null;
	let stream: MediaStream | null = null;
	let capturing = $state(false);

	function handleFileSelect(event: Event) {
		const target = event.target as HTMLInputElement;
		const file = target.files?.[0];
		if (!file) return;

		error = null;

		// Validar tamanho
		if (file.size > maxSizeMB * 1024 * 1024) {
			error = `Arquivo muito grande. Tamanho máximo: ${maxSizeMB}MB`;
			return;
		}

		// Validar tipo
		if (!file.type.startsWith('image/')) {
			error = 'Por favor, selecione um arquivo de imagem';
			return;
		}

		const reader = new FileReader();

		reader.onload = (e) => {
			const result = e.target?.result as string;
			if (result) {
				// Redimensionar imagem se necessário
				resizeImage(result, maxWidth, maxHeight)
					.then((resized) => {
						preview = resized;
						value = resized;
						if (onChange) {
							onChange(resized);
						}
					})
					.catch((err) => {
						error = err instanceof Error ? err.message : 'Erro ao processar imagem';
					});
			}
		};

		reader.onerror = () => {
			error = 'Erro ao ler arquivo';
		};

		reader.readAsDataURL(file);
	}

	function resizeImage(
		dataUrl: string,
		maxWidth: number,
		maxHeight: number
	): Promise<string> {
		return new Promise((resolve, reject) => {
			const img = new window.Image();
			img.onload = () => {
				let width = img.width;
				let height = img.height;

				// Calcular novas dimensões mantendo proporção
				if (width > maxWidth || height > maxHeight) {
					const ratio = Math.min(maxWidth / width, maxHeight / height);
					width = width * ratio;
					height = height * ratio;
				}

				const canvas = document.createElement('canvas');
				canvas.width = width;
				canvas.height = height;

				const ctx = canvas.getContext('2d');
				if (!ctx) {
					reject(new Error('Não foi possível criar contexto do canvas'));
					return;
				}

				ctx.drawImage(img, 0, 0, width, height);
				const resizedDataUrl = canvas.toDataURL('image/jpeg', 0.85);
				resolve(resizedDataUrl);
			};

			img.onerror = () => {
				reject(new Error('Erro ao carregar imagem'));
			};

			img.src = dataUrl;
		});
	}

	function removeImage() {
		preview = null;
		value = null;
		if (inputElement) {
			inputElement.value = '';
		}
		if (onChange) {
			onChange(null);
		}
	}

	function triggerFileInput() {
		inputElement?.click();
	}

	async function openCamera() {
		// Se já estiver inicializando ou já tiver stream, não fazer nada
		if (stream) {
			return;
		}

		// Primeiro, abrir o modal
		showCamera = true;
		capturing = false;
		error = null;

		// Aguardar o próximo tick para garantir que o DOM foi atualizado
		await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));

		try {
			// Verificar se a API está disponível
			if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
				error = 'Câmera não disponível neste dispositivo ou navegador não suporta acesso à câmera';
				showCamera = false;
				return;
			}

			// Aguardar o elemento de vídeo estar disponível no DOM
			let attempts = 0;
			while (!videoElement && attempts < 30) {
				await new Promise((resolve) => setTimeout(resolve, 50));
				attempts++;
			}

			if (!videoElement) {
				throw new Error('Elemento de vídeo não encontrado no DOM');
			}

			// Solicitar acesso à câmera
			stream = await navigator.mediaDevices.getUserMedia({
				video: {
					facingMode: 'environment', // Câmera traseira por padrão
					width: { ideal: 1280 },
					height: { ideal: 720 }
				}
			});

			// Atribuir stream ao vídeo
			videoElement.srcObject = stream;
			
			// Aguardar o vídeo estar pronto e começar a reproduzir
			await videoElement.play();
			
			// Aguardar metadata estar carregado
			if (videoElement.readyState < 2) {
				await new Promise<void>((resolve, reject) => {
					if (!videoElement) {
						reject(new Error('Elemento de vídeo não encontrado'));
						return;
					}

					const onLoadedMetadata = () => {
						videoElement?.removeEventListener('loadedmetadata', onLoadedMetadata);
						videoElement?.removeEventListener('error', onError);
						resolve();
					};

					const onError = () => {
						videoElement?.removeEventListener('loadedmetadata', onLoadedMetadata);
						videoElement?.removeEventListener('error', onError);
						reject(new Error('Erro ao carregar vídeo'));
					};

					videoElement.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
					videoElement.addEventListener('error', onError, { once: true });
				});
			}

			capturing = true;
		} catch (err) {
			console.error('Erro ao acessar câmera:', err);
			let errorMessage = 'Erro ao acessar câmera';
			
			if (err instanceof Error) {
				if (err.name === 'NotAllowedError' || err.name === 'PermissionDeniedError') {
					errorMessage = 'Permissão de acesso à câmera negada. Por favor, permita o acesso à câmera nas configurações do navegador.';
				} else if (err.name === 'NotFoundError' || err.name === 'DevicesNotFoundError') {
					errorMessage = 'Nenhuma câmera encontrada no dispositivo.';
				} else if (err.name === 'NotReadableError' || err.name === 'TrackStartError') {
					errorMessage = 'Câmera está sendo usada por outro aplicativo.';
				} else {
					errorMessage = err.message || errorMessage;
				}
			}
			
			error = errorMessage;
			showCamera = false;
			capturing = false;
			stopCamera();
		}
	}

	function stopCamera() {
		if (stream) {
			stream.getTracks().forEach((track) => track.stop());
			stream = null;
		}
		if (videoElement) {
			videoElement.srcObject = null;
		}
		capturing = false;
	}

	function closeCamera() {
		stopCamera();
		showCamera = false;
		error = null;
	}

	async function capturePhoto() {
		if (!videoElement) return;

		try {
			// Criar canvas para capturar o frame
			const canvas = document.createElement('canvas');
			canvas.width = videoElement.videoWidth;
			canvas.height = videoElement.videoHeight;

			const ctx = canvas.getContext('2d');
			if (!ctx) {
				error = 'Não foi possível criar contexto do canvas';
				return;
			}

			// Desenhar o frame atual do vídeo no canvas
			ctx.drawImage(videoElement, 0, 0);

			// Converter para base64
			const dataUrl = canvas.toDataURL('image/jpeg', 0.85);

			// Redimensionar e processar
			const resized = await resizeImage(dataUrl, maxWidth, maxHeight);
			preview = resized;
			value = resized;
			if (onChange) {
				onChange(resized);
			}

			// Fechar câmera
			closeCamera();
		} catch (err) {
			error = err instanceof Error ? err.message : 'Erro ao capturar foto';
			console.error('Erro ao capturar foto:', err);
		}
	}

	// Sincronizar preview com value sempre que value mudar
	$effect(() => {
		// Sempre sincronizar quando value mudar
		preview = value;
	});


	// Limpar stream quando o componente for desmontado
	$effect(() => {
		return () => {
			stopCamera();
		};
	});
</script>

<div class="image-upload">
	<input
		type="file"
		accept="image/*"
		class="hidden"
		bind:this={inputElement}
		onchange={handleFileSelect}
		aria-label="Selecionar imagem do produto"
	/>

	{#if preview}
		<div class="relative inline-block">
			<img src={preview} alt="Preview da imagem do produto" class="max-w-full max-h-64 rounded-lg" />
			<button
				type="button"
				class="btn btn-sm btn-circle btn-error absolute top-2 right-2"
				onclick={removeImage}
				aria-label="Remover imagem"
			>
				<X class="h-4 w-4" />
			</button>
		</div>
	{:else}
		<div class="flex flex-col gap-4">
			<div
				class="border-2 border-dashed border-base-300 rounded-lg p-8 text-center cursor-pointer hover:border-primary transition-colors"
				onclick={triggerFileInput}
				role="button"
				tabindex="0"
				onkeydown={(e) => {
					if (e.key === 'Enter' || e.key === ' ') {
						e.preventDefault();
						triggerFileInput();
					}
				}}
			>
				<Upload class="h-12 w-12 mx-auto mb-4 text-base-content/40" />
				<p class="text-base-content/70 font-medium mb-2">Clique para fazer upload da imagem</p>
				<p class="text-sm text-base-content/50">
					PNG, JPG ou GIF até {maxSizeMB}MB
				</p>
			</div>
			<div class="divider text-sm">ou</div>
			<button
				type="button"
				class="btn btn-outline btn-primary w-full"
				onclick={openCamera}
			>
				<Camera class="h-5 w-5" />
				Capturar da Câmera
			</button>
		</div>
	{/if}

	{#if error}
		<div class="alert alert-error mt-4">
			<span>{error}</span>
		</div>
	{/if}

	{#if preview}
		<div class="flex gap-2 mt-4">
			<button
				type="button"
				class="btn btn-sm btn-outline btn-primary flex-1"
				onclick={triggerFileInput}
			>
				<ImageIcon class="h-4 w-4" />
				Alterar Imagem
			</button>
			<button
				type="button"
				class="btn btn-sm btn-outline btn-primary flex-1"
				onclick={openCamera}
			>
				<Camera class="h-4 w-4" />
				Capturar Foto
			</button>
		</div>
	{/if}
</div>

<!-- Modal da Câmera -->
{#if showCamera}
	<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/80" onclick={closeCamera}>
		<div
			class="bg-base-100 rounded-lg shadow-2xl p-6 max-w-2xl w-full mx-4"
			onclick={(e) => e.stopPropagation()}
		>
			<div class="flex items-center justify-between mb-4">
				<h3 class="text-xl font-bold">Capturar Foto</h3>
				<button
					type="button"
					class="btn btn-sm btn-circle btn-ghost"
					onclick={closeCamera}
					aria-label="Fechar câmera"
				>
					<X class="h-5 w-5" />
				</button>
			</div>

			<div class="relative bg-black rounded-lg overflow-hidden mb-4" style="aspect-ratio: 4/3; min-height: 300px;">
				{#if showCamera}
					<video
						bind:this={videoElement}
						autoplay
						playsinline
						muted
						class="w-full h-full object-cover"
						style="transform: scaleX(-1); opacity: {capturing ? '1' : '0'}; transition: opacity 0.3s;"
					></video>
				{/if}
				{#if !capturing}
					<div class="flex items-center justify-center h-full absolute inset-0 z-10">
						<div class="text-center">
							<span class="loading loading-spinner loading-lg text-primary mb-2"></span>
							<p class="text-base-content/70 text-sm">Iniciando câmera...</p>
						</div>
					</div>
				{/if}
			</div>

			<div class="flex gap-2 justify-end">
				<button
					type="button"
					class="btn btn-ghost"
					onclick={closeCamera}
				>
					Cancelar
				</button>
				<button
					type="button"
					class="btn btn-primary"
					onclick={capturePhoto}
					disabled={!capturing}
				>
					<Camera class="h-5 w-5" />
					Capturar Foto
				</button>
			</div>
		</div>
	</div>
{/if}

<style>
	.image-upload {
		width: 100%;
	}
</style>

