import { File as FileIcon } from '@phosphor-icons/react';
import { useEffect, useRef, useState, type ReactNode } from 'react';
import styles from './FileUploadDropZone.module.css';

export type DropMode = 'compose' | 'instant';

interface FileUploadDropZoneProps {
	channelName: string;
	onDropFiles: (files: File[], mode: DropMode) => void;
	disabled?: boolean;
	children: ReactNode;
}

/**
 * Full-area file drop target. Wrap the whole chat region with this so
 * a drop anywhere in the viewport — sidebar, chat body, members — is
 * captured. The overlay covers the full root and shows a centered
 * "Upload to #channel" card.
 *
 * Drag counter guards nested dragenter/dragleave events; the overlay
 * uses `pointer-events: none` so the drop itself falls through to
 * the root handler.
 */
export function FileUploadDropZone({
	channelName,
	onDropFiles,
	disabled = false,
	children,
}: FileUploadDropZoneProps) {
	const [isDragging, setIsDragging] = useState(false);
	const dragCounter = useRef(0);

	const hasFiles = (e: React.DragEvent): boolean => {
		const items = e.dataTransfer?.items;
		if (items) {
			for (let i = 0; i < items.length; i++) {
				if (items[i].kind === 'file') return true;
			}
		}
		const types = e.dataTransfer?.types;
		return !!types && Array.from(types).includes('Files');
	};

	const handleDragEnter = (e: React.DragEvent) => {
		if (disabled || !hasFiles(e)) return;
		e.preventDefault();
		e.stopPropagation();
		dragCounter.current += 1;
		if (dragCounter.current === 1) setIsDragging(true);
	};

	const handleDragOver = (e: React.DragEvent) => {
		if (disabled || !hasFiles(e)) return;
		e.preventDefault();
		e.stopPropagation();
		if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';
	};

	const handleDragLeave = (e: React.DragEvent) => {
		if (disabled || !hasFiles(e)) return;
		e.preventDefault();
		e.stopPropagation();
		dragCounter.current -= 1;
		if (dragCounter.current <= 0) {
			dragCounter.current = 0;
			setIsDragging(false);
		}
	};

	const handleDrop = (e: React.DragEvent) => {
		if (disabled) return;
		if (!hasFiles(e)) return;
		e.preventDefault();
		e.stopPropagation();
		dragCounter.current = 0;
		setIsDragging(false);

		const files: File[] = [];
		if (e.dataTransfer?.files) {
			for (let i = 0; i < e.dataTransfer.files.length; i++) {
				files.push(e.dataTransfer.files[i]);
			}
		}
		if (files.length === 0) return;
		const mode: DropMode = e.shiftKey ? 'instant' : 'compose';
		onDropFiles(files, mode);
	};

	// Window blur can strand the overlay if the user drags out of the
	// viewport without a matching dragleave. Reset defensively.
	useEffect(() => {
		const handleWindowBlur = () => {
			dragCounter.current = 0;
			setIsDragging(false);
		};
		window.addEventListener('blur', handleWindowBlur);
		return () => window.removeEventListener('blur', handleWindowBlur);
	}, []);

	return (
		<div
			className={styles.root}
			onDragEnter={handleDragEnter}
			onDragOver={handleDragOver}
			onDragLeave={handleDragLeave}
			onDrop={handleDrop}
		>
			{children}
			{isDragging && (
				<div className={styles.overlay} aria-hidden="true">
					<div className={styles.card}>
						<div className={styles.iconBadge}>
							<FileIcon size={32} weight="duotone" />
						</div>
						<div className={styles.title}>Upload to #{channelName}</div>
						<div className={styles.subtitle}>
							You can add comments before uploading. Hold shift to upload directly.
						</div>
						<div className={styles.hint}>
							<span className={styles.hintKey}>⇧</span>
							<span>Hold for instant upload</span>
						</div>
					</div>
				</div>
			)}
		</div>
	);
}
