import { useState, useRef, useEffect, useMemo } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { ChevronLeft, ChevronRight, ChevronDown, CalendarDays } from 'lucide-react';
import { getTodayKST, dayjs } from '@/utils';
import { MIN_YEAR, WEEKDAYS, MONTH_NAMES } from '@/constants';

const MONTHS = MONTH_NAMES;

/**
 * PC용 달력 컴포넌트
 * @param {Date} currentDate - 현재 표시 중인 년/월
 * @param {function} onDateChange - 년/월 변경 핸들러
 * @param {string} selectedDate - 선택된 날짜 (YYYY-MM-DD)
 * @param {function} onSelectDate - 날짜 선택 핸들러
 * @param {Array} schedules - 일정 목록 (점 표시용)
 * @param {function} getCategoryColor - 카테고리 색상 가져오기
 * @param {boolean} disabled - 비활성화 여부
 */
function Calendar({
  currentDate,
  onDateChange,
  selectedDate,
  onSelectDate,
  schedules = [],
  getCategoryColor,
  disabled = false,
}) {
  const [showYearMonthPicker, setShowYearMonthPicker] = useState(false);
  const [slideDirection, setSlideDirection] = useState(0);
  const [yearRangeStart, setYearRangeStart] = useState(MIN_YEAR);
  const pickerRef = useRef(null);

  const year = currentDate.getFullYear();
  const month = currentDate.getMonth();

  // 외부 클릭 시 팝업 닫기
  useEffect(() => {
    const handleClickOutside = (event) => {
      if (pickerRef.current && !pickerRef.current.contains(event.target)) {
        setShowYearMonthPicker(false);
      }
    };
    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, []);

  // 달력 계산
  const getDaysInMonth = (y, m) => new Date(y, m + 1, 0).getDate();
  const getFirstDayOfMonth = (y, m) => new Date(y, m, 1).getDay();

  const daysInMonth = getDaysInMonth(year, month);
  const firstDay = getFirstDayOfMonth(year, month);

  // 일정 날짜별 맵 (O(1) 조회용)
  const scheduleDateMap = useMemo(() => {
    const map = new Map();
    schedules.forEach((s) => {
      const dateStr = s.date ? s.date.split('T')[0] : '';
      if (!map.has(dateStr)) {
        map.set(dateStr, []);
      }
      map.get(dateStr).push(s);
    });
    return map;
  }, [schedules]);

  // 2017년 1월 이전으로 이동 불가
  const canGoPrevMonth = !(year === MIN_YEAR && month === 0);

  const prevMonth = () => {
    if (!canGoPrevMonth) return;
    setSlideDirection(-1);
    const newDate = new Date(year, month - 1, 1);
    onDateChange(newDate);
    // 이번달이면 오늘, 다른 달이면 1일 선택
    const today = new Date();
    if (newDate.getFullYear() === today.getFullYear() && newDate.getMonth() === today.getMonth()) {
      onSelectDate(getTodayKST());
    } else {
      onSelectDate(`${newDate.getFullYear()}-${String(newDate.getMonth() + 1).padStart(2, '0')}-01`);
    }
  };

  const nextMonth = () => {
    setSlideDirection(1);
    const newDate = new Date(year, month + 1, 1);
    onDateChange(newDate);
    const today = new Date();
    if (newDate.getFullYear() === today.getFullYear() && newDate.getMonth() === today.getMonth()) {
      onSelectDate(getTodayKST());
    } else {
      onSelectDate(`${newDate.getFullYear()}-${String(newDate.getMonth() + 1).padStart(2, '0')}-01`);
    }
  };

  // 오늘 날짜로 이동
  const goToToday = () => {
    const today = new Date();
    const isFuture =
      today.getFullYear() > year ||
      (today.getFullYear() === year && today.getMonth() > month);
    setSlideDirection(isFuture ? 1 : -1);
    onDateChange(today);
    onSelectDate(getTodayKST());
  };

  const selectYear = (newYear) => {
    onDateChange(new Date(newYear, month, 1));
  };

  const selectMonth = (newMonth) => {
    const newDate = new Date(year, newMonth, 1);
    onDateChange(newDate);
    const today = new Date();
    if (newDate.getFullYear() === today.getFullYear() && newDate.getMonth() === today.getMonth()) {
      onSelectDate(getTodayKST());
    } else {
      onSelectDate(`${year}-${String(newMonth + 1).padStart(2, '0')}-01`);
    }
    setShowYearMonthPicker(false);
  };

  const selectDate = (day) => {
    const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
    onSelectDate(dateStr);
  };

  // 연도 범위
  const yearRange = Array.from({ length: 12 }, (_, i) => yearRangeStart + i);
  const canGoPrevYearRange = yearRangeStart > MIN_YEAR;
  const prevYearRange = () => canGoPrevYearRange && setYearRangeStart((prev) => Math.max(MIN_YEAR, prev - 12));
  const nextYearRange = () => setYearRangeStart((prev) => prev + 12);

  const currentYear = new Date().getFullYear();
  const isCurrentYear = (y) => y === currentYear;
  const isCurrentMonth = (m) => {
    const now = new Date();
    return year === now.getFullYear() && m === now.getMonth();
  };

  return (
    <motion.div
      animate={{ opacity: disabled ? 0.4 : 1 }}
      transition={{ duration: 0.2 }}
      className={disabled ? 'pointer-events-none' : ''}
    >
      <div className="bg-white rounded-2xl shadow-sm pt-8 px-8 pb-5 relative" ref={pickerRef}>
        {/* 헤더 */}
        <div className="flex items-center justify-between mb-8">
          <button
            aria-label="이전 달"
            onClick={prevMonth}
            disabled={!canGoPrevMonth}
            className={`p-2 rounded-full transition-colors ${canGoPrevMonth ? 'hover:bg-gray-100' : 'opacity-30'}`}
          >
            <ChevronLeft size={24} aria-hidden="true" />
          </button>
          <button
            aria-label="년/월 선택"
            aria-expanded={showYearMonthPicker}
            onClick={() => setShowYearMonthPicker(!showYearMonthPicker)}
            className="flex items-center gap-1 text-xl font-bold hover:text-primary transition-colors"
          >
            <span>{year}년 {month + 1}월</span>
            <ChevronDown size={20} aria-hidden="true" className={`transition-transform ${showYearMonthPicker ? 'rotate-180' : ''}`} />
          </button>
          <button aria-label="다음 달" onClick={nextMonth} className="p-2 hover:bg-gray-100 rounded-full transition-colors">
            <ChevronRight size={24} aria-hidden="true" />
          </button>
        </div>

        {/* 년/월 선택 팝업 */}
        <AnimatePresence>
          {showYearMonthPicker && (
            <motion.div
              initial={{ opacity: 0, y: -10 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -10 }}
              className="absolute top-20 left-8 right-8 mx-auto w-80 bg-white rounded-xl shadow-lg border border-gray-200 p-4 z-10"
            >
              <div className="flex items-center justify-between mb-4">
                <button
                  aria-label="이전 연도 범위"
                  onClick={prevYearRange}
                  disabled={!canGoPrevYearRange}
                  className={`p-1.5 rounded-lg transition-colors ${canGoPrevYearRange ? 'hover:bg-gray-100' : 'opacity-30'}`}
                >
                  <ChevronLeft size={20} aria-hidden="true" className="text-gray-600" />
                </button>
                <span className="font-medium text-gray-900">
                  {yearRange[0]} - {yearRange[yearRange.length - 1]}
                </span>
                <button aria-label="다음 연도 범위" onClick={nextYearRange} className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors">
                  <ChevronRight size={20} aria-hidden="true" className="text-gray-600" />
                </button>
              </div>

              {/* 년도 선택 */}
              <div className="text-center text-sm text-gray-500 mb-3">년도</div>
              <div className="grid grid-cols-4 gap-2 mb-4">
                {yearRange.map((y) => (
                  <button
                    key={y}
                    aria-label={`${y}년 선택`}
                    aria-pressed={year === y}
                    onClick={() => selectYear(y)}
                    className={`py-2 text-sm rounded-lg transition-colors ${
                      year === y
                        ? 'bg-primary text-white'
                        : isCurrentYear(y) && year !== y
                        ? 'text-primary font-medium hover:bg-primary/10'
                        : 'hover:bg-gray-100 text-gray-700'
                    }`}
                  >
                    {y}
                  </button>
                ))}
              </div>

              {/* 월 선택 */}
              <div className="text-center text-sm text-gray-500 mb-3">월</div>
              <div className="grid grid-cols-4 gap-2">
                {MONTHS.map((m, i) => (
                  <button
                    key={m}
                    aria-label={`${m} 선택`}
                    aria-pressed={month === i}
                    onClick={() => selectMonth(i)}
                    className={`py-2 text-sm rounded-lg transition-colors ${
                      month === i
                        ? 'bg-primary text-white'
                        : isCurrentMonth(i) && month !== i
                        ? 'text-primary font-medium hover:bg-primary/10'
                        : 'hover:bg-gray-100 text-gray-700'
                    }`}
                  >
                    {m}
                  </button>
                ))}
              </div>
            </motion.div>
          )}
        </AnimatePresence>

        {/* 요일 헤더 + 날짜 그리드 */}
        <AnimatePresence mode="wait" initial={false}>
          <motion.div
            key={`${year}-${month}`}
            initial={{ opacity: 0, x: slideDirection * 20 }}
            animate={{ opacity: 1, x: 0 }}
            exit={{ opacity: 0, x: slideDirection * -20 }}
            transition={{ duration: 0.08 }}
          >
            <div className="grid grid-cols-7 mb-4">
              {WEEKDAYS.map((day, i) => (
                <div
                  key={day}
                  className={`text-center text-sm font-medium py-2 ${
                    i === 0 ? 'text-red-500' : i === 6 ? 'text-blue-500' : 'text-gray-500'
                  }`}
                >
                  {day}
                </div>
              ))}
            </div>

            <div className="grid grid-cols-7 gap-1">
              {/* 전달 날짜 */}
              {Array.from({ length: firstDay }).map((_, i) => {
                const prevMonthDays = getDaysInMonth(year, month - 1);
                const day = prevMonthDays - firstDay + i + 1;
                return (
                  <div key={`prev-${i}`} className="aspect-square flex items-center justify-center text-gray-300 text-base">
                    {day}
                  </div>
                );
              })}

              {/* 현재 달 날짜 */}
              {Array.from({ length: daysInMonth }).map((_, i) => {
                const day = i + 1;
                const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
                const isSelected = selectedDate === dateStr;
                const dayOfWeek = (firstDay + i) % 7;
                const isToday = new Date().toDateString() === new Date(year, month, day).toDateString();
                const daySchedules = (scheduleDateMap.get(dateStr) || []).slice(0, 3);

                return (
                  <button
                    key={day}
                    aria-label={`${month + 1}월 ${day}일${isToday ? ' (오늘)' : ''}${daySchedules.length > 0 ? `, 일정 ${daySchedules.length}개` : ''}`}
                    aria-pressed={isSelected}
                    onClick={() => selectDate(day)}
                    className={`aspect-square flex flex-col items-center justify-center rounded-full text-base font-medium transition-all relative hover:bg-gray-100
                      ${isSelected ? 'bg-primary text-white shadow-lg hover:bg-primary' : ''}
                      ${isToday && !isSelected ? 'text-primary font-bold' : ''}
                      ${dayOfWeek === 0 && !isSelected && !isToday ? 'text-red-500' : ''}
                      ${dayOfWeek === 6 && !isSelected && !isToday ? 'text-blue-500' : ''}
                    `}
                  >
                    <span>{day}</span>
                    {!isSelected && daySchedules.length > 0 && (
                      <span className="absolute bottom-1 flex gap-0.5">
                        {daySchedules.map((schedule, idx) => (
                          <span
                            key={idx}
                            className="w-1 h-1 rounded-full"
                            style={{ backgroundColor: getCategoryColor?.(schedule.category_id, schedule) || '#4A7C59' }}
                          />
                        ))}
                      </span>
                    )}
                  </button>
                );
              })}

              {/* 다음달 날짜 */}
              {(() => {
                const totalCells = firstDay + daysInMonth;
                const remainder = totalCells % 7;
                const nextDays = remainder === 0 ? 0 : 7 - remainder;
                return Array.from({ length: nextDays }).map((_, i) => (
                  <div key={`next-${i}`} className="aspect-square flex items-center justify-center text-gray-300 text-base">
                    {i + 1}
                  </div>
                ));
              })()}
            </div>
          </motion.div>
        </AnimatePresence>

        {/* 범례 + 오늘 버튼 */}
        <div className="mt-6 pt-4 border-t border-gray-100 flex items-center justify-between text-sm">
          <div className="flex items-center gap-1.5 text-gray-500">
            <span className="w-2 h-2 rounded-full bg-primary flex-shrink-0" />
            <span className="leading-none">일정 있음</span>
          </div>
          <button
            aria-label="오늘 날짜로 이동"
            onClick={goToToday}
            className="flex items-center gap-1 px-2.5 py-1.5 rounded-lg text-primary font-medium hover:bg-primary/10 transition-colors"
          >
            <CalendarDays size={14} aria-hidden="true" />
            오늘
          </button>
        </div>
      </div>
    </motion.div>
  );
}

export default Calendar;
