import React, { useState, useRef, useEffect, useId } from 'react';
import { createPortal } from 'react-dom';
import { Calendar as CalendarIcon, ChevronLeft, ChevronRight, ChevronDown } from 'lucide-react';
import { Button } from './Button';
import { Ripple } from './Ripple';

interface DatePickerProps {
    value: string; // YYYY-MM-DD
    onChange: (value: string) => void;
    label: string;
    placeholder?: string;
    icon?: React.ReactNode;
    disabled?: boolean;
    testId?: string;
    maxDate?: Date; // Optional maximum date constraint
}

export const DatePicker: React.FC<DatePickerProps> = ({
    value,
    onChange,
    label,
    placeholder = 'Select date',
    icon = <CalendarIcon size={16} />,
    disabled = false,
    testId,
    maxDate
}) => {
    const id = useId();
    const [isOpen, setIsOpen] = useState(false);
    const [viewDate, setViewDate] = useState(value ? new Date(value) : new Date());
    const [popoverPos, setPopoverPos] = useState({ top: 0, left: 0, width: 320 });
    const containerRef = useRef<HTMLDivElement>(null);
    const popoverRef = useRef<HTMLDivElement>(null);

    // MD3 Enhancement: Calendar view and text input states
    const [calendarView, setCalendarView] = useState<'days' | 'months' | 'years'>('days');
    const [textInputValue, setTextInputValue] = useState('');
    const [textInputError, setTextInputError] = useState('');

    // Update popover position when opening or when window resizes
    const updatePosition = () => {
        if (containerRef.current) {
            const rect = containerRef.current.getBoundingClientRect();
            const scrollX = window.scrollX;
            const scrollY = window.scrollY;

            // Try to align with the right side of the input for better visibility
            let left = rect.left + rect.width - 320 + scrollX;
            // But don't go off-screen to the left
            if (left < scrollX + 16) {
                left = rect.left + scrollX;
            }

            setPopoverPos({
                top: rect.bottom + scrollY + 4,
                left: left,
                width: 320
            });
        }
    };

    useEffect(() => {
        if (isOpen) {
            updatePosition();
            window.addEventListener('resize', updatePosition);
            window.addEventListener('scroll', updatePosition, true);
        }
        return () => {
            window.removeEventListener('resize', updatePosition);
            window.removeEventListener('scroll', updatePosition, true);
        };
    }, [isOpen]);

    // Ensure viewDate is valid
    useEffect(() => {
        if (value) {
            const date = new Date(value);
            if (!isNaN(date.getTime())) {
                setViewDate(date);
            }
        }
    }, [value]);

    useEffect(() => {
        const handleClickOutside = (event: MouseEvent) => {
            if (
                containerRef.current && !containerRef.current.contains(event.target as Node) &&
                popoverRef.current && !popoverRef.current.contains(event.target as Node)
            ) {
                setIsOpen(false);
            }
        };

        if (isOpen) {
            document.addEventListener('mousedown', handleClickOutside);
        } else {
            document.removeEventListener('mousedown', handleClickOutside);
        }

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

    const handleInputClick = () => {
        if (!disabled) {
            const nextOpen = !isOpen;
            if (nextOpen) {
                updatePosition();
                // MD3 Enhancement: Reset to days view when opening
                setCalendarView('days');
                setTextInputValue('');
                setTextInputError('');
            }
            setIsOpen(nextOpen);
        }
    };

    const handlePrevMonth = () => {
        setViewDate(new Date(viewDate.getFullYear(), viewDate.getMonth() - 1, 1));
    };

    const handleNextMonth = () => {
        setViewDate(new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 1));
    };

    const handleDateSelect = (day: number) => {
        const selectedDate = new Date(viewDate.getFullYear(), viewDate.getMonth(), day);
        const year = selectedDate.getFullYear();
        const month = String(selectedDate.getMonth() + 1).padStart(2, '0');
        const d = String(selectedDate.getDate()).padStart(2, '0');
        onChange(`${year}-${month}-${d}`);
        setIsOpen(false);
    };

    // MD3 Enhancement: Year selection handler
    const handleYearSelect = (year: number) => {
        setViewDate(new Date(year, viewDate.getMonth(), 1));
        setCalendarView('days');
    };

    // MD3 Enhancement: Text input validation and handling
    const validateDateInput = (input: string): boolean => {
        // Check format YYYY-MM-DD
        const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
        if (!dateRegex.test(input)) {
            setTextInputError('Format: YYYY-MM-DD');
            return false;
        }

        // Check if date is valid
        const date = new Date(input);
        if (isNaN(date.getTime())) {
            setTextInputError('Invalid date');
            return false;
        }

        // Check if the input matches the parsed date (catches invalid dates like 2023-02-30)
        const [year, month, day] = input.split('-').map(Number);
        if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
            setTextInputError('Invalid date');
            return false;
        }

        // Check against maxDate constraint
        if (maxDate && date > maxDate) {
            setTextInputError('Date cannot be in the future');
            return false;
        }

        setTextInputError('');
        return true;
    };

    const handleTextInputSubmit = () => {
        if (validateDateInput(textInputValue)) {
            onChange(textInputValue);
            setIsOpen(false);
            setTextInputValue('');
        }
    };

    const daysInMonth = (year: number, month: number) => new Date(year, month + 1, 0).getDate();
    const firstDayOfMonth = (year: number, month: number) => new Date(year, month, 1).getDay();


    const renderCalendar = () => {
        const year = viewDate.getFullYear();
        const month = viewDate.getMonth();
        const daysCount = daysInMonth(year, month);
        const startingDay = firstDayOfMonth(year, month);
        const monthName = viewDate.toLocaleString('en-US', { month: 'long' });
        const shortMonthName = viewDate.toLocaleString('en-US', { month: 'short' });

        // Format selected date for header display
        const selectedDate = value ? new Date(value) : null;
        const headerDateText = selectedDate
            ? selectedDate.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' })
            : 'Select date';

        // Render year selection view
        const renderYearsView = () => {
            const currentYear = new Date().getFullYear();
            const maxYear = maxDate ? maxDate.getFullYear() : currentYear + 100;
            const years = [];
            // Generate years from current year going backwards (recent first)
            for (let y = maxYear; y >= currentYear - 100; y--) {
                years.push(y);
            }

            const selectedYear = selectedDate?.getFullYear();

            return (
                <div className="h-64 overflow-y-auto">
                    <div className="grid grid-cols-3 gap-2 p-2">
                        {years.map(y => (
                            <button
                                key={y}
                                type="button"
                                onClick={() => handleYearSelect(y)}
                                className={`
                                    relative py-3 rounded-lg text-sm transition-colors
                                    ${y === year
                                        ? 'bg-primary text-on-primary font-bold'
                                        : y === currentYear
                                            ? 'text-primary border border-primary font-medium'
                                            : 'text-on-surface hover:bg-surface-container-high'
                                    }
                                `}
                            >
                                <Ripple color={y === year ? 'rgba(255,255,255,0.3)' : 'rgba(var(--primary-rgb), 0.1)'} />
                                {y}
                            </button>
                        ))}
                    </div>
                </div>
            );
        };

        // Render month selection view
        const renderMonthsView = () => {
            const months = [
                'January', 'February', 'March', 'April', 'May', 'June',
                'July', 'August', 'September', 'October', 'November', 'December'
            ];

            return (
                <div className="h-64 overflow-y-auto">
                    <div className="space-y-1">
                        {months.map((monthLabel, i) => (
                            <button
                                key={i}
                                type="button"
                                onClick={() => {
                                    setViewDate(new Date(year, i, 1));
                                    setCalendarView('days');
                                }}
                                className={`
                                    relative w-full text-left px-4 py-3 rounded-lg text-sm transition-colors flex items-center gap-2
                                    ${i === month
                                        ? 'bg-secondary-container text-on-secondary-container font-medium'
                                        : 'text-on-surface hover:bg-surface-container-high'
                                    }
                                `}
                            >
                                {i === month && (
                                    <svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                                        <polyline points="20 6 9 17 4 12" />
                                    </svg>
                                )}
                                <span className={i === month ? '' : 'ml-7'}>{monthLabel}</span>
                            </button>
                        ))}
                    </div>
                </div>
            );
        };

        // Render days view
        const renderDaysView = () => {
            const days = [];
            for (let i = 0; i < startingDay; i++) {
                days.push(<div key={`empty-${i}`} className="w-10 h-10" />);
            }

            const isSelected = (d: number) => {
                return selectedDate &&
                    selectedDate.getFullYear() === year &&
                    selectedDate.getMonth() === month &&
                    selectedDate.getDate() === d;
            };

            const today = new Date();
            const isToday = (d: number) => {
                return today.getFullYear() === year &&
                    today.getMonth() === month &&
                    today.getDate() === d;
            };

            // Check if a date is disabled (after maxDate)
            const isDisabled = (d: number) => {
                if (!maxDate) return false;
                const checkDate = new Date(year, month, d);
                return checkDate > maxDate;
            };

            for (let d = 1; d <= daysCount; d++) {
                const disabled = isDisabled(d);
                days.push(
                    <button
                        key={d}
                        type="button"
                        onClick={() => !disabled && handleDateSelect(d)}
                        disabled={disabled}
                        className={`
                            relative w-10 h-10 rounded-full flex items-center justify-center text-sm transition-colors
                            ${disabled
                                ? 'text-on-surface/30 cursor-not-allowed'
                                : isSelected(d)
                                    ? 'bg-primary text-on-primary font-bold'
                                    : isToday(d)
                                        ? 'text-primary border border-primary font-medium'
                                        : 'text-on-surface hover:bg-surface-container-high'
                            }
                        `}
                    >
                        {!disabled && <Ripple color={isSelected(d) ? 'rgba(255,255,255,0.3)' : 'rgba(var(--primary-rgb), 0.1)'} />}
                        {d}
                    </button>
                );
            }

            return (
                <>
                    <div className="flex items-center justify-between mb-4">
                        {/* Month navigation */}
                        <div className="flex items-center gap-1">
                            <Button variant="ghost" size="icon" onClick={handlePrevMonth} className="h-8 w-8">
                                <ChevronLeft size={18} />
                            </Button>
                            <button
                                type="button"
                                onClick={() => setCalendarView('months')}
                                className="flex items-center gap-1 hover:bg-surface-container rounded px-2 py-1 transition-colors text-sm font-medium text-on-surface"
                            >
                                {shortMonthName}
                                <ChevronDown size={14} />
                            </button>
                            <Button variant="ghost" size="icon" onClick={handleNextMonth} className="h-8 w-8">
                                <ChevronRight size={18} />
                            </Button>
                        </div>

                        {/* Year navigation */}
                        <div className="flex items-center gap-1">
                            <Button variant="ghost" size="icon" onClick={() => setViewDate(new Date(viewDate.getFullYear() - 1, viewDate.getMonth(), 1))} className="h-8 w-8">
                                <ChevronLeft size={18} />
                            </Button>
                            <button
                                type="button"
                                onClick={() => setCalendarView('years')}
                                className="flex items-center gap-1 hover:bg-surface-container rounded px-2 py-1 transition-colors text-sm font-medium text-on-surface"
                            >
                                {year}
                                <ChevronDown size={14} />
                            </button>
                            <Button variant="ghost" size="icon" onClick={() => setViewDate(new Date(viewDate.getFullYear() + 1, viewDate.getMonth(), 1))} className="h-8 w-8">
                                <ChevronRight size={18} />
                            </Button>
                        </div>
                    </div>

                    <div className="grid grid-cols-7 gap-1 mb-2">
                        {['S', 'M', 'T', 'W', 'T', 'F', 'S'].map((day, i) => (
                            <div key={i} className="text-center text-[10px] font-bold text-on-surface-variant h-8 flex items-center justify-center uppercase tracking-wider">
                                {day}
                            </div>
                        ))}
                    </div>

                    <div className="grid grid-cols-7 gap-1">
                        {days}
                    </div>
                </>
            );
        };

        const calendarContent = (
            <div
                ref={popoverRef}
                style={{
                    position: 'absolute',
                    top: popoverPos.top,
                    left: popoverPos.left,
                    zIndex: 9999,
                }}
                className="p-4 w-[320px] bg-surface-container-high rounded-2xl shadow-xl border border-outline-variant animate-in fade-in zoom-in duration-200 origin-top"
            >
                {/* Calendar content based on view */}
                {calendarView === 'years' ? (
                    renderYearsView()
                ) : calendarView === 'months' ? (
                    renderMonthsView()
                ) : (
                    renderDaysView()
                )}

                {/* Footer with Cancel button */}
                <div className="mt-4 pt-2 border-t border-outline-variant flex justify-end gap-2">
                    <Button variant="ghost" size="sm" onClick={() => setIsOpen(false)}>
                        Cancel
                    </Button>
                </div>
            </div>
        );

        return createPortal(calendarContent, document.body);
    };

    // Display value in same format as editing (YYYY-MM-DD)
    const formattedValue = value || '';

    return (
        <div className="relative w-full" ref={containerRef}>
            <div
                className={`
                    relative group bg-surface-container-high rounded-t-[4px] border-b transition-all min-h-[56px]
                    ${isOpen ? 'border-primary border-b-2' : 'border-on-surface-variant hover:bg-on-surface/10'}
                    ${disabled ? 'opacity-50 cursor-not-allowed' : ''}
                `}
            >
                <label htmlFor={id} className={`
                    absolute top-2 left-4 text-label-sm font-medium transition-colors flex items-center gap-1
                    ${isOpen ? 'text-primary' : 'text-on-surface-variant'}
                `}>
                    {icon} {label}
                </label>

                <input
                    id={id}
                    type="text"
                    value={textInputValue || formattedValue}
                    onChange={(e) => {
                        setTextInputValue(e.target.value);
                        setTextInputError('');
                    }}
                    onFocus={() => {
                        // Initialize text input with current value and open calendar
                        setTextInputValue(value || '');
                        if (!disabled && !isOpen) {
                            updatePosition();
                            setCalendarView('days');
                            setIsOpen(true);
                        }
                    }}
                    onBlur={() => {
                        // Validate and apply on blur
                        if (textInputValue && textInputValue !== value) {
                            if (validateDateInput(textInputValue)) {
                                onChange(textInputValue);
                                setTextInputValue('');
                            }
                        } else if (!textInputValue) {
                            setTextInputValue('');
                            setTextInputError('');
                        }
                    }}
                    onKeyDown={(e) => {
                        if (e.key === 'Enter') {
                            if (textInputValue && validateDateInput(textInputValue)) {
                                onChange(textInputValue);
                                setTextInputValue('');
                                setIsOpen(false);
                                (e.target as HTMLInputElement).blur();
                            } else if (!textInputValue) {
                                setIsOpen(false);
                                (e.target as HTMLInputElement).blur();
                            }
                        }
                        if (e.key === 'Escape') {
                            setIsOpen(false);
                            setTextInputValue('');
                            setTextInputError('');
                            (e.target as HTMLInputElement).blur();
                        }
                    }}
                    placeholder={placeholder}
                    disabled={disabled}
                    className="w-full h-[56px] pt-5 pb-1 pl-4 pr-10 text-body-lg text-on-surface bg-transparent focus:outline-none"
                />

                {textInputError && (
                    <span className="absolute bottom-[-18px] left-4 text-xs text-error">{textInputError}</span>
                )}

                <button
                    type="button"
                    onClick={handleInputClick}
                    disabled={disabled}
                    className="absolute right-3 top-1/2 -translate-y-1/2 text-on-surface-variant hover:text-primary p-1 rounded-full transition-colors"
                >
                    <CalendarIcon size={20} />
                </button>
            </div>


            {/* Hidden input for Playwright test compatibility */}
            <input
                type="date"
                data-testid={testId}
                value={value}
                onChange={(e) => onChange(e.target.value)}
                className="sr-only"
                style={{
                    position: 'absolute',
                    width: '1px',
                    height: '1px',
                    padding: '0',
                    margin: '-1px',
                    overflow: 'hidden',
                    clip: 'rect(0, 0, 0, 0)',
                    whiteSpace: 'nowrap',
                    borderWidth: '0',
                    pointerEvents: 'none',
                    opacity: 0
                }}
                tabIndex={-1}
                aria-hidden="true"
            />

            {isOpen && renderCalendar()}
        </div>
    );
};
