/**
 * NodeTypeCombobox
 *
 * A combobox component for selecting and adding node types to the canvas.
 * Lists all registered node types and creates a new node on selection.
 */

'use client';

import React, { useState, useRef, useEffect } from 'react';
import { useAtomValue } from 'jotai';
import { getRegisteredNodeTypes } from '../core/node-type-registry';
import { useCreateNode } from '../db/hooks/useCreateNode';
import { currentGraphIdAtom, viewportRectAtom, panAtom, zoomAtom } from '../core';
import { createDebug } from '../utils/debug';
import { ComboboxSearch } from './ComboboxSearch';
import { ComboboxOption } from './ComboboxOption';

// Re-export sub-components
export { ComboboxOption } from './ComboboxOption';
export type { ComboboxOptionProps } from './ComboboxOption';
export { ComboboxSearch } from './ComboboxSearch';
export type { ComboboxSearchProps } from './ComboboxSearch';

const debug = createDebug('node-type-combobox');

export interface NodeTypeOption {
	/** Node type identifier (used for registration) */
	type: string;
	/** Display label (defaults to type if not provided) */
	label?: string;
	/** Optional icon or emoji */
	icon?: string;
	/** Optional description */
	description?: string;
	/** Default width for this node type */
	defaultWidth?: number;
	/** Default height for this node type */
	defaultHeight?: number;
}

export interface NodeTypeComboboxProps {
	/** Optional custom list of node types (defaults to registered types) */
	nodeTypes?: NodeTypeOption[];

	/** Callback after node is created */
	onNodeCreated?: (nodeId: string, nodeType: string) => void;

	/** Position to create node at. Defaults to center of viewport */
	createPosition?: { x: number; y: number } | 'center' | 'random';

	/** Placeholder text */
	placeholder?: string;

	/** Whether to clear selection after creating */
	clearOnCreate?: boolean;

	/** Custom className for the container */
	className?: string;

	/** Custom styles */
	style?: React.CSSProperties;

	/** Disabled state */
	disabled?: boolean;
}

/**
 * A combobox for selecting node types and adding them to the canvas.
 *
 * @example
 * ```tsx
 * // Basic usage - uses all registered node types
 * <NodeTypeCombobox onNodeCreated={(id) => console.log('Created:', id)} />
 *
 * // With custom node types
 * <NodeTypeCombobox
 *   nodeTypes={[
 *     { type: 'note', label: 'Note', icon: '📝' },
 *     { type: 'image', label: 'Image', icon: '🖼️' },
 *   ]}
 * />
 * ```
 */
