'use client'

import { useRef, useState, useCallback, ChangeEvent, DragEvent, useEffect, useMemo } from 'react';
import { IconSearch } 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';
import { useQueryClient } from '@tanstack/react-query';
import { removeUserFile } from '@/app/actions/fileEntity';
import { FileSearchPanel } from '@/app/ui/search/file-search-panel';
interface SelectedFile {
	file: File;
	preview: string | undefined;
	name: string;
	size: string;
}

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

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

export default function SectionSearchFile({ fileType, allowedExtensions, maxFileSize }: SectionSearchFile) {
	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 [fileId, setFileId] = useState<string | null>(null);
	const queryClient = useQueryClient();
	const isCancelledRef = useRef(false);

	const childRef = useRef(null);

	const t = useTranslations('Global');

	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 (!allowedExtensions.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 handleFileSelect = useCallback(async (file: File | null): Promise<void> => {
		if (!file) {
			setError(null);
			return;
		}

		if (fileId) {
			await removeUserFile(fileId, 1);
			setFileId(null);
		}

		setError(null);
		setIsFileUploaded(false);

		if (childRef.current) {
			//@ts-ignore
			childRef.current.clearList();
		}

		setUploadProgress(0);

		const validation = validateFile(file);

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

		setSelectedFile({
			file,
			name: file.name,
			size: `${(file.size / 1024 / 1024).toFixed(2)} MB`,
			preview: file.size < 10 * 1024 * 1024 ? URL.createObjectURL(file) : undefined
		});

		handlerFileUpload({
			file,
			name: file.name,
			size: `${(file.size / 1024 / 1024).toFixed(2)} MB`,
			preview: file.size < 10 * 1024 * 1024 ? URL.createObjectURL(file) : undefined
		});

	}, [fileType, t]);

	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 handlerFileUpload = useCallback(async (fileInfo: SelectedFile): Promise<void> => {
		if (uploadId) return;

		setError(null);
		isCancelledRef.current = false;
		const file = fileInfo.file;

		try {
			const extension = file.name.split('.').pop() || '';
			const initMessageBody = {
				file_name: file.name,
				file_type: fileType,
				extension: extension,
				file_size: file.size
			};

			const response = await fileUpload(initMessageBody) as FileUploadInitResponse;

			if (!response?.upload_id) {
				throw new Error('Failed to get upload_id');
			}

			const CHUNK_SIZE = response.chunk_size;
			const totalChunks = response.total_chunks;

			setUploadId(response.upload_id);

			for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
				if (isCancelledRef.current) {
					return;
				}

				const isLastChunk = chunkIndex === totalChunks - 1;
				const start = chunkIndex * CHUNK_SIZE;
				const end = Math.min(start + CHUNK_SIZE, file.size);
				const chunk = 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);
				formData.append('findSimilar', '1');

				const chunkResponse = await chunkUpload(formData);

				if (chunkResponse.message_desc !== 'Chunk uploaded successfully') {
					throw new Error(`Chunk ${chunkIndex} upload failed`);
				}

				setUploadProgress(Math.floor((chunkIndex + 1) / totalChunks * 100));

				if (isLastChunk) {
					setFileId(chunkResponse.message_body.file_id);
					document.cookie = `searchedFileId=${chunkResponse.message_body.file_id}`
				}
			}

			const chunkStatus = await checkChunkStatus(response.upload_id);
			if (chunkStatus.message_body.missing_chunks === 0) {
				setIsFileUploaded(true);
				await queryClient.invalidateQueries({ queryKey: ['userFilesData'] });
				await queryClient.invalidateQueries({ queryKey: ['userFilesInfo'] });
			} else {
				throw new Error('Not all chunks were uploaded');
			}

		} catch (error) {
			if (!isCancelledRef.current) {
				setError(t('error-uploading-file'));
				console.error('Upload error:', error);
			}
		} finally {
			setUploadId(null);
		}
	}, [uploadId, 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">
			<div className="search-info">
				<div className="search-info-title">Как работает поиск?</div>
				<div className="search-info-text">
					Наша система анализирует загруженный файл и сравнивает его с вашими защищенными файлами,
					используя алгоритмы компьютерного зрения и цифровых отпечатков.
				</div>
			</div>

			<div
				className={`drag-drop-zone ${isDragging ? 'dragging' : ''}`}
				onDragOver={handleDragOver}
				onDragLeave={handleDragLeave}
				onDrop={handleDrop}
			>
				<IconSearch />
				<h4>
					Выберите файл для поиска
				</h4>

				<input
					ref={fileInputRef}
					type="file"
					accept={acceptString}
					style={{ display: 'none' }}
					onChange={handleFileInputChange}
					aria-label="Выбор файла для защиты"
				/>

				<button
					className="btn btn-primary"
					onClick={handleButtonClick}
					type="button"
					disabled={uploadProgress && uploadProgress !== 100 ? true : false}
				>
					Выбрать файл
				</button>

				{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`}
					>
						<div className="selected-file-file-info relative">
							<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>
							</div>
							{uploadProgress !== 0 && (
								<div
									className={`absolute top-0 right-0 font-medium ${isFileUploaded ? "text-green-600" : ""}`}
								>
									{uploadProgress}%
								</div>
							)}
						</div>
					</div>
				)}
			</div>

			{isFileUploaded && (
				<FileSearchPanel fileId={fileId} ref={childRef} />
			)}
		</div>
	);
}