import React, { useState, useRef, useEffect, useCallback } from "react";

interface ChatBubbleProps {
	agentName: string;
	agentUrl: string;
	initialPosition?: { bottom?: number; right?: number; top?: number; left?: number };
}

const MIN_WIDTH = 200;
const MIN_HEIGHT = 150;
const DEFAULT_WIDTH = 350;
const DEFAULT_HEIGHT = 500;

export function ChatBubble({ agentName, agentUrl, initialPosition = { bottom: 20, right: 20 } }: ChatBubbleProps) {
	const [isExpanded, setIsExpanded] = useState(false);
	const [position, setPosition] = useState(initialPosition);
	const [size, setSize] = useState({ width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT });
	const [isDragging, setIsDragging] = useState(false);
	const [isResizing, setIsResizing] = useState(false);
	const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
	const [resizeStart, setResizeStart] = useState({ x: 0, y: 0, width: 0, height: 0 });

	const bubbleRef = useRef<HTMLDivElement>(null);

	const toggleExpansion = useCallback(
		(e: React.MouseEvent) => {
			if (isResizing) {
				return;
			}
			if (
				isExpanded &&
				(e.target === e.currentTarget || (e.target as HTMLElement).closest("button") === e.currentTarget)
			) {
				e.stopPropagation();
			}
			setIsExpanded((prev) => !prev);
			if (!isExpanded) {
				setSize({ width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT });
			}
		},
		[isExpanded, isResizing],
	);

	const handleDragMouseDown = useCallback((e: React.MouseEvent) => {
		if (!bubbleRef.current || (e.target as HTMLElement).closest("button")) {
			return;
		}
		setIsDragging(true);
		const rect = bubbleRef.current.getBoundingClientRect();
		setDragOffset({
			x: e.clientX - rect.left,
			y: e.clientY - rect.top,
		});
		e.preventDefault();
	}, []);

	const handleDragMouseMove = useCallback(
		(e: MouseEvent) => {
			if (!isDragging) return;
			setPosition({
				top: e.clientY - dragOffset.y,
				left: e.clientX - dragOffset.x,
				bottom: undefined,
				right: undefined,
			});
		},
		[isDragging, dragOffset],
	);

	const handleDragMouseUp = useCallback(() => {
		setIsDragging(false);
	}, []);

	const handleResizeMouseDown = useCallback(
		(e: React.MouseEvent) => {
			e.stopPropagation();
			setIsResizing(true);
			setResizeStart({
				x: e.clientX,
				y: e.clientY,
				width: size.width,
				height: size.height,
			});
			e.preventDefault();
		},
		[size],
	);

	const handleResizeMouseMove = useCallback(
		(e: MouseEvent) => {
			if (!isResizing) return;
			const newWidth = Math.max(MIN_WIDTH, resizeStart.width + (e.clientX - resizeStart.x));
			const newHeight = Math.max(MIN_HEIGHT, resizeStart.height + (e.clientY - resizeStart.y));
			setSize({ width: newWidth, height: newHeight });
		},
		[isResizing, resizeStart],
	);

	const handleResizeMouseUp = useCallback(() => {
		setIsResizing(false);
	}, []);

	useEffect(() => {
		const activeDragging = isDragging;
		const activeResizing = isResizing;

		const globalMouseMove = (e: MouseEvent) => {
			if (activeDragging) handleDragMouseMove(e);
			if (activeResizing) handleResizeMouseMove(e);
		};
		const globalMouseUp = () => {
			if (activeDragging) handleDragMouseUp();
			if (activeResizing) handleResizeMouseUp();
		};

		if (activeDragging || activeResizing) {
			window.addEventListener("mousemove", globalMouseMove);
			window.addEventListener("mouseup", globalMouseUp);
		} else {
			window.removeEventListener("mousemove", globalMouseMove);
			window.removeEventListener("mouseup", globalMouseUp);
		}
		return () => {
			window.removeEventListener("mousemove", globalMouseMove);
			window.removeEventListener("mouseup", globalMouseUp);
		};
	}, [isDragging, isResizing, handleDragMouseMove, handleDragMouseUp, handleResizeMouseMove, handleResizeMouseUp]);

	const baseBubbleClasses = `fixed border shadow-lg z-[1000] flex flex-col bg-card text-card-foreground p-3`;
	const collapsedClasses = `min-w-[150px] h-auto rounded-lg items-start`;
	const expandedDynamicClasses = `rounded-lg items-center`;

	const bubbleDynamicClasses = `${baseBubbleClasses} ${isExpanded ? expandedDynamicClasses : collapsedClasses}`;

	const headerClasses = "w-full flex justify-between items-center cursor-grab select-none";
	const iframeContainerClasses = "w-full flex-grow mt-2.5 relative";
	const iframeClasses = "w-full h-full border-none rounded-b-md";
	const buttonClasses = "bg-transparent border-none text-card-foreground p-1 leading-none cursor-pointer";
	const resizeHandleClasses =
		"absolute bottom-0 right-0 w-4 h-4 cursor-se-resize bg-gray-400 opacity-50 hover:opacity-100";

	const bubbleStyle: React.CSSProperties = {
		top: position.top !== undefined ? `${position.top}px` : undefined,
		left: position.left !== undefined ? `${position.left}px` : undefined,
		bottom: position.bottom !== undefined && position.top === undefined ? `${position.bottom}px` : undefined,
		right: position.right !== undefined && position.left === undefined ? `${position.right}px` : undefined,
		width: isExpanded ? `${size.width}px` : undefined,
		height: isExpanded ? `${size.height}px` : undefined,
	};

	return (
		<div
			ref={bubbleRef}
			className={bubbleDynamicClasses}
			style={bubbleStyle}
			onClick={!isExpanded && !isDragging && !isResizing ? toggleExpansion : undefined}
		>
			<div
				className={headerClasses}
				onMouseDown={handleDragMouseDown}
				onDoubleClick={(e) => {
					e.stopPropagation();
					toggleExpansion(e);
				}}
			>
				<span className="font-semibold truncate pr-2">{agentName}</span>
				<button
					onClick={(e) => {
						e.stopPropagation();
						toggleExpansion(e);
					}}
					className={buttonClasses}
					aria-label={isExpanded ? "Collapse chat" : "Expand chat"}
				>
					{isExpanded ? "▼" : "▲"}
				</button>
			</div>
			{isExpanded && (
				<div className={iframeContainerClasses}>
					// TODO(gio): use AgentIframe
					<iframe
						src={agentUrl}
						title={agentName}
						className={iframeClasses}
						style={{ pointerEvents: isDragging || isResizing ? "none" : "auto" }}
					/>
					<div className={resizeHandleClasses} onMouseDown={handleResizeMouseDown} />
				</div>
			)}
		</div>
	);
}