export function NodeTypeCombobox({
	nodeTypes: customNodeTypes,
	onNodeCreated,
	createPosition = 'center',
	placeholder = 'Add node...',
	clearOnCreate = true,
	className,
	style,
	disabled = false,
}: NodeTypeComboboxProps) {
	const [isOpen, setIsOpen] = useState(false);
	const [searchQuery, setSearchQuery] = useState('');
	const [highlightedIndex, setHighlightedIndex] = useState(0);
	const inputRef = useRef<HTMLInputElement>(null);
	const listRef = useRef<HTMLUListElement>(null);

	const createNode = useCreateNode();
	const graphId = useAtomValue(currentGraphIdAtom);
	const viewportRect = useAtomValue(viewportRectAtom);
	const pan = useAtomValue(panAtom);
	const zoom = useAtomValue(zoomAtom);

	// Get node types - either custom or from registry
	const nodeTypes: NodeTypeOption[] = customNodeTypes ?? getRegisteredNodeTypes().map((type) => ({
		type,
		label: formatTypeLabel(type),
	}));

	// Filter by search query
	const filteredTypes = (() => {
		if (!searchQuery.trim()) return nodeTypes;

		const query = searchQuery.toLowerCase();
		return nodeTypes.filter(
			(opt) =>
				opt.type.toLowerCase().includes(query) ||
				opt.label?.toLowerCase().includes(query) ||
				opt.description?.toLowerCase().includes(query),
		);
	})();

	// Calculate creation position
	const getCreatePosition = () => {
		if (typeof createPosition === 'object') {
			return createPosition;
		}

		// Default viewport dimensions if not available
		const vpWidth = viewportRect?.width ?? 800;
		const vpHeight = viewportRect?.height ?? 600;

		if (createPosition === 'random') {
			// Random position within viewport
			const centerX = (vpWidth / 2 - pan.x) / zoom;
			const centerY = (vpHeight / 2 - pan.y) / zoom;
			const offsetX = (Math.random() - 0.5) * 400;
			const offsetY = (Math.random() - 0.5) * 400;
			return { x: centerX + offsetX, y: centerY + offsetY };
		}

		// Default: center of viewport
		const centerX = (vpWidth / 2 - pan.x) / zoom;
		const centerY = (vpHeight / 2 - pan.y) / zoom;
		return { x: centerX, y: centerY };
	};

	// Handle selection
	const handleSelect = (option: NodeTypeOption) => {
		if (!graphId) {
			debug.warn('No graphId available');
			return;
		}

		const position = getCreatePosition();
		const width = option.defaultWidth ?? 200;
		const height = option.defaultHeight ?? 150;

		createNode.mutate(
			{
				graph_id: graphId,
				label: option.label || option.type,
				node_type: option.type,
				configuration: null,
				ui_properties: {
					x: position.x - width / 2, // Center the node
					y: position.y - height / 2,
					width,
					height,
				},
			},
			{
				onSuccess: (data) => {
					onNodeCreated?.(data.id, option.type);
				},
			},
		);

		if (clearOnCreate) {
			setSearchQuery('');
		}
		setIsOpen(false);
	};

	// Keyboard navigation
	const handleKeyDown = (e: React.KeyboardEvent) => {
		if (!isOpen) {
			if (e.key === 'ArrowDown' || e.key === 'Enter') {
				setIsOpen(true);
				e.preventDefault();
			}
			return;
		}

		switch (e.key) {
			case 'ArrowDown':
				e.preventDefault();
				setHighlightedIndex((prev) => Math.min(prev + 1, filteredTypes.length - 1));
				break;
			case 'ArrowUp':
				e.preventDefault();
				setHighlightedIndex((prev) => Math.max(prev - 1, 0));
				break;
			case 'Enter':
				e.preventDefault();
				if (filteredTypes[highlightedIndex]) {
					handleSelect(filteredTypes[highlightedIndex]);
				}
				break;
			case 'Escape':
				e.preventDefault();
				setIsOpen(false);
				break;
		}
	};

	// Reset highlighted index when filtered list changes
	useEffect(() => {
		setHighlightedIndex(0);
	}, [filteredTypes.length]);

	// Scroll highlighted item into view
	useEffect(() => {
		if (isOpen && listRef.current) {
			const highlightedElement = listRef.current.children[highlightedIndex] as HTMLElement;
			highlightedElement?.scrollIntoView({ block: 'nearest' });
		}
	}, [highlightedIndex, isOpen]);

	// Close on click outside
	useEffect(() => {
		const handleClickOutside = (e: MouseEvent) => {
			if (inputRef.current && !inputRef.current.parentElement?.contains(e.target as Node)) {
				setIsOpen(false);
			}
		};

		document.addEventListener('mousedown', handleClickOutside);
		return () => document.removeEventListener('mousedown', handleClickOutside);
	}, []);

	return (
		<div className={className} style={{ ...styles.container, ...style }}>
			<ComboboxSearch
				inputRef={inputRef}
				value={searchQuery}
				onChange={(v) => { setSearchQuery(v); setIsOpen(true); }}
				onFocus={() => setIsOpen(true)}
				onKeyDown={handleKeyDown}
				placeholder={placeholder}
				disabled={disabled}
				isOpen={isOpen}
			/>

			{isOpen && filteredTypes.length > 0 && (
				<ul ref={listRef} style={styles.dropdown} role="listbox">
					{filteredTypes.map((option, index) => (
						<ComboboxOption
							key={option.type}
							type={option.type}
							label={option.label || option.type}
							icon={option.icon}
							description={option.description}
							highlighted={index === highlightedIndex}
							onClick={() => handleSelect(option)}
							onMouseEnter={() => setHighlightedIndex(index)}
						/>
					))}
				</ul>
			)}

			{isOpen && filteredTypes.length === 0 && (
				<div style={styles.emptyState}>No node types found</div>
			)}
		</div>
	);
}

// Helper to format type names into labels
function formatTypeLabel(type: string): string {
	return type
		.split(/[-_]/)
		.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
		.join(' ');
}

const styles: Record<string, React.CSSProperties> = {
	container: {
		position: 'relative',
		width: '200px',
	},
	input: {
		width: '100%',
		padding: '8px 12px',
		fontSize: '14px',
		border: '1px solid #ddd',
		borderRadius: '6px',
		outline: 'none',
		backgroundColor: '#fff',
	},
	dropdown: {
		position: 'absolute',
		top: '100%',
		left: 0,
		right: 0,
		marginTop: '4px',
		padding: '4px 0',
		backgroundColor: '#fff',
		border: '1px solid #ddd',
		borderRadius: '6px',
		boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
		maxHeight: '240px',
		overflowY: 'auto',
		zIndex: 1000,
		listStyle: 'none',
	},
	option: {
		display: 'flex',
		alignItems: 'center',
		gap: '8px',
		padding: '8px 12px',
		cursor: 'pointer',
		transition: 'background-color 0.1s',
	},
	optionHighlighted: {
		backgroundColor: '#f0f0f0',
	},
	icon: {
		fontSize: '16px',
		width: '20px',
		textAlign: 'center',
	},
	optionContent: {
		display: 'flex',
		flexDirection: 'column',
		gap: '2px',
	},
	optionLabel: {
		fontSize: '14px',
		fontWeight: 500,
	},
	optionDescription: {
		fontSize: '12px',
		color: '#666',
	},
	emptyState: {
		position: 'absolute',
		top: '100%',
		left: 0,
		right: 0,
		marginTop: '4px',
		padding: '12px',
		backgroundColor: '#fff',
		border: '1px solid #ddd',
		borderRadius: '6px',
		boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
		color: '#666',
		fontSize: '14px',
		textAlign: 'center',
	},
};

export default NodeTypeCombobox;
