import React, { useState, useRef, useEffect, useLayoutEffect } from 'react';
import ReactDOM from 'react-dom';
import { sortByProperty } from '../utils/sort-utils';

// Default prefix for TMS username search
const TMS_USERNAME_PREFIX = 'DKI_';

// Simple cache for user search results
const userCache = new Map<string, TmsUser[]>();

interface TmsUser {
    email: string;
    name: string;
}

interface UsernameAutocompleteProps {
    value: string;
    onChange: (value: string) => void;
    onUserSelect: (username: string) => void;
    disabled?: boolean;
    placeholder?: string;
    rows?: number;
    onHeightChange?: (heightPx: number) => void;
}

const UsernameAutocomplete: React.FC<UsernameAutocompleteProps> = ({
    value,
    onChange,
    onUserSelect,
    disabled = false,
    placeholder = '',
    rows = 5,
    onHeightChange,
}) => {
    // Use internal state for instant typing, sync to parent via onChange
    const [internalValue, setInternalValue] = useState(value);
    const [suggestions, setSuggestions] = useState<TmsUser[]>([]);
    const [showSuggestions, setShowSuggestions] = useState(false);
    const [selectedIndex, setSelectedIndex] = useState(-1);
    const [isLoading, setIsLoading] = useState(false);
    const [justSelected, setJustSelected] = useState(false);
    const textareaRef = useRef<HTMLTextAreaElement>(null);
    const suggestionsRef = useRef<HTMLDivElement | null>(null);
    const [portalStyle, setPortalStyle] = useState<React.CSSProperties | null>(null);
    const debounceTimerRef = useRef<number>(0);

    // Sync external value changes to internal state
    useEffect(() => {
        setInternalValue(value);
    }, [value]);

    // report textarea height to parent so they can keep other inputs in sync
    const onHeightChangeRef = useRef(onHeightChange);
    onHeightChangeRef.current = onHeightChange;

    useEffect(() => {
        const ta = textareaRef.current;
        if (!ta) return;
        const obs = new ResizeObserver(entries => {
            if (!entries || !entries.length) return;
            const h = (entries[0].target as HTMLElement).offsetHeight;
            if (typeof onHeightChangeRef.current === 'function') onHeightChangeRef.current(h);
        });
        obs.observe(ta);
        // report initial size
        if (typeof onHeightChangeRef.current === 'function') onHeightChangeRef.current(ta.offsetHeight);
        return () => obs.disconnect();
    }, []);

    // Get current line content (word being typed)
    const getCurrentWord = () => {
        if (!textareaRef.current) return '';
        const textarea = textareaRef.current;
        const text = textarea.value;
        const cursorPos = textarea.selectionStart;
        const beforeCursor = text.substring(0, cursorPos);
        const lines = beforeCursor.split('\n');
        const currentLine = lines[lines.length - 1];
        return currentLine;
    };

    // Get all existing usernames from textarea (excluding current line being typed)
    const getExistingUsernames = (): Set<string> => {
        if (!textareaRef.current) return new Set();
        const textarea = textareaRef.current;
        const text = textarea.value;
        const cursorPos = textarea.selectionStart;
        const beforeCursor = text.substring(0, cursorPos);
        const afterCursor = text.substring(cursorPos);

        const linesBefore = beforeCursor.split('\n');
        const currentLineIndex = linesBefore.length - 1;

        // Get all lines except the current one being typed
        const allLines = text.split('\n');
        const existingNames = new Set<string>();
        allLines.forEach((line, index) => {
            const trimmed = line.trim().toLowerCase();
            if (trimmed && index !== currentLineIndex) {
                existingNames.add(trimmed);
            }
        });
        return existingNames;
    };

    // Fetch suggestions from TMS API (only DKI_ users) with cache
    const fetchSuggestions = async (query: string) => {
        // Don't fetch if just selected a suggestion
        if (justSelected) return;

        if (query.length < 1) {
            setSuggestions([]);
            setShowSuggestions(false);
            return;
        }

        const cacheKey = query.toLowerCase();

        // Check cache first
        if (userCache.has(cacheKey)) {
            const cached = userCache.get(cacheKey)!;
            const existingUsernames = getExistingUsernames();
            const filteredUsers = cached.filter(u => !existingUsernames.has(u.name.toLowerCase()));
            setSuggestions(filteredUsers);
            setShowSuggestions(filteredUsers.length > 0);
            setSelectedIndex(filteredUsers.length > 0 ? 0 : -1);
            return;
        }

        setIsLoading(true);
        try {
            // Search with original query
            const response = await fetch('/api/user/search', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ query }),
            });
            const data = await response.json();
            if (data.success && Array.isArray(data.data)) {
                // Filter: only DKI_ users, then sort by name
                const usersData = data.data as TmsUser[];
                const dkiUsers = sortByProperty(
                    usersData.filter((user) => user.name.toUpperCase().includes(TMS_USERNAME_PREFIX)),
                    (user) => user.name
                );

                // Cache the result
                userCache.set(cacheKey, dkiUsers);

                // Filter out existing usernames for display
                const existingUsernames = getExistingUsernames();
                const filteredUsers = dkiUsers.filter(u => !existingUsernames.has(u.name.toLowerCase()));
                setSuggestions(filteredUsers);
                setShowSuggestions(filteredUsers.length > 0);
                setSelectedIndex(filteredUsers.length > 0 ? 0 : -1);
            }
        } catch (error) {
            console.error('Error fetching suggestions:', error);
            setSuggestions([]);
        } finally {
            setIsLoading(false);
        }
    };

    // Handle input change - update internal state immediately, debounce parent update
    const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
        const newValue = e.target.value;
        setInternalValue(newValue); // Instant update for smooth typing

        // Clear previous timer
        window.clearTimeout(debounceTimerRef.current);

        // Debounce: update parent and fetch suggestions after 100ms
        debounceTimerRef.current = window.setTimeout(() => {
            onChange(newValue); // Sync to parent
            const currentWord = getCurrentWord();
            fetchSuggestions(currentWord);
        }, 100);
    };

    // Cleanup debounce timer on unmount
    useEffect(() => {
        return () => window.clearTimeout(debounceTimerRef.current);
    }, []);

    // Handle keyboard navigation
    const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
        if (!showSuggestions || suggestions.length === 0) {
            if (e.key === 'ArrowDown' && e.ctrlKey) {
                e.preventDefault();
                setShowSuggestions(true);
            }
            return;
        }

        switch (e.key) {
            case 'ArrowDown':
                e.preventDefault();
                setSelectedIndex((prev) => (prev + 1) % suggestions.length);
                break;
            case 'ArrowUp':
                e.preventDefault();
                setSelectedIndex((prev) => (prev - 1 + suggestions.length) % suggestions.length);
                break;
            case 'Enter':
                if (selectedIndex >= 0) {
                    e.preventDefault();
                    selectSuggestion(suggestions[selectedIndex]);
                }
                break;
            case 'Escape':
                e.preventDefault();
                setShowSuggestions(false);
                setSelectedIndex(-1);
                break;
            default:
                break;
        }
    };

    // Select suggestion and replace current line with user's name
    const selectSuggestion = (user: TmsUser) => {
        if (!textareaRef.current) return;

        const textarea = textareaRef.current;
        const text = internalValue;
        const cursorPos = textarea.selectionStart;
        const beforeCursor = text.substring(0, cursorPos);
        const afterCursor = text.substring(cursorPos);

        const lines = beforeCursor.split('\n');
        const currentLineIndex = lines.length - 1;
        lines[currentLineIndex] = user.name; // Use name as the selected value

        const newText = lines.join('\n') + afterCursor;
        setInternalValue(newText);
        onChange(newText);

        // Hide suggestions and set flag to prevent re-showing
        setShowSuggestions(false);
        setSelectedIndex(-1);
        setSuggestions([]);
        setJustSelected(true);

        // Focus back to textarea and move cursor to end of suggestion
        setTimeout(() => {
            textarea.focus();
            const newCursorPos = lines.join('\n').length;
            textarea.setSelectionRange(newCursorPos, newCursorPos);
            // Reset flag after a short delay
            setTimeout(() => setJustSelected(false), 200);
        }, 0);
    };

    // Close suggestions when clicking outside
    useEffect(() => {
        const handleClickOutside = (e: MouseEvent) => {
            const sugEl = suggestionsRef.current;
            const taEl = textareaRef.current;
            if (sugEl && !sugEl.contains(e.target as Node)) {
                if (taEl && !taEl.contains(e.target as Node)) {
                    setShowSuggestions(false);
                }
            }
        };

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

    // compute portal position based on textarea bounding rect
    const updatePortalPosition = () => {
        const ta = textareaRef.current;
        if (!ta) return;
        const rect = ta.getBoundingClientRect();
        const top = rect.bottom + window.scrollY;
        const left = rect.left + window.scrollX;
        const width = rect.width;
        setPortalStyle({ position: 'absolute', top: `${top}px`, left: `${left}px`, width: `${width}px`, zIndex: 99999 });
    };

    useLayoutEffect(() => {
        if (showSuggestions) updatePortalPosition();
    }, [showSuggestions, suggestions]);

    useEffect(() => {
        const onScroll = () => { if (showSuggestions) updatePortalPosition(); };
        const onResize = () => { if (showSuggestions) updatePortalPosition(); };
        window.addEventListener('scroll', onScroll, true);
        window.addEventListener('resize', onResize);
        return () => {
            window.removeEventListener('scroll', onScroll, true);
            window.removeEventListener('resize', onResize);
        };
    }, [showSuggestions]);

    return (
        <div className="relative">
            <textarea
                ref={textareaRef}
                value={internalValue}
                onChange={handleInputChange}
                onKeyDown={handleKeyDown}
                className="bg-slate-900/50 border border-slate-700 text-slate-100 text-sm rounded-lg focus:ring-indigo-500 focus:border-indigo-500 block w-full p-2.5 transition-colors duration-200 resize-y min-h-32"
                placeholder={placeholder}
                disabled={disabled}
                rows={rows}
            />

            {showSuggestions && suggestions.length > 0 && portalStyle && ReactDOM.createPortal(
                <div
                    ref={suggestionsRef}
                    style={portalStyle}
                >
                    <div className="bg-slate-800 border border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto" style={{ maxHeight: '240px' }}>
                        {suggestions.map((user, index) => (
                            <div
                                key={user.email}
                                onClick={() => selectSuggestion(user)}
                                className={`px-3 py-2 cursor-pointer transition-colors ${index === selectedIndex
                                    ? 'bg-indigo-600 text-white'
                                    : 'text-slate-200 hover:bg-slate-700'
                                    }`}
                            >
                                <div className="font-medium">{user.name}</div>
                                <div className="text-xs text-slate-400">{user.email}</div>
                            </div>
                        ))}
                    </div>
                </div>, document.body
            )}

            {isLoading && (
                <div className="absolute right-2 top-2 text-xs text-slate-400">
                    <span className="animate-pulse">...</span>
                </div>
            )}
        </div>
    );
};

export default UsernameAutocomplete;
