import { useState, useMemo } from 'react';
import { Button } from './button';
import { Dropdown } from './dropdown';
import { cn } from '@/lib/utils';
import {
  Calendar as CalendarIcon,
  ChevronLeft,
  ChevronRight,
  X,
} from 'lucide-react';

export interface DatePickerProps {
  value?: Date | { start: Date; end: Date };
  onChange: (date: Date | { start: Date; end: Date }) => void;
  mode?: 'single' | 'range';
  minDate?: Date;
  maxDate?: Date;
  placeholder?: string;
  disabled?: boolean;
  className?: string;
}

const DAYS_OF_WEEK = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
const MONTHS = [
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December',
];

/**
 * Composant DatePicker avec calendrier, sélection de date unique ou range.
 */
export function DatePicker({
  value,
  onChange,
  mode = 'single',
  minDate,
  maxDate,
  placeholder,
  disabled = false,
  className,
}: DatePickerProps) {
  const [_open, setOpen] = useState(false);
  const [currentMonth, setCurrentMonth] = useState(new Date());

  // Normaliser les dates pour la comparaison (sans heures)
  const normalizeDate = (date: Date): Date => {
    const normalized = new Date(date);
    normalized.setHours(0, 0, 0, 0);
    return normalized;
  };

  const isDateDisabled = (date: Date): boolean => {
    const normalized = normalizeDate(date);
    if (minDate && normalized < normalizeDate(minDate)) return true;
    if (maxDate && normalized > normalizeDate(maxDate)) return true;
    return false;
  };

  const isDateInRange = (date: Date): boolean => {
    if (
      mode !== 'range' ||
      !value ||
      (typeof value === 'object' && !('start' in value))
    ) {
      return false;
    }
    const range = value as { start: Date; end: Date };
    if (!range.start || !range.end) return false;
    const normalized = normalizeDate(date);
    const start = normalizeDate(range.start);
    const end = normalizeDate(range.end);
    return normalized >= start && normalized <= end;
  };

  const isDateSelected = (date: Date): boolean => {
    const normalized = normalizeDate(date);
    if (mode === 'single') {
      if (!value || value instanceof Date === false) return false;
      return normalized.getTime() === normalizeDate(value as Date).getTime();
    } else {
      if (!value || typeof value !== 'object' || !('start' in value))
        return false;
      const range = value as { start: Date; end: Date };
      if (!range.start && !range.end) return false;
      if (
        range.start &&
        normalized.getTime() === normalizeDate(range.start).getTime()
      )
        return true;
      if (
        range.end &&
        normalized.getTime() === normalizeDate(range.end).getTime()
      )
        return true;
      return false;
    }
  };

  const isDateStart = (date: Date): boolean => {
    if (
      mode !== 'range' ||
      !value ||
      typeof value !== 'object' ||
      !('start' in value)
    ) {
      return false;
    }
    const range = value as { start: Date; end: Date };
    if (!range.start) return false;
    return (
      normalizeDate(date).getTime() === normalizeDate(range.start).getTime()
    );
  };

  const isDateEnd = (date: Date): boolean => {
    if (
      mode !== 'range' ||
      !value ||
      typeof value !== 'object' ||
      !('end' in value)
    ) {
      return false;
    }
    const range = value as { start: Date; end: Date };
    if (!range.end) return false;
    return normalizeDate(date).getTime() === normalizeDate(range.end).getTime();
  };

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

    if (mode === 'single') {
      onChange(date);
      setOpen(false);
    } else {
      // Mode range
      if (!value || typeof value !== 'object' || !('start' in value)) {
        onChange({ start: date, end: date });
        return;
      }
      const range = value as { start: Date; end: Date };
      if (!range.start || (range.start && range.end)) {
        // Nouvelle sélection
        onChange({ start: date, end: date });
      } else {
        // Compléter la sélection
        if (date < range.start) {
          onChange({ start: date, end: range.start });
        } else {
          onChange({ start: range.start, end: date });
        }
        setOpen(false);
      }
    }
  };

  const handleClear = (e: React.MouseEvent) => {
    e.stopPropagation();
    e.preventDefault();
    if (mode === 'single') {
      onChange(undefined as any);
    } else {
      onChange({ start: undefined as any, end: undefined as any });
    }
  };

  const handlePreviousMonth = () => {
    setCurrentMonth(
      new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1),
    );
  };

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

  const handleToday = () => {
    const today = new Date();
    if (!isDateDisabled(today)) {
      handleDateSelect(today);
    }
  };

  // Générer les jours du calendrier
  const calendarDays = useMemo(() => {
    const year = currentMonth.getFullYear();
    const month = currentMonth.getMonth();
    const firstDay = new Date(year, month, 1);
    const lastDay = new Date(year, month + 1, 0);
    const daysInMonth = lastDay.getDate();
    const startingDayOfWeek = (firstDay.getDay() + 6) % 7; // Lundi = 0

    const days: (Date | null)[] = [];

    // Jours du mois précédent
    for (let i = 0; i < startingDayOfWeek; i++) {
      days.push(null);
    }

    // Jours du mois courant
    for (let day = 1; day <= daysInMonth; day++) {
      days.push(new Date(year, month, day));
    }

    return days;
  }, [currentMonth]);

  // Format de l'affichage
  const displayValue = useMemo(() => {
    if (!value) return placeholder || 'Select date...';

    if (mode === 'single') {
      if (value instanceof Date) {
        return value.toLocaleDateString();
      }
      return placeholder || 'Select date...';
    } else {
      const range = value as { start: Date; end: Date };
      if (range.start && range.end) {
        return `${range.start.toLocaleDateString()} - ${range.end.toLocaleDateString()}`;
      } else if (range.start) {
        return `${range.start.toLocaleDateString()} - ...`;
      }
      return placeholder || 'Select date range...';
    }
  }, [value, mode, placeholder]);

  const trigger = (
    <Button
      variant="outline"
      disabled={disabled}
      className={cn(
        'w-full justify-start text-left font-normal',
        !value && 'text-muted-foreground',
        className,
      )}
    >
      <CalendarIcon className="mr-2 h-4 w-4" />
      <span className="flex-1 truncate">{displayValue}</span>
      {value && (
        <X
          className="ml-2 h-4 w-4 shrink-0 opacity-50 hover:opacity-100"
          onClick={handleClear}
        />
      )}
    </Button>
  );

  return (
    <Dropdown
      trigger={trigger}
      align="left"
      onOpenChange={setOpen}
      className="w-full"
    >
      <div className="w-auto p-0">
        <div className="p-3">
          {/* Header avec navigation */}
          <div className="flex items-center justify-between mb-4">
            <div className="flex items-center gap-2">
              <Button
                variant="ghost"
                size="icon"
                onClick={handlePreviousMonth}
                className="h-7 w-7"
              >
                <ChevronLeft className="h-4 w-4" />
              </Button>
              <div className="text-sm font-semibold min-w-[120px] text-center">
                {MONTHS[currentMonth.getMonth()]} {currentMonth.getFullYear()}
              </div>
              <Button
                variant="ghost"
                size="icon"
                onClick={handleNextMonth}
                className="h-7 w-7"
              >
                <ChevronRight className="h-4 w-4" />
              </Button>
            </div>
            <Button
              variant="ghost"
              size="sm"
              onClick={handleToday}
              className="text-xs"
            >
              Today
            </Button>
          </div>

          {/* Jours de la semaine */}
          <div className="grid grid-cols-7 gap-1 mb-2">
            {DAYS_OF_WEEK.map((day) => (
              <div
                key={day}
                className="text-xs font-medium text-muted-foreground text-center py-1"
              >
                {day}
              </div>
            ))}
          </div>

          {/* Grille du calendrier */}
          <div className="grid grid-cols-7 gap-1">
            {calendarDays.map((day, index) => {
              if (!day) {
                return <div key={`empty-${index}`} className="h-9" />;
              }

              const isSelected = isDateSelected(day);
              const isInRange = isDateInRange(day);
              const isStart = isDateStart(day);
              const isEnd = isDateEnd(day);
              const isDisabled = isDateDisabled(day);
              const isToday =
                normalizeDate(day).getTime() ===
                normalizeDate(new Date()).getTime();

              return (
                <button
                  key={day.toISOString()}
                  type="button"
                  onClick={() => handleDateSelect(day)}
                  disabled={isDisabled}
                  className={cn(
                    'h-9 w-9 text-sm rounded-md transition-colors',
                    'hover:bg-accent hover:text-accent-foreground',
                    'focus:bg-accent focus:text-accent-foreground',
                    isSelected &&
                      'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground',
                    isInRange && !isSelected && 'bg-accent',
                    isStart && 'rounded-l-md',
                    isEnd && 'rounded-r-md',
                    isDisabled &&
                      'opacity-50 cursor-not-allowed pointer-events-none',
                    isToday && !isSelected && 'border border-primary',
                  )}
                >
                  {day.getDate()}
                </button>
              );
            })}
          </div>
        </div>
      </div>
    </Dropdown>
  );
}
