import { useState, useRef, useEffect, forwardRef } from 'react';
import { createPortal } from 'react-dom';
import { motion, AnimatePresence } from 'framer-motion';
import {
  format,
  startOfMonth,
  endOfMonth,
  startOfWeek,
  endOfWeek,
  addDays,
  addMonths,
  subMonths,
  isSameMonth,
  isSameDay,
  isToday,
  parse,
  isValid,
} from 'date-fns';
import { es } from 'date-fns/locale';
import { Calendar, ChevronLeft, ChevronRight, X } from 'lucide-react';
import { cn } from '@utils/cn';
import { Button } from '@components/atoms/Button';

export interface DatePickerProps {
  value?: Date | null;
  onChange?: (date: Date | null) => void;
  placeholder?: string;
  disabled?: boolean;
  error?: boolean;
  clearable?: boolean;
  minDate?: Date;
  maxDate?: Date;
  dateFormat?: string;
  className?: string;
  name?: string;
}

const WEEKDAYS = ['Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa', 'Do'];

export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
  (
    {
      value,
      onChange,
      placeholder = 'Seleccionar fecha',
      disabled = false,
      error = false,
      clearable = true,
      minDate,
      maxDate,
      dateFormat = 'dd/MM/yyyy',
      className,
      name,
    },
    ref
  ) => {
    const [isOpen, setIsOpen] = useState(false);
    const [currentMonth, setCurrentMonth] = useState(value || new Date());
    const [position, setPosition] = useState({ top: 0, left: 0 });
    const [inputValue, setInputValue] = useState('');
    const triggerRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
      if (value) {
        setInputValue(format(value, dateFormat, { locale: es }));
        setCurrentMonth(value);
      } else {
        setInputValue('');
      }
    }, [value, dateFormat]);

    useEffect(() => {
      if (isOpen && triggerRef.current) {
        const rect = triggerRef.current.getBoundingClientRect();
        const spaceBelow = window.innerHeight - rect.bottom;
        const calendarHeight = 320;

        setPosition({
          top: spaceBelow > calendarHeight ? rect.bottom + 4 : rect.top - calendarHeight - 4,
          left: rect.left,
        });
      }
    }, [isOpen]);

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

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

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

    const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      const val = e.target.value;
      setInputValue(val);

      if (val === '') {
        onChange?.(null);
        return;
      }

      const parsed = parse(val, dateFormat, new Date());
      if (isValid(parsed)) {
        const isInRange =
          (!minDate || parsed >= minDate) && (!maxDate || parsed <= maxDate);
        if (isInRange) {
          onChange?.(parsed);
          setCurrentMonth(parsed);
        }
      }
    };

    const handleDateSelect = (date: Date) => {
      onChange?.(date);
      setIsOpen(false);
    };

    const handleClear = (e: React.MouseEvent) => {
      e.stopPropagation();
      onChange?.(null);
      setInputValue('');
    };

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

    const renderCalendar = () => {
      const monthStart = startOfMonth(currentMonth);
      const monthEnd = endOfMonth(currentMonth);
      const startDate = startOfWeek(monthStart, { weekStartsOn: 1 });
      const endDate = endOfWeek(monthEnd, { weekStartsOn: 1 });

      const days: Date[] = [];
      let day = startDate;

      while (day <= endDate) {
        days.push(day);
        day = addDays(day, 1);
      }

      return (
        <div className="grid grid-cols-7 gap-1">
          {days.map((d, i) => {
            const isCurrentMonth = isSameMonth(d, currentMonth);
            const isSelected = value && isSameDay(d, value);
            const isTodayDate = isToday(d);
            const isDisabled = isDateDisabled(d);

            return (
              <button
                key={i}
                type="button"
                disabled={isDisabled}
                onClick={() => !isDisabled && handleDateSelect(d)}
                className={cn(
                  'flex h-8 w-8 items-center justify-center rounded-full text-sm transition-colors',
                  !isCurrentMonth && 'text-gray-300',
                  isCurrentMonth && !isSelected && !isDisabled && 'hover:bg-gray-100',
                  isSelected && 'bg-primary-600 text-white',
                  isTodayDate && !isSelected && 'font-bold text-primary-600',
                  isDisabled && 'cursor-not-allowed opacity-50'
                )}
              >
                {format(d, 'd')}
              </button>
            );
          })}
        </div>
      );
    };

    const calendar = (
      <AnimatePresence>
        {isOpen && (
          <motion.div
            initial={{ opacity: 0, y: -8 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -8 }}
            transition={{ duration: 0.15 }}
            className="fixed z-50 w-72 rounded-lg border bg-white p-4 shadow-lg"
            style={{ top: position.top, left: position.left }}
          >
            {/* Header */}
            <div className="mb-4 flex items-center justify-between">
              <Button
                variant="ghost"
                size="sm"
                onClick={() => setCurrentMonth(subMonths(currentMonth, 1))}
              >
                <ChevronLeft className="h-4 w-4" />
              </Button>
              <span className="text-sm font-semibold capitalize">
                {format(currentMonth, 'MMMM yyyy', { locale: es })}
              </span>
              <Button
                variant="ghost"
                size="sm"
                onClick={() => setCurrentMonth(addMonths(currentMonth, 1))}
              >
                <ChevronRight className="h-4 w-4" />
              </Button>
            </div>

            {/* Weekdays */}
            <div className="mb-2 grid grid-cols-7 gap-1">
              {WEEKDAYS.map((day) => (
                <div
                  key={day}
                  className="flex h-8 w-8 items-center justify-center text-xs font-medium text-gray-500"
                >
                  {day}
                </div>
              ))}
            </div>

            {/* Days */}
            {renderCalendar()}

            {/* Footer */}
            <div className="mt-4 flex justify-between border-t pt-3">
              <Button
                variant="ghost"
                size="sm"
                onClick={() => {
                  const today = new Date();
                  if (!isDateDisabled(today)) {
                    handleDateSelect(today);
                  }
                }}
              >
                Hoy
              </Button>
              <Button variant="ghost" size="sm" onClick={() => setIsOpen(false)}>
                Cerrar
              </Button>
            </div>
          </motion.div>
        )}
      </AnimatePresence>
    );

    return (
      <>
        <div
          ref={(node) => {
            (triggerRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
            if (typeof ref === 'function') ref(node);
            else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;
          }}
          className={cn(
            'relative flex items-center rounded-md border transition-colors',
            disabled
              ? 'cursor-not-allowed bg-gray-50'
              : 'bg-white hover:border-gray-400',
            error
              ? 'border-danger-500 focus-within:border-danger-500 focus-within:ring-1 focus-within:ring-danger-500'
              : 'border-gray-300 focus-within:border-primary-500 focus-within:ring-1 focus-within:ring-primary-500',
            className
          )}
        >
          <input
            type="hidden"
            name={name}
            value={value ? format(value, 'yyyy-MM-dd') : ''}
          />
          <div className="pointer-events-none absolute left-3 text-gray-400">
            <Calendar className="h-4 w-4" />
          </div>
          <input
            type="text"
            value={inputValue}
            onChange={handleInputChange}
            onFocus={() => !disabled && setIsOpen(true)}
            placeholder={placeholder}
            disabled={disabled}
            className="h-10 w-full rounded-md bg-transparent py-2 pl-10 pr-8 text-sm outline-none placeholder:text-gray-400 disabled:cursor-not-allowed"
          />
          {clearable && value && !disabled && (
            <button
              type="button"
              onClick={handleClear}
              className="absolute right-2 rounded p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600"
            >
              <X className="h-4 w-4" />
            </button>
          )}
        </div>
        {createPortal(calendar, document.body)}
      </>
    );
  }
);

DatePicker.displayName = 'DatePicker';
