import React, { forwardRef, useState, useRef, useEffect, useMemo } from 'react';
import { clsx } from 'clsx';
import { useTranslation } from 'react-i18next';

export interface DatePickerProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'> {
  label?: string;
  error?: string;
  helperText?: string;
  placeholder?: string;
  size?: 'sm' | 'md' | 'lg';
  variant?: 'outline' | 'filled' | 'unstyled';
  value?: Date | null;
  defaultValue?: Date | null;
  onChange?: (date: Date | null) => void;
  onBlur?: (event: React.FocusEvent<HTMLInputElement>) => void;
  onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
  isRequired?: boolean;
  isInvalid?: boolean;
  format?: string;
  locale?: 'es' | 'en';
  minDate?: Date;
  maxDate?: Date;
  disabledDates?: Date[];
  disablePast?: boolean;
  disableFuture?: boolean;
  showTime?: boolean;
  showToday?: boolean;
  showClear?: boolean;
  closeOnSelect?: boolean;
  firstDayOfWeek?: 0 | 1; // 0 = Sunday, 1 = Monday
  monthsToShow?: number;
  yearRange?: number;
  renderDay?: (date: Date, isSelected: boolean, isToday: boolean, isDisabled: boolean) => React.ReactNode;
  renderHeader?: (date: Date, onPrevMonth: () => void, onNextMonth: () => void) => React.ReactNode;
}

