'use client'

import { useRef, useState, useCallback, ChangeEvent, DragEvent, useEffect, useMemo } from 'react';
import { IconShieldAdd } from '@/app/ui/icons/icons';
import { fileUpload, cancelUpload, chunkUpload, checkChunkStatus } from '@/app/actions/fileUpload';
import { useTranslations } from 'next-intl';
import { useNavigationBlocker } from '@/app/hooks/useNavigationBlocker';
interface SelectedFile {
	file: File;
	preview: string;
	name: string;
	size: string;
	dimensions?: {
		width: number;
		height: number;
	};
}

interface FileUploadInitResponse {
	upload_id: string,
	file_name: string,
	total_chunks: number,
	chunk_size: number,
	status: string
}

interface UploadSectionFile {
	fileType: string
	allowedExtensions: string[]
	maxFileSize: number
}

export default function UploadSectionFile({ fileType, allowedExtensions, maxFileSize }: UploadSectionFile) {
	const fileInputRef = useRef<HTMLInputElement>(null);
	const [isDragging, setIsDragging] = useState<boolean>(false);
	const [selectedFile, setSelectedFile] = useState<SelectedFile | null>(null);
	const [error, setError] = useState<string | null>(null);
	const [uploadId, setUploadId] = useState<string | null>(null);
	const [isFileUploaded, setIsFileUploaded] = useState<boolean>(false);
	const [uploadProgress, setUploadProgress] = useState<number>(0);
	const [isUploading, setIsUploading] = useState(false);

	const t = useTranslations('Global');
	let SUPPORTED_FORMATS: string[] = [];

	switch (fileType) {
		case 'image':
			SUPPORTED_FORMATS = [
				'image/jpeg',
				'image/jpg',
				'image/png',
				'image/gif',
				'image/bmp',
				'image/webp',
				'image/svg+xml',
				'image/tiff',
				'image/x-icon'
			];
			break;
		case 'video':
			SUPPORTED_FORMATS = [
				'video/mp4',
				'video/mpeg',
				'video/ogg',
				'video/webm',
				'video/quicktime',
				'video/x-msvideo',
				'video/x-matroska',
				'video/x-flv',
				'video/3gpp',
				'video/3gpp2'
			];
			break;
		case 'audio':
			SUPPORTED_FORMATS = [
				'audio/mpeg',
				'audio/wav',
				'audio/wave',
				'audio/x-wav',
				'audio/x-pn-wav',
				'audio/ogg',
				'audio/webm',
				'audio/aac',
				'audio/mp4',
				'audio/x-m4a',
				'audio/flac',
				'audio/x-flac',
				'audio/opus'
			];
			break;

		default:
			break;
	}

	const acceptString = useMemo(() => {
		if (!allowedExtensions || !Array.isArray(allowedExtensions)) {
			return '';
		}
		return allowedExtensions.map(e => `.${e}`).join(', ');
	}, [allowedExtensions]);

	const validateFile = (file: File): { isValid: boolean; errorMessage?: string } => {
		if (!SUPPORTED_FORMATS.includes(file.type as string)) {
			const extension = file.name.split('.').pop()?.toLowerCase();
			if (!extension || !allowedExtensions.includes(extension as string)) {
				return {
					isValid: false,
					errorMessage: t('unsupported-file-format')
				};
			}
		}

		const MAX_SIZE = maxFileSize;

		if (file.size > MAX_SIZE) {
			return {
				isValid: false,
				errorMessage: t('the-file-is-too-large')
			};
		}

		return { isValid: true };
	};

	const getImageDimensions = (file: File): Promise<{ width: number; height: number }> => {
		return new Promise((resolve, reject) => {
			const img = new Image();
			const objectUrl = URL.createObjectURL(file);

			img.onload = () => {
				const dimensions = {
					width: img.width,
					height: img.height
				};
				URL.revokeObjectURL(objectUrl);
				resolve(dimensions);
			};

			img.onerror = () => {
				URL.revokeObjectURL(objectUrl);
				reject(new Error(t('error-uploading-file')));
			};

			img.src = objectUrl;
		});
	};

	const handleFileSelect = useCallback(async (file: File | null): Promise<void> => {
		if (!file) {
			setError(null);
			return;
		}
		setUploadProgress(0);
		setError(null);

		const validation = validateFile(file);

		if (!validation.isValid) {
			setError(validation.errorMessage || t('unknown-validation-error'));

			return;
		}

		try {
			let dimensions = undefined;

			if (fileType === "image") {
				dimensions = await getImageDimensions(file) as { width: number, height: number };
				if (dimensions.width < 150 || dimensions.height < 150 ||
					dimensions.width > 10000 || dimensions.height > 10000) {
					setError(`${t('image-size')}: ${dimensions.width}x${dimensions.height}. ${t('acceptable-range')}: 150x150 - 10000x10000 ${t('pixels')}.`);

					return;
				}
			}

			const objectUrl = URL.createObjectURL(file);

			setSelectedFile({
				file,
				preview: objectUrl,
				name: file.name,
				size: `${(file.size / 1024 / 1024).toFixed(2)} MB`,
				...(dimensions && { dimensions })
			});

			console.log('Файл обработан:', {
				file: file,
				name: file.name,
				type: file.type,
				size: file.size,
				...(dimensions && { dimensions })
			});

		} catch (err) {
			setError(t('error-processing-file'));
		}
	}, []);

	const handleFileInputChange = (event: ChangeEvent<HTMLInputElement>): void => {
		const file = event.target.files?.[0] || null;
		handleFileSelect(file);

		if (fileInputRef.current) {
			fileInputRef.current.value = '';
		}
	};

	const handleButtonClick = (): void => {
		if (fileInputRef.current) {
			fileInputRef.current.click();
		}
	};

	const handleDragOver = (event: DragEvent<HTMLDivElement>): void => {
		event.preventDefault();
		setIsDragging(true);
	};

	const handleDragLeave = (): void => {
		setIsDragging(false);
	};

	const handleDrop = (event: DragEvent<HTMLDivElement>): void => {
		event.preventDefault();
		setIsDragging(false);

		const file = event.dataTransfer.files[0];
		handleFileSelect(file);
	};

	const handleClearFile = async (): Promise<void> => {
		if (selectedFile) {
			URL.revokeObjectURL(selectedFile.preview);
		}

		if (uploadId) {
			await cancelUpload(uploadId);
		}

		setIsFileUploaded(false);
		setSelectedFile(null);
		setError(null);
		setUploadProgress(0);
	};

	const handlerFileUpload = useCallback(async (file: SelectedFile): Promise<void> => {
		// Защита от повторного вызова
		if (isUploading) return;

		// Сбрасываем состояния
		setError(null);
		setIsUploading(true);

		try {
			const extension = file.name.split('.').pop();

			if (!extension) {
				setError(t('file-has-no-extension'));
				return;
			}

			const initMessageBody = {
				file_name: file.name,
				file_type: fileType,
				extension: extension,
				file_size: file.file.size
			};

			const response = await fileUpload(initMessageBody) as FileUploadInitResponse;

			if (response?.upload_id) {
				setUploadId(response.upload_id);
				const CHUNK_SIZE = response.chunk_size;
				const totalChunks = response.total_chunks;
				const fileSize = file.file.size;
				let start = 0;
				let chunkIndex = 0;

				console.log('start upload');
				console.log(`total chanks - ${totalChunks}`);

				while (start < fileSize) {
					console.log(`chank-${chunkIndex}`);
					const end = Math.min(start + CHUNK_SIZE, fileSize);
					const chunk = file.file.slice(start, end);

					const formData = new FormData();
					formData.append('upload_id', response.upload_id);
					formData.append('chunk_number', chunkIndex.toString());
					formData.append('chunk', chunk);
					console.log(`init chunkUpload`);
					const chunkResponse = await chunkUpload(formData);
					console.log(`chunkResponse - ${chunkResponse}`);

					if (chunkResponse.message_desc !== 'Chunk uploaded successfully') {
						throw new Error('Er1: response error');
					}

					if (chunkIndex === totalChunks - 1) {
						const chunkStatus = await checkChunkStatus(response.upload_id);
						if (chunkStatus.message_body.missing_chunks === 0) {
							setUploadId(null);
							setIsFileUploaded(true);
						} else {
							throw new Error('Er2: not all chunks was uploaded');
						}
					}

					start = end;
					chunkIndex++;
					setUploadProgress(Math.floor(chunkIndex / totalChunks * 100));
				}
			} else {
				console.error(response);
				throw new Error('Failed to get upload_id');
			}
		} catch (error) {
			setError(t('error-uploading-file'));
			console.error('Chunk upload error:', error);

			// Для дебага в production
			if (error instanceof Error) {
				console.error('Error name:', error.name);
				console.error('Error message:', error.message);
				if (error.cause) console.error('Error cause:', error.cause);
			}
		} finally {
			setIsUploading(false);
			setUploadId(null);
		}
	}, [isUploading, fileType]); // Добавьте зависимости

	useEffect(() => {
		// Обработка закрытия вкладки
		// Тут можно попробовать изучить вопрос с navigator.sendBeacon('', blob)
		// он нужен для того что бы послать запрос на бек при закрытии вкладки,
		// но у него есть свои особенности и стандартные запросы не работают.
		const handleUnload = () => {
			if (uploadId) {
				//const data = JSON.stringify({ uploadId, reason: 'tab_closed' });
				//const blob = new Blob([data], { type: 'application/json' });
				//navigator.sendBeacon('/api/v1/data/cancel', blob);
				console.log('sendBeacon');
			}
		};
		if (uploadId) {
			window.addEventListener('unload', handleUnload);
		}

		return () => {
			window.removeEventListener('unload', handleUnload);
		};
	}, [uploadId]);

	useNavigationBlocker({
		shouldBlock: !!uploadId,
		message: t('have-unsaved-changes'),
		onConfirm: async () => {
			console.log('User confirmed navigation');
			if (uploadId) {
				await cancelUpload(uploadId);
			}
		},
		onCancel: () => {
			console.log('User cancelled navigation');
		}
	});

	return (
		<div className="upload-section">
			<h3>
				{t('upload-for-protection', { fileType: t(fileType.toLocaleLowerCase()) })}
			</h3>

			<div
				className={`drag-drop-zone ${isDragging ? 'dragging' : ''}`}
				onDragOver={handleDragOver}
				onDragLeave={handleDragLeave}
				onDrop={handleDrop}
				style={{
					border: isDragging ? '2px dashed #3b82f6' : '2px dashed #d1d5db',
					backgroundColor: isDragging ? '#eff6ff' : '#f9fafb',
					padding: '2rem',
					borderRadius: '.75rem',
					textAlign: 'center',
					transition: 'all .2s ease-in-out'
				}}
			>
				<IconShieldAdd />
				<h4>
					{t('drag-the-file-here')}
				</h4>
				<p className="mb-2.5 text-[#6b7280]">
					{t('or')}
				</p>
				<input
					ref={fileInputRef}
					type="file"
					accept={acceptString}
					style={{ display: 'none' }}
					onChange={handleFileInputChange}
					aria-label="Выбор файла для защиты"
				/>

				<button
					className="btn btn-primary"
					onClick={handleButtonClick}
					type="button"
				>
					{t('select-files-to-protect')}
				</button>

				{fileType === "image" && (
					<p className="description">
						{t('image-resolution')}: 100x100 - 10000x10000
					</p>
				)}
				<p className="description">
					{t('file-size')}: {t('to')} {(maxFileSize / 1024 / 1024)} {t('mb')}
				</p>
				<p className="description">
					{t('file-format')}: {acceptString}
				</p>

				{error && (
					<div className="mt-4 p-3 bg-red-50 border border-red-200 rounded-lg">
						<p className="text-red-600 font-medium">{error}</p>
					</div>
				)}

				{selectedFile && (
					<div
						className={`selected-file ${isFileUploaded ? 'done' : ''}`}
					>
						<div className="selected-file-file-info">
							<div>
								<p className="text-gray-700">
									<span className="font-medium">
										{t('file')}:
									</span> {selectedFile.name}
								</p>
								<p className="text-gray-700">
									<span className="font-medium">
										{t('size')}:
									</span> {selectedFile.size}
								</p>
								<p className="text-gray-700">
									<span className="font-medium">{t('cost-of-protection')}:</span> 0
								</p>
								<p className="text-gray-700">
									<span className="font-medium">{t('current-balance')}:</span> 0
								</p>
							</div>
							<div>
								{isFileUploaded && (
									<div className="font-medium text-green-600 text-2xl">
										{t('file-successfully-uploaded')}
									</div>
								)}
							</div>
						</div>

						{fileType === 'image' && (
							<img
								src={selectedFile.preview}
								alt="Предпросмотр загруженного изображения"
								className="uploaded-image"
								onError={() => setError('Не удалось загрузить превью изображения')}
							/>
						)}

						<div className="mt-4 flex gap-3 justify-center relative">
							<button
								className="btn btn-cancel"
								onClick={handleClearFile}
								type="button"
							>
								{isFileUploaded ? t('close') : t('cancel')}
							</button>
							<button
								className={`btn btn-confirm ${error || isFileUploaded ? 'disabled' : ''}`}
								onClick={() => {
									handlerFileUpload(selectedFile);
								}}
								type="button"
								disabled={error || isFileUploaded || isUploading ? true : false}
							>
								{t('upload-file')}
							</button>
							{uploadProgress !== 0 && (
								<div
									className={`absolute top-5 right-5 font-medium ${isFileUploaded ? "text-green-600" : ""}`}
								>
									{uploadProgress}%
								</div>
							)}
						</div>
					</div>
				)}
			</div>
		</div>
	);
}