import { useEffect, useState } from 'react';

import getProvider from '../../utils/getProvider.js';
import { useDebounce } from '../../utils/useDebounce.js';

import './Gallery.scss';

const PROVIDER = getProvider();

interface Props {
	currentFile: any;
	setCurrentFile: (value: any) => void;
	close: () => void;
	fileTypes: string[];
}

export default function Gallery({
	currentFile,
	setCurrentFile,
	close,
	fileTypes,
}: Props) {
	const [files, setFiles] = useState<any[]>([]);
	const [selectedFileInit, setSelectedFileInit] = useState(currentFile);
	const [selectedFile, setSelectedFile] = useState(currentFile);
	const [search, setSearch] = useState('');
	const [page, setPage] = useState(1);
	const [maxPages, setMaxPages] = useState(1);
	const debouncedSearch = useDebounce(search, 500);

	function onSetSelectedFile(file: any) {
		setSelectedFile(file);
		setSelectedFileInit(file);
	}

	useEffect(() => {
		PROVIDER &&
			PROVIDER.gallery.getFiles(
				setFiles,
				fileTypes,
				debouncedSearch,
				page,
				setMaxPages
			);
	}, [debouncedSearch, page]);

	function renderFiles() {
		return PROVIDER
			? PROVIDER.gallery.renderFiles(files, selectedFile, onSetSelectedFile)
			: null;
	}

	function updateSelectedFile() {
		if (selectedFile) {
			setSelectedFileInit(selectedFile);
			setFiles((prev) =>
				prev.map((file) => {
					if (file.id === selectedFile.id) {
						return selectedFile;
					}
					return file;
				})
			);

			PROVIDER && PROVIDER.gallery.updateFile(selectedFile.id, selectedFile);
		}
	}

	function renderSelectedFile(details?: boolean) {
		if (selectedFile) {
			return PROVIDER
				? PROVIDER.gallery.renderSelectedFile(
						selectedFile,
						setSelectedFile,
						details
				  )
				: null;
		}
	}

	const [dragging, setDragging] = useState(false);

	const count = -1; // max number of files that can be uploaded at a time
	const formats = fileTypes; //['jpg', 'jpeg', 'png', 'gif', 'svg']; // allowed file formats

	async function onUpload(files: any) {
		if (PROVIDER) {
			const data = await PROVIDER.gallery.uploadFiles(files);
			setFiles((prev) => [...data, ...prev]);
		}
	}

	function handleDragOver(e: React.DragEvent<HTMLDivElement>) {
		e.preventDefault();
		e.stopPropagation();
	}
	function handleDrop(e: React.DragEvent<HTMLDivElement>) {
		e.preventDefault();
		e.stopPropagation();

		// this is required to convert FileList object to array
		const files = [...(e.dataTransfer?.files ?? [])];

		setDragging(false);

		if (!files.length) return; // if no files were dropped, do nothing

		// check if the provided count prop is less than uploaded count of files
		if (count > -1 && count < files.length) {
			console.log(
				`Only ${count} file${count > 1 ? 's' : ''} can be uploaded at a time`
			);
			return;
		}

		// check if some uploaded file is not in one of the allowed formats
		if (
			formats &&
			files.some(
				(file) =>
					!formats.some((format) =>
						file.name.toLowerCase().endsWith(format.toLowerCase())
					)
			)
		) {
			console.log(
				`Only following file formats are acceptable: ${formats.join(', ')}`
			);
			return;
		}

		onUpload(files);
	}
	function handleDragEnter(e: React.DragEvent<HTMLDivElement>) {
		e.preventDefault();
		e.stopPropagation();

		if ((e.target as HTMLDivElement).id === 'draggingOverlay') return;
		setDragging(true);
	}
	function handleDragLeave(e: React.DragEvent<HTMLDivElement>) {
		e.preventDefault();
		e.stopPropagation();

		if ((e.target as HTMLDivElement).id !== 'draggingOverlay') return;
		setDragging(false);
	}

	return (
		<div
			className={`gallery`}
			onClick={close} // close on click outside
		>
			<div
				className={`gallery__container`}
				onClick={(e) => e.stopPropagation()} // prevent closing on click inside
				onDragOver={handleDragOver}
				onDrop={handleDrop}
				onDragEnter={handleDragEnter}
				onDragLeave={handleDragLeave}
			>
				{dragging && (
					<div
						id='draggingOverlay'
						className={`gallery__container__drag-overlay`}
					>
						<div>Drop here</div>
					</div>
				)}

				<i
					className='gallery__container__close-btn fa-solid fa-sharp fa-times'
					onClick={close}
				/>

				<div className={`gallery__container__inner`}>
					<div className='gallery__topbar'>
						<input
							type='text'
							placeholder='Search...'
							className='gallery__topbar__search'
							onChange={(e) => setSearch(e.target.value)}
						/>
					</div>
					<div
						className={`gallery__container__file-container ${
							files.length > 0
								? `gallery__container__file-container--has-files`
								: ``
						}`}
					>
						{files.length > 0 ? (
							renderFiles()
						) : (
							<div className={`gallery__container__file-container__empty`}>
								Drop files to upload
							</div>
						)}
					</div>
					<div className='gallery__bottombar'>
						<div className='gallery__bottombar__pagination'>
							<button
								className='gallery__bottombar__pagination__prev'
								disabled={page === 1}
								onClick={() => {
									if (page > 1) {
										setPage(page - 1);
									}
								}}
							>
								Prev
							</button>
							<span className='gallery__bottombar__pagination__page'>
								{page} / {maxPages}
							</span>
							<button
								className='gallery__bottombar__pagination__next'
								disabled={page === maxPages}
								onClick={() => {
									if (page < maxPages) {
										setPage(page + 1);
									}
								}}
							>
								Next
							</button>
						</div>
					</div>
				</div>
				{selectedFile && (
					<div className={`gallery__container__selected-file-panel`}>
						<div>
							{renderSelectedFile(true)}
							{selectedFile != selectedFileInit && (
								<button
									className={`gallery__container__selected-file-panel__save-btn`}
									onClick={updateSelectedFile}
								>
									SAVE
								</button>
							)}
						</div>
						<button
							className={`gallery__container__selected-file-panel__select-btn`}
							onClick={() => {
								setCurrentFile(selectedFile);
								setSelectedFile('');
								setSelectedFileInit(null);
								close();
							}}
						>
							SELECT
						</button>
					</div>
				)}
			</div>
		</div>
	);
}