const DatePicker = forwardRef<HTMLInputElement, DatePickerProps>(({
  label,
  error,
  helperText,
  placeholder,
  size = 'md',
  variant = 'outline',
  value,
  defaultValue,
  onChange,
  onBlur,
  onFocus,
  isRequired = false,
  isInvalid = false,
  format = 'dd/mm/yyyy',
  locale = 'es',
  minDate,
  maxDate,
  disabledDates = [],
  disablePast = false,
  disableFuture = false,
  showTime = false,
  showToday = true,
  showClear = true,
  closeOnSelect = true,
  firstDayOfWeek = 1,
  monthsToShow = 1,
  yearRange = 100,
  renderDay,
  renderHeader,
  className,
  id,
  disabled,
  ...props
}, ref) => {
  const { t } = useTranslation(['ui']);
  const datePickerId = id || `datepicker-${Math.random().toString(36).substr(2, 9)}`;
  const [internalValue, setInternalValue] = useState<Date | null>(
    value !== undefined ? value : defaultValue || null
  );
  const [isOpen, setIsOpen] = useState(false);
  const [currentMonth, setCurrentMonth] = useState(
    (value || defaultValue || new Date()).getMonth()
  );
  const [currentYear, setCurrentYear] = useState(
    (value || defaultValue || new Date()).getFullYear()
  );
  const [inputValue, setInputValue] = useState('');
  const [timeValue, setTimeValue] = useState('00:00');

  const containerRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  
  // Use controlled value if provided, otherwise use internal state
  const currentValue = value !== undefined ? value : internalValue;

  // Localization
  const translations = {
    es: {
      months: [
        'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
        'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'
      ],
      weekdays: ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb'],
      today: 'Hoy',
      clear: 'Limpiar',
    },
    en: {
      months: [
        'January', 'February', 'March', 'April', 'May', 'June',
        'July', 'August', 'September', 'October', 'November', 'December'
      ],
      weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
      today: 'Today',
      clear: 'Clear',
    },
  };

  const localT = translations[locale];

  // Format date for display
  const formatDate = (date: Date | null): string => {
    if (!date) return '';
    
    const day = date.getDate().toString().padStart(2, '0');
    const month = (date.getMonth() + 1).toString().padStart(2, '0');
    const year = date.getFullYear().toString();
    const hours = date.getHours().toString().padStart(2, '0');
    const minutes = date.getMinutes().toString().padStart(2, '0');
    
    let formatted = format
      .replace(/dd/g, day)
      .replace(/mm/g, month)
      .replace(/yyyy/g, year);
      
    if (showTime) {
      formatted += ` ${hours}:${minutes}`;
    }
    
    return formatted;
  };

  // Parse date from string
  const parseDate = (dateString: string): Date | null => {
    if (!dateString) return null;
    
    try {
      const parts = dateString.split(/[/\-\s:]/);
      
      if (format.startsWith('dd/mm/yyyy')) {
        const day = parseInt(parts[0], 10);
        const month = parseInt(parts[1], 10) - 1;
        const year = parseInt(parts[2], 10);
        
        if (!isNaN(day) && !isNaN(month) && !isNaN(year)) {
          const date = new Date(year, month, day);
          
          if (showTime && parts.length >= 5) {
            const hours = parseInt(parts[3], 10) || 0;
            const minutes = parseInt(parts[4], 10) || 0;
            date.setHours(hours, minutes);
          }
          
          return date;
        }
      }
      
      return null;
    } catch {
      return null;
    }
  };

  // Check if date is disabled
  const isDateDisabled = (date: Date): boolean => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    
    const checkDate = new Date(date);
    checkDate.setHours(0, 0, 0, 0);
    
    if (disablePast && checkDate < today) return true;
    if (disableFuture && checkDate > today) return true;
    if (minDate && checkDate < minDate) return true;
    if (maxDate && checkDate > maxDate) return true;
    
    return disabledDates.some(disabledDate => {
      const disabled = new Date(disabledDate);
      disabled.setHours(0, 0, 0, 0);
      return disabled.getTime() === checkDate.getTime();
    });
  };

  // Check if date is today
  const isToday = (date: Date): boolean => {
    const today = new Date();
    return date.getDate() === today.getDate() &&
           date.getMonth() === today.getMonth() &&
           date.getFullYear() === today.getFullYear();
  };

  // Check if date is selected
  const isSelected = (date: Date): boolean => {
    if (!currentValue) return false;
    return date.getDate() === currentValue.getDate() &&
           date.getMonth() === currentValue.getMonth() &&
           date.getFullYear() === currentValue.getFullYear();
  };

  // Get calendar days for current month
  const getCalendarDays = useMemo(() => {
    const firstDay = new Date(currentYear, currentMonth, 1);
    const lastDay = new Date(currentYear, currentMonth + 1, 0);
    const startDate = new Date(firstDay);
    const endDate = new Date(lastDay);

    // Adjust for first day of week
    const dayOfWeek = firstDay.getDay();
    const adjustedDayOfWeek = firstDayOfWeek === 0 ? dayOfWeek : (dayOfWeek + 6) % 7;
    startDate.setDate(1 - adjustedDayOfWeek);

    // Adjust end date to complete the grid
    const daysToAdd = 6 - ((endDate.getDay() - firstDayOfWeek + 7) % 7);
    endDate.setDate(endDate.getDate() + daysToAdd);

    const days: Date[] = [];
    const current = new Date(startDate);

    while (current <= endDate) {
      days.push(new Date(current));
      current.setDate(current.getDate() + 1);
    }

    return days;
  }, [currentMonth, currentYear, firstDayOfWeek]);

  // Handle date selection
  const handleDateSelect = (date: Date) => {
    if (isDateDisabled(date)) return;

    const newDate = new Date(date);
    
    // Preserve time if time is shown and a previous value exists
    if (showTime && currentValue) {
      newDate.setHours(currentValue.getHours(), currentValue.getMinutes());
    }

    if (value === undefined) {
      setInternalValue(newDate);
    }
    onChange?.(newDate);
    
    if (closeOnSelect && !showTime) {
      setIsOpen(false);
    }
  };

  // Handle today button click
  const handleTodayClick = () => {
    const today = new Date();
    if (showTime && currentValue) {
      today.setHours(currentValue.getHours(), currentValue.getMinutes());
    }
    
    if (value === undefined) {
      setInternalValue(today);
    }
    onChange?.(today);
    setCurrentMonth(today.getMonth());
    setCurrentYear(today.getFullYear());
    
    if (closeOnSelect && !showTime) {
      setIsOpen(false);
    }
  };

  // Handle clear button click
  const handleClear = () => {
    if (value === undefined) {
      setInternalValue(null);
    }
    onChange?.(null);
    setInputValue('');
  };

  // Handle input change
  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newValue = e.target.value;
    setInputValue(newValue);
    
    const parsedDate = parseDate(newValue);
    if (parsedDate && !isNaN(parsedDate.getTime())) {
      if (value === undefined) {
        setInternalValue(parsedDate);
      }
      onChange?.(parsedDate);
    }
  };

  // Handle time change
  const handleTimeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newTime = e.target.value;
    setTimeValue(newTime);
    
    if (currentValue) {
      const [hours, minutes] = newTime.split(':').map(num => parseInt(num, 10));
      const newDate = new Date(currentValue);
      newDate.setHours(hours, minutes);
      
      if (value === undefined) {
        setInternalValue(newDate);
      }
      onChange?.(newDate);
    }
  };

  // Handle navigation
  const handlePrevMonth = () => {
    if (currentMonth === 0) {
      setCurrentMonth(11);
      setCurrentYear(currentYear - 1);
    } else {
      setCurrentMonth(currentMonth - 1);
    }
  };

  const handleNextMonth = () => {
    if (currentMonth === 11) {
      setCurrentMonth(0);
      setCurrentYear(currentYear + 1);
    } else {
      setCurrentMonth(currentMonth + 1);
    }
  };

  // Close calendar when clicking outside
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
        setIsOpen(false);
      }
    };

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

  // Update input value when currentValue changes
  useEffect(() => {
    if (currentValue) {
      setInputValue(formatDate(currentValue));
      if (showTime) {
        setTimeValue(`${currentValue.getHours().toString().padStart(2, '0')}:${currentValue.getMinutes().toString().padStart(2, '0')}`);
      }
    } else {
      setInputValue('');
    }
  }, [currentValue, format, showTime]);

  const hasError = isInvalid || !!error;

  const baseInputClasses = [
    'w-full transition-colors duration-200',
    'focus:outline-none',
    'disabled:opacity-50 disabled:cursor-not-allowed',
    'placeholder:text-input-placeholder'
  ];

  const variantClasses = {
    outline: [
      'bg-input-bg border border-input-border',
      'focus:border-input-border-focus focus:ring-1 focus:ring-input-border-focus',
      hasError ? 'border-input-border-error focus:border-input-border-error focus:ring-input-border-error' : ''
    ],
    filled: [
      'bg-bg-secondary border border-transparent',
      'focus:bg-input-bg focus:border-input-border-focus',
      hasError ? 'border-input-border-error' : ''
    ],
    unstyled: [
      'bg-transparent border-none',
      'focus:ring-0'
    ]
  };

  const sizeClasses = {
    sm: 'h-8 px-3 text-sm',
    md: 'h-10 px-4 text-base',
    lg: 'h-12 px-5 text-lg'
  };

  const inputClasses = clsx(
    baseInputClasses,
    variantClasses[variant],
    sizeClasses[size],
    'rounded-lg pr-10',
    className
  );

  const calendarClasses = clsx(
    'absolute top-full left-0 z-50 mt-1 bg-dropdown-bg border border-dropdown-border rounded-lg shadow-lg',
    'transform transition-all duration-200 ease-out',
    {
      'opacity-0 scale-95 pointer-events-none': !isOpen,
      'opacity-100 scale-100': isOpen,
    }
  );

  return (
    <div className="w-full">
      {label && (
        <label
          htmlFor={datePickerId}
          className="block text-sm font-medium text-text-primary mb-2"
        >
          {label}
          {isRequired && (
            <span className="text-color-error ml-1">*</span>
          )}
        </label>
      )}

      <div ref={containerRef} className="relative">
        <input
          ref={ref || inputRef}
          id={datePickerId}
          type="text"
          className={inputClasses}
          placeholder={placeholder || t('ui:datepicker.placeholder', 'Seleccionar fecha')}
          value={inputValue}
          onChange={handleInputChange}
          onFocus={(e) => {
            setIsOpen(true);
            onFocus?.(e);
          }}
          onBlur={onBlur}
          disabled={disabled}
          aria-invalid={hasError}
          aria-describedby={
            error ? `${datePickerId}-error` : 
            helperText ? `${datePickerId}-helper` : 
            undefined
          }
          {...props}
        />
        
        <button
          type="button"
          className="absolute inset-y-0 right-0 flex items-center pr-3 text-text-tertiary hover:text-text-primary transition-colors duration-150"
          onClick={() => setIsOpen(!isOpen)}
          tabIndex={-1}
        >
          <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
          </svg>
        </button>

        {/* Calendar Popup */}
        <div className={calendarClasses}>
          <div className="p-4">
            {/* Header */}
            {renderHeader ? (
              renderHeader(new Date(currentYear, currentMonth), handlePrevMonth, handleNextMonth)
            ) : (
              <div className="flex items-center justify-between mb-4">
                <button
                  type="button"
                  className="p-1 text-text-tertiary hover:text-text-primary transition-colors duration-150"
                  onClick={handlePrevMonth}
                >
                  <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
                  </svg>
                </button>
                
                <div className="flex items-center gap-2">
                  <select
                    className="px-2 py-1 text-sm border border-border-primary rounded bg-input-bg focus:outline-none focus:ring-2 focus:ring-color-primary/20"
                    value={currentMonth}
                    onChange={(e) => setCurrentMonth(parseInt(e.target.value))}
                  >
                    {localT.months.map((month, index) => (
                      <option key={index} value={index}>
                        {month}
                      </option>
                    ))}
                  </select>
                  
                  <select
                    className="px-2 py-1 text-sm border border-border-primary rounded bg-input-bg focus:outline-none focus:ring-2 focus:ring-color-primary/20"
                    value={currentYear}
                    onChange={(e) => setCurrentYear(parseInt(e.target.value))}
                  >
                    {Array.from({ length: yearRange * 2 + 1 }, (_, i) => {
                      const year = new Date().getFullYear() - yearRange + i;
                      return (
                        <option key={year} value={year}>
                          {year}
                        </option>
                      );
                    })}
                  </select>
                </div>
                
                <button
                  type="button"
                  className="p-1 text-text-tertiary hover:text-text-primary transition-colors duration-150"
                  onClick={handleNextMonth}
                >
                  <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
                  </svg>
                </button>
              </div>
            )}

            {/* Weekdays */}
            <div className="grid grid-cols-7 gap-1 mb-2">
              {(firstDayOfWeek === 0 ? localT.weekdays : [...localT.weekdays.slice(1), localT.weekdays[0]]).map((day) => (
                <div key={day} className="text-xs font-medium text-text-tertiary text-center p-2">
                  {day}
                </div>
              ))}
            </div>

            {/* Calendar Grid */}
            <div className="grid grid-cols-7 gap-1">
              {getCalendarDays.map((date) => {
                const isCurrentMonth = date.getMonth() === currentMonth;
                const selected = isSelected(date);
                const today = isToday(date);
                const disabled = isDateDisabled(date);

                const dayContent = renderDay ? (
                  renderDay(date, selected, today, disabled)
                ) : (
                  <button
                    type="button"
                    className={clsx(
                      'w-8 h-8 text-sm rounded-full transition-colors duration-150 hover:bg-bg-secondary',
                      {
                        'text-text-tertiary': !isCurrentMonth,
                        'text-text-primary': isCurrentMonth && !selected && !today,
                        'bg-color-primary text-text-inverse': selected,
                        'bg-color-primary/10 text-color-primary font-medium': today && !selected,
                        'opacity-50 cursor-not-allowed': disabled,
                        'hover:bg-bg-secondary': !disabled && !selected,
                      }
                    )}
                    onClick={() => handleDateSelect(date)}
                    disabled={disabled}
                  >
                    {date.getDate()}
                  </button>
                );

                return (
                  <div key={date.toString()} className="flex items-center justify-center">
                    {dayContent}
                  </div>
                );
              })}
            </div>

            {/* Time Input */}
            {showTime && (
              <div className="mt-4 pt-4 border-t border-border-primary">
                <label className="block text-sm font-medium text-text-primary mb-2">
                  Hora
                </label>
                <input
                  type="time"
                  value={timeValue}
                  onChange={handleTimeChange}
                  className="w-full px-3 py-2 border border-input-border rounded bg-input-bg focus:outline-none focus:ring-2 focus:ring-color-primary/20"
                />
              </div>
            )}

            {/* Footer */}
            {(showToday || showClear) && (
              <div className="flex items-center justify-between mt-4 pt-4 border-t border-border-primary">
                {showToday && (
                  <button
                    type="button"
                    className="px-3 py-1 text-sm text-color-primary hover:bg-color-primary/10 rounded transition-colors duration-150"
                    onClick={handleTodayClick}
                  >
                    {localT.today}
                  </button>
                )}
                
                {showClear && (
                  <button
                    type="button"
                    className="px-3 py-1 text-sm text-text-tertiary hover:text-color-error hover:bg-color-error/10 rounded transition-colors duration-150"
                    onClick={handleClear}
                  >
                    {localT.clear}
                  </button>
                )}
              </div>
            )}
          </div>
        </div>
      </div>

      {error && (
        <p
          id={`${datePickerId}-error`}
          className="mt-2 text-sm text-color-error"
        >
          {error}
        </p>
      )}

      {helperText && !error && (
        <p
          id={`${datePickerId}-helper`}
          className="mt-2 text-sm text-text-secondary"
        >
          {helperText}
        </p>
      )}
    </div>
  );
});

DatePicker.displayName = 'DatePicker';

export default DatePicker;