'use client'

import { useState, useRef, useMemo, ChangeEvent, useCallback } from 'react';
import { useAllFilesExtensions } from '@/app/hooks/react-query/useAllFilesExtensions';
import { removeUserFile } from '@/app/actions/fileEntity';
import { useTranslations } from 'next-intl';
import { fileUpload, chunkUpload, checkChunkStatus } from '@/app/actions/fileUpload';
import { getFileType } from '@/app/lib/getFileType';
import { searchUserFiles } from '@/app/actions/searchActions';
import { toast } from 'sonner';

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
}

export default function LocalFileCheck() {
	const { data: allFilesExtensions } = useAllFilesExtensions();

	const fileInputRef = useRef<HTMLInputElement>(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 [searchResult, setSearchResult] = useState<string | null>(null);
	const isCancelledRef = useRef(false);

	const childRef = useRef(null);

	const t = useTranslations('Global');

	const allExtensions = useMemo(() => {
		if (allFilesExtensions) {
			return [...allFilesExtensions.images, ...allFilesExtensions.videos, ...allFilesExtensions.audios, ...allFilesExtensions.documents]
		} else {
			return []
		}
	}, []);



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

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

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

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

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

		const MAX_SIZE = allFilesExtensions?.maxFileSize ? allFilesExtensions?.maxFileSize : 0;

		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> => {
		setSearchResult(null);

		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;
		}

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

	}, [t]);

	const handlerFileUpload = useCallback(async (fileInfo: SelectedFile): Promise<void> => {
		if (uploadId) return;

		setError(null);
		isCancelledRef.current = false;
		const file = fileInfo.file;
		const fileType = getFileType(fileInfo.file.name, allFilesExtensions);

		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.errorMesage !== null) {
					throw chunkResponse.errorMesage;
				}

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

				if (isLastChunk && chunkResponse.fileId) {
					setFileId(chunkResponse.fileId);
					document.cookie = `searchedFileId=${chunkResponse.fileId}`
					handlerSearchUserFile(chunkResponse.fileId, fileInfo.name);
				}
			}

			const chunkStatus = await checkChunkStatus(response.upload_id);
			if (chunkStatus.message_body.missing_chunks === 0) {
				setIsFileUploaded(true);
			} 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, allFilesExtensions]);


	const handlerSearchUserFile = useCallback(async (fileId: string, fileName: string): Promise<void> => {

		try {
			let result = await searchUserFiles(fileId);

			if (result.errorMessage) {
				throw result.errorMessage
			}

			if (result?.content?.length) {
				result.content.some((e: any) => {
					if (e.status === 'PROTECTED') {
						toast.success(t('file-file-name-already-exists', {
							fileName: fileName
						}));
						setSearchResult(t('file-file-name-already-exists', {
							fileName: fileName
						}));
						return true;
					}
					return false;
				});
			} else {
				toast.warning(t('file-file-name-does-not-exist', {
					fileName: fileName
				}));
				setSearchResult(t('file-file-name-does-not-exist', {
					fileName: fileName
				}));
			}
		} catch (error) {

			if (error === 'file-for-search-unsupported') {
				toast.error(t(error));
			} else {
				toast.error(t('search-error'));
			}
		}

	}, [fileId])

	return (
		<div
			className="local-file-check"
		>
			<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}
				style={{ minWidth: '140px' }}
			>
				<span>Проверка файла</span>
				{(uploadProgress !== 0 && uploadProgress !== 100) && (
					<div className="loading-animation">
						<span className="global-spinner"></span>
					</div>
				)}
			</button>
			<div
				className="local-file-check-result"
				onClick={() => {
					setSearchResult(null);
					setIsFileUploaded(false);
				}}
			>
				{searchResult}
			</div>
		</div>
	)
}