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

export interface DateRange {
  start: Date | null;
  end: Date | null;
}

export interface DateRangePickerProps {
  value?: DateRange;
  onChange?: (range: DateRange) => void;
  placeholder?: string;
  disabled?: boolean;
  error?: boolean;
  minDate?: Date;
  maxDate?: Date;
  className?: string;
}

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

export function DateRangePicker({
  value = { start: null, end: null },
  onChange,
  placeholder = 'Seleccionar rango',
  disabled = false,
  error = false,
  minDate,
  maxDate,
  className,
}: DateRangePickerProps) {
  const [isOpen, setIsOpen] = useState(false);
  const [leftMonth, setLeftMonth] = useState(value.start || new Date());
  const [rightMonth, setRightMonth] = useState(addMonths(value.start || new Date(), 1));
  const [hoverDate, setHoverDate] = useState<Date | null>(null);
  const [selecting, setSelecting] = useState<'start' | 'end'>('start');
  const [position, setPosition] = useState({ top: 0, left: 0 });
  const triggerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (isOpen && triggerRef.current) {
      const rect = triggerRef.current.getBoundingClientRect();
      setPosition({
        top: rect.bottom + 4,
        left: Math.min(rect.left, window.innerWidth - 600),
      });
    }
  }, [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 handleDateClick = (date: Date) => {
    if (selecting === 'start') {
      onChange?.({ start: date, end: null });
      setSelecting('end');
    } else {
      if (value.start && isBefore(date, value.start)) {
        onChange?.({ start: date, end: value.start });
      } else {
        onChange?.({ start: value.start, end: date });
      }
      setSelecting('start');
      setIsOpen(false);
    }
  };

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

  const isInRange = (date: Date) => {
    if (!value.start) return false;
    const endDate = value.end || hoverDate;
    if (!endDate) return false;

    const start = isBefore(value.start, endDate) ? value.start : endDate;
    const end = isAfter(value.start, endDate) ? value.start : endDate;

    return isWithinInterval(date, { start, end });
  };

  const renderMonth = (month: Date) => {
    const monthStart = startOfMonth(month);
    const monthEnd = endOfMonth(month);
    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="w-64">
        <div className="mb-4 text-center text-sm font-semibold capitalize">
          {format(month, 'MMMM yyyy', { locale: es })}
        </div>
        <div className="mb-2 grid grid-cols-7 gap-1">
          {WEEKDAYS.map((d) => (
            <div
              key={d}
              className="flex h-8 w-8 items-center justify-center text-xs font-medium text-gray-500"
            >
              {d}
            </div>
          ))}
        </div>
        <div className="grid grid-cols-7 gap-1">
          {days.map((d, i) => {
            const isCurrentMonth = isSameMonth(d, month);
            const isStart = value.start && isSameDay(d, value.start);
            const isEnd = value.end && isSameDay(d, value.end);
            const inRange = isInRange(d);
            const isDisabled = isDateDisabled(d);

            return (
              <button
                key={i}
                type="button"
                disabled={isDisabled || !isCurrentMonth}
                onClick={() => handleDateClick(d)}
                onMouseEnter={() => selecting === 'end' && setHoverDate(d)}
                className={cn(
                  'flex h-8 w-8 items-center justify-center text-sm transition-colors',
                  !isCurrentMonth && 'invisible',
                  isCurrentMonth && !isStart && !isEnd && !inRange && 'hover:bg-gray-100 rounded-full',
                  (isStart || isEnd) && 'bg-primary-600 text-white rounded-full',
                  inRange && !isStart && !isEnd && 'bg-primary-100',
                  isDisabled && 'cursor-not-allowed opacity-50'
                )}
              >
                {format(d, 'd')}
              </button>
            );
          })}
        </div>
      </div>
    );
  };

  const displayValue = () => {
    if (!value.start) return placeholder;
    const startStr = format(value.start, 'dd/MM/yyyy', { locale: es });
    if (!value.end) return `${startStr} - ...`;
    const endStr = format(value.end, 'dd/MM/yyyy', { locale: es });
    return `${startStr} - ${endStr}`;
  };

  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 rounded-lg border bg-white p-4 shadow-lg"
          style={{ top: position.top, left: position.left }}
        >
          <div className="flex gap-8">
            {/* Left month */}
            <div>
              <div className="mb-2 flex justify-start">
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={() => {
                    setLeftMonth(subMonths(leftMonth, 1));
                    setRightMonth(subMonths(rightMonth, 1));
                  }}
                >
                  <ChevronLeft className="h-4 w-4" />
                </Button>
              </div>
              {renderMonth(leftMonth)}
            </div>

            {/* Right month */}
            <div>
              <div className="mb-2 flex justify-end">
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={() => {
                    setLeftMonth(addMonths(leftMonth, 1));
                    setRightMonth(addMonths(rightMonth, 1));
                  }}
                >
                  <ChevronRight className="h-4 w-4" />
                </Button>
              </div>
              {renderMonth(rightMonth)}
            </div>
          </div>

          {/* Presets */}
          <div className="mt-4 flex gap-2 border-t pt-3">
            <Button
              variant="ghost"
              size="sm"
              onClick={() => {
                const today = new Date();
                onChange?.({ start: today, end: today });
                setIsOpen(false);
              }}
            >
              Hoy
            </Button>
            <Button
              variant="ghost"
              size="sm"
              onClick={() => {
                const today = new Date();
                const weekAgo = addDays(today, -7);
                onChange?.({ start: weekAgo, end: today });
                setIsOpen(false);
              }}
            >
              Última semana
            </Button>
            <Button
              variant="ghost"
              size="sm"
              onClick={() => {
                const today = new Date();
                const monthAgo = addDays(today, -30);
                onChange?.({ start: monthAgo, end: today });
                setIsOpen(false);
              }}
            >
              Últimos 30 días
            </Button>
          </div>
        </motion.div>
      )}
    </AnimatePresence>
  );

  return (
    <>
      <div
        ref={triggerRef}
        onClick={() => !disabled && setIsOpen(true)}
        className={cn(
          'flex h-10 cursor-pointer items-center gap-2 rounded-md border px-3 transition-colors',
          disabled
            ? 'cursor-not-allowed bg-gray-50 text-gray-500'
            : 'bg-white hover:border-gray-400',
          error
            ? 'border-danger-500'
            : 'border-gray-300',
          isOpen && 'border-primary-500 ring-1 ring-primary-500',
          className
        )}
      >
        <Calendar className="h-4 w-4 text-gray-400" />
        <span className={cn('flex-1 text-sm', !value.start && 'text-gray-400')}>
          {displayValue()}
        </span>
      </div>
      {createPortal(calendar, document.body)}
    </>
  );
}
