import { useState, useEffect, useRef, useMemo, useDeferredValue } from 'react';
import { useNavigate, Link } from 'react-router-dom';
import { motion, AnimatePresence } from 'framer-motion';
import {
  Home,
  ChevronRight,
  Calendar,
  Plus,
  ChevronLeft,
  Search,
  ChevronDown,
  Bot,
  Tag,
  ArrowLeft,
  Book,
} from 'lucide-react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useVirtualizer } from '@tanstack/react-virtual';

import { Toast } from '@/components/common';
import { AdminLayout, ConfirmDialog } from '@/components/pc/admin';
import { ScheduleItem, getEditPath } from '@/components/pc/admin/schedule';
import useScheduleStore from '@/stores/useScheduleStore';
import { useAdminAuth, useScheduleSearch } from '@/hooks/pc/admin';
import { useToast } from '@/hooks/common';
import { getTodayKST, formatDate } from '@/utils';
import { getCategoryId, getScheduleDate } from '@/utils/schedule';
import * as schedulesApi from '@/api/admin/schedules';
import { getColorStyle } from '@/utils/color';

function Schedules() {
  const navigate = useNavigate();
  const queryClient = useQueryClient();

  // Zustand 스토어에서 상태 가져오기 (검색 제외)
  const {
    selectedCategories,
    setSelectedCategories,
    selectedDate,
    setSelectedDate,
    currentDate,
    setCurrentDate,
    scrollPosition,
    setScrollPosition,
  } = useScheduleStore();

  const { user, isAuthenticated } = useAdminAuth();

  // 검색 관련 (커스텀 훅)
  const {
    searchInput,
    searchTerm,
    isSearchMode,
    setIsSearchMode,
    showSuggestions,
    setShowSuggestions,
    selectedSuggestionIndex,
    suggestions,
    isLoadingSuggestions,
    searchResults,
    searchLoading,
    hasNextPage,
    isFetchingNextPage,
    handleSearch,
    exitSearchMode,
    handleSearchInputChange,
    handleSuggestionSelect,
    handleKeyDown: handleSearchKeyDown,
    loadMoreRef,
  } = useScheduleSearch();

  // 로컬 상태 (페이지 이동 시 유지할 필요 없는 것들)
  const { toast, setToast } = useToast();
  const scrollContainerRef = useRef(null);
  const searchContainerRef = useRef(null); // 검색 컨테이너 (외부 클릭 감지용)

  const ESTIMATED_ITEM_HEIGHT = 100; // 아이템 추정 높이 (동적 측정)

  // selectedDate가 없으면 오늘 날짜로 초기화
  useEffect(() => {
    if (!selectedDate) {
      setSelectedDate(getTodayKST());
    }
  }, []);

  const [slideDirection, setSlideDirection] = useState(0);

  // 년월 선택 관련 (Schedule.jsx와 동일한 패턴)
  const [showYearMonthPicker, setShowYearMonthPicker] = useState(false);
  const [showCategoryTooltip, setShowCategoryTooltip] = useState(false);
  const [viewMode, setViewMode] = useState('yearMonth'); // 'yearMonth' | 'months'
  const pickerRef = useRef(null);
  const categoryTooltipRef = useRef(null);

  // 달력 관련
  const year = currentDate.getFullYear();
  const month = currentDate.getMonth();
  const firstDay = new Date(year, month, 1).getDay();
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  const days = ['일', '월', '화', '수', '목', '금', '토'];
  const monthNames = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'];

  // 년도 범위 (2017년부터 시작, 12년 단위)
  const MIN_YEAR = 2017;
  const groupIndex = Math.floor((year - MIN_YEAR) / 12);
  const startYear = MIN_YEAR + groupIndex * 12;
  const yearRange = Array.from({ length: 12 }, (_, i) => startYear + i);
  const canGoPrevYearRange = startYear > MIN_YEAR;

  // 현재 년도/월 확인 함수
  const currentYear = new Date().getFullYear();
  const currentMonth = new Date().getMonth();
  const isCurrentYear = (y) => currentYear === y;
  const isCurrentMonth = (m) => currentYear === year && currentMonth === m;

  const getDaysInMonth = (y, m) => new Date(y, m + 1, 0).getDate();

  // 일정 목록 (React Query로 캐싱)
  const { data: schedules = [], isLoading: loading } = useQuery({
    queryKey: ['adminSchedules', year, month + 1],
    queryFn: () => schedulesApi.getSchedules(year, month + 1),
    enabled: isAuthenticated,
  });

  // 카테고리는 일정 데이터에서 추출
  const categories = useMemo(() => {
    const categoryMap = new Map();
    schedules.forEach((s) => {
      if (s.category_id && !categoryMap.has(s.category_id)) {
        categoryMap.set(s.category_id, {
          id: s.category_id,
          name: s.category_name,
          color: s.category_color,
        });
      }
    });
    return [{ id: 'all', name: '전체', color: 'gray' }, ...Array.from(categoryMap.values())];
  }, [schedules]);

  // 일정 데이터를 지연 처리하여 달력 UI 응답성 향상
  const deferredSchedules = useDeferredValue(schedules);

  // 일정 날짜별 맵 (O(1) 조회용) - 지연된 데이터로 점 표시
  const scheduleDateMap = useMemo(() => {
    const map = new Map();
    deferredSchedules.forEach((s) => {
      const dateStr = formatDate(s.date);
      if (!map.has(dateStr)) {
        map.set(dateStr, s);
      }
    });
    return map;
  }, [deferredSchedules]);

  // 해당 날짜에 일정이 있는지 확인 (O(1))
  const hasSchedule = (day) => {
    const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
    return scheduleDateMap.has(dateStr);
  };

  useEffect(() => {
    if (!isAuthenticated) return;

    // sessionStorage에서 토스트 메시지 확인 (일정 추가/수정 완료 시)
    const savedToast = sessionStorage.getItem('scheduleToast');
    if (savedToast) {
      setToast(JSON.parse(savedToast));
      sessionStorage.removeItem('scheduleToast');
      // 추가/수정 후 돌아왔을 때 캐시 무효화
      queryClient.invalidateQueries({ queryKey: ['adminSchedules'] });
    }
  }, [isAuthenticated, queryClient]);

  // 스크롤 위치 복원
  useEffect(() => {
    if (scrollContainerRef.current && scrollPosition > 0) {
      scrollContainerRef.current.scrollTop = scrollPosition;
    }
  }, [loading]); // 로딩이 끝나면 스크롤 복원

  // 날짜 변경 시 스크롤 맨 위로 초기화
  useEffect(() => {
    if (scrollContainerRef.current) {
      scrollContainerRef.current.scrollTop = 0;
    }
  }, [selectedDate]);

  // 스크롤 위치 저장
  const handleScroll = (e) => {
    setScrollPosition(e.target.scrollTop);
  };

  // 외부 클릭 시 피커 닫기
  useEffect(() => {
    const handleClickOutside = (event) => {
      if (pickerRef.current && !pickerRef.current.contains(event.target)) {
        setShowYearMonthPicker(false);
        setViewMode('yearMonth');
      }
      if (categoryTooltipRef.current && !categoryTooltipRef.current.contains(event.target)) {
        setShowCategoryTooltip(false);
      }
      // 검색 추천 드롭다운 외부 클릭 시 닫기
      if (searchContainerRef.current && !searchContainerRef.current.contains(event.target)) {
        setShowSuggestions(false);
        setSelectedSuggestionIndex(-1);
      }
    };

    if (showYearMonthPicker || showCategoryTooltip) {
      document.addEventListener('mousedown', handleClickOutside);
    }

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

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

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

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

  // 년도 범위 이동 (12년 단위, 2017년 이전 불가)
  const prevYearRange = () => canGoPrevYearRange && setCurrentDate(new Date(startYear - 12, month, 1));
  const nextYearRange = () => setCurrentDate(new Date(startYear + 12, month, 1));

  // 년도 선택
  const selectYear = (newYear) => {
    setCurrentDate(new Date(newYear, month, 1));
  };

  // 월 선택 시 적용 후 닫기
  const selectMonth = (newMonth) => {
    const newDate = new Date(year, newMonth, 1);
    setCurrentDate(newDate);
    // 이번달이면 오늘, 다른 달이면 1일 선택
    const today = new Date();
    if (newDate.getFullYear() === today.getFullYear() && newDate.getMonth() === today.getMonth()) {
      setSelectedDate(getTodayKST());
    } else {
      const firstDay = `${year}-${String(newMonth + 1).padStart(2, '0')}-01`;
      setSelectedDate(firstDay);
    }
    setShowYearMonthPicker(false);
    setViewMode('yearMonth');
  };

  // 날짜 선택 (토글 없이 항상 선택)
  const selectDate = (day) => {
    const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
    setSelectedDate(dateStr);
  };

  // 삭제 관련 상태
  const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
  const [scheduleToDelete, setScheduleToDelete] = useState(null);
  const [deleting, setDeleting] = useState(false);

  // 삭제 확인 다이얼로그 열기
  const openDeleteDialog = (schedule) => {
    setScheduleToDelete(schedule);
    setDeleteDialogOpen(true);
  };

  // 일정 삭제
  const handleDelete = async () => {
    if (!scheduleToDelete) return;

    setDeleting(true);
    try {
      await schedulesApi.deleteSchedule(scheduleToDelete.id);
      setToast({ type: 'success', message: '일정이 삭제되었습니다.' });
      // 캐시 무효화하여 목록 새로고침
      queryClient.invalidateQueries({ queryKey: ['adminSchedules', year, month + 1] });
    } catch (error) {
      console.error('삭제 오류:', error);
      setToast({ type: 'error', message: error.message || '삭제 중 오류가 발생했습니다.' });
    } finally {
      setDeleting(false);
      setDeleteDialogOpen(false);
      setScheduleToDelete(null);
    }
  };

  // 일정 목록 (검색 모드일 때 searchResults, 일반 모드일 때 로컬 필터링) - useMemo로 최적화
  const filteredSchedules = useMemo(() => {
    let result;
    if (isSearchMode) {
      if (!searchTerm) return [];
      // 카테고리 필터링 적용
      if (selectedCategories.length === 0) {
        result = [...searchResults];
      } else {
        result = searchResults.filter((s) => selectedCategories.includes(getCategoryId(s)));
      }
    } else {
      // 일반 모드: 로컬 필터링
      result = schedules.filter((schedule) => {
        const matchesCategory =
          selectedCategories.length === 0 || selectedCategories.includes(schedule.category_id);
        const scheduleDate = formatDate(schedule.date);
        const matchesDate = !selectedDate || scheduleDate === selectedDate;
        return matchesCategory && matchesDate;
      });
    }
    // 생일 일정을 맨 위로 정렬
    return result.sort((a, b) => {
      const aIsBirthday = a.is_birthday || String(a.id).startsWith('birthday-');
      const bIsBirthday = b.is_birthday || String(b.id).startsWith('birthday-');
      if (aIsBirthday && !bIsBirthday) return -1;
      if (!aIsBirthday && bIsBirthday) return 1;
      return 0;
    });
  }, [isSearchMode, searchTerm, searchResults, schedules, selectedCategories, selectedDate]);

  // 가상 스크롤 설정 (검색 모드에서만 활성화, 동적 높이 지원)
  const virtualizer = useVirtualizer({
    count: isSearchMode && searchTerm ? filteredSchedules.length : 0,
    getScrollElement: () => scrollContainerRef.current,
    estimateSize: () => ESTIMATED_ITEM_HEIGHT,
    overscan: 5, // 버퍼 아이템 수
  });

  // 카테고리별 카운트 맵 (선택 날짜와 무관하게 해당 달 전체 기준)
  const categoryCounts = useMemo(() => {
    // 검색어가 있을 때만 검색 결과 사용, 아니면 기존 schedules 사용
    const source = isSearchMode && searchTerm ? searchResults : schedules;
    const counts = new Map();
    let total = 0;

    source.forEach((s) => {
      const catId = getCategoryId(s);
      counts.set(catId, (counts.get(catId) || 0) + 1);
      total++;
    });

    counts.set('total', total);
    return counts;
  }, [schedules, searchResults, isSearchMode, searchTerm]);

  // 정렬된 카테고리 목록 (메모이제이션으로 깜빡임 방지)
  const sortedCategories = useMemo(() => {
    const total = categoryCounts.get('total') || 0;

    return categories
      .map((category) => ({
        ...category,
        count: category.id === 'all' ? total : categoryCounts.get(category.id) || 0,
      }))
      .filter((category) => category.id === 'all' || category.count > 0)
      .sort((a, b) => {
        if (a.id === 'all') return -1;
        if (b.id === 'all') return 1;
        if (a.name === '기타') return 1;
        if (b.name === '기타') return -1;
        return b.count - a.count;
      });
  }, [categories, categoryCounts]);

  // 연도 버튼 클래스
  const getYearButtonClass = (y) => {
    if (year === y) {
      return 'bg-primary text-white';
    }
    if (isCurrentYear(y)) {
      return 'text-primary font-medium hover:bg-primary/10';
    }
    return 'hover:bg-gray-100 text-gray-700';
  };

  // 월 버튼 클래스
  const getMonthButtonClass = (m) => {
    if (month === m) {
      return 'bg-primary text-white';
    }
    if (isCurrentMonth(m)) {
      return 'text-primary font-medium hover:bg-primary/10';
    }
    return 'hover:bg-gray-100 text-gray-700';
  };

  return (
    <AdminLayout user={user}>
      <Toast toast={toast} onClose={() => setToast(null)} />

      {/* 삭제 확인 다이얼로그 */}
      <ConfirmDialog
        isOpen={deleteDialogOpen}
        onClose={() => setDeleteDialogOpen(false)}
        onConfirm={handleDelete}
        title="일정 삭제"
        message={
          <>
            <p className="text-gray-600 mb-2">다음 일정을 삭제하시겠습니까?</p>
            <p className="text-gray-900 font-medium mb-4 p-3 bg-gray-50 rounded-lg">
              {scheduleToDelete?.title}
            </p>
            <p className="text-sm text-red-500">이 작업은 되돌릴 수 없습니다.</p>
          </>
        }
        loading={deleting}
      />

      {/* 메인 콘텐츠 - 전체 높이 차지 */}
      <div className="h-full flex flex-col overflow-hidden max-w-7xl mx-auto px-6 py-8 w-full">
        {/* 브레드크럼 */}
        <div className="flex-shrink-0 flex items-center gap-2 text-sm text-gray-400 mb-8">
          <Link to="/admin/dashboard" className="hover:text-primary transition-colors">
            <Home size={16} />
          </Link>
          <ChevronRight size={14} />
          <span className="text-gray-700">일정 관리</span>
        </div>

        {/* 타이틀 + 추가 버튼 */}
        <div className="flex-shrink-0 flex items-center justify-between mb-8">
          <div>
            <h1 className="text-3xl font-bold text-gray-900 mb-2">일정 관리</h1>
            <p className="text-gray-500">fromis_9의 일정을 관리합니다</p>
          </div>
          <div className="flex items-center gap-3">
            <button
              onClick={() => navigate('/admin/schedule/dict')}
              className="flex items-center gap-2 px-5 py-3 bg-gray-100 text-gray-700 rounded-xl hover:bg-gray-200 transition-colors font-medium"
            >
              <Book size={20} />
              사전 관리
            </button>
            <button
              onClick={() => navigate('/admin/schedule/bots')}
              className="flex items-center gap-2 px-5 py-3 bg-gray-100 text-gray-700 rounded-xl hover:bg-gray-200 transition-colors font-medium"
            >
              <Bot size={20} />
              봇 관리
            </button>
            <button
              onClick={() => navigate('/admin/schedule/new')}
              className="flex items-center gap-2 px-5 py-3 bg-primary text-white rounded-xl hover:bg-primary-dark transition-colors font-medium shadow-sm"
            >
              <Plus size={20} />
              일정 추가
            </button>
          </div>
        </div>

        <div className="flex-1 min-h-0 grid grid-cols-3 gap-8">
          {/* 왼쪽: 달력 + 카테고리 필터 */}
          <div className="space-y-6">
            {/* 달력 (Schedule.jsx와 동일한 패턴) */}
            <motion.div
              ref={pickerRef}
              animate={{ opacity: isSearchMode ? 0.4 : 1 }}
              transition={{ duration: 0.2 }}
              className={`bg-white rounded-2xl shadow-sm pt-8 px-8 pb-6 relative ${isSearchMode ? 'pointer-events-none' : ''}`}
            >
              {/* 달력 헤더 */}
              <div className={`flex items-center justify-between mb-8 ${isSearchMode ? 'opacity-50' : ''}`}>
                <button
                  onClick={prevMonth}
                  disabled={isSearchMode || !canGoPrevMonth}
                  className={`p-2 rounded-full transition-colors ${isSearchMode || !canGoPrevMonth ? 'opacity-30' : 'hover:bg-gray-100'}`}
                >
                  <ChevronLeft size={24} />
                </button>
                <button
                  onClick={() => !isSearchMode && setShowYearMonthPicker(!showYearMonthPicker)}
                  disabled={isSearchMode}
                  className={`flex items-center gap-1 text-xl font-bold transition-colors ${isSearchMode ? 'cursor-not-allowed' : 'hover:text-primary'}`}
                >
                  <span>
                    {year}년 {month + 1}월
                  </span>
                  <ChevronDown
                    size={20}
                    className={`transition-transform ${showYearMonthPicker ? 'rotate-180' : ''}`}
                  />
                </button>
                <button
                  onClick={nextMonth}
                  disabled={isSearchMode}
                  className={`p-2 rounded-full transition-colors ${isSearchMode ? 'cursor-not-allowed' : 'hover:bg-gray-100'}`}
                >
                  <ChevronRight size={24} />
                </button>
              </div>

              {/* 년/월 선택 팝업 (Schedule.jsx와 동일한 스타일) */}
              <AnimatePresence>
                {showYearMonthPicker && (
                  <motion.div
                    initial={{ opacity: 0, y: -10 }}
                    animate={{ opacity: 1, y: 0 }}
                    exit={{ opacity: 0, y: -10 }}
                    className="absolute top-16 left-6 right-6 bg-white rounded-xl shadow-lg border border-gray-200 p-4 z-10"
                  >
                    {/* 헤더 - 년도 범위 이동 */}
                    <div className="flex items-center justify-between mb-4">
                      <button
                        onClick={prevYearRange}
                        disabled={!canGoPrevYearRange}
                        className={`p-1.5 rounded-lg transition-colors ${canGoPrevYearRange ? 'hover:bg-gray-100' : 'opacity-30'}`}
                      >
                        <ChevronLeft size={20} className="text-gray-600" />
                      </button>
                      <span className="font-medium text-gray-900">
                        {viewMode === 'yearMonth'
                          ? `${yearRange[0]} - ${yearRange[yearRange.length - 1]}`
                          : `${year}년`}
                      </span>
                      <button
                        onClick={nextYearRange}
                        className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors"
                      >
                        <ChevronRight size={20} className="text-gray-600" />
                      </button>
                    </div>

                    <AnimatePresence mode="wait">
                      {viewMode === 'yearMonth' && (
                        <motion.div
                          key="yearMonth"
                          initial={{ opacity: 0 }}
                          animate={{ opacity: 1 }}
                          exit={{ opacity: 0 }}
                          transition={{ duration: 0.15 }}
                        >
                          {/* 년도 선택 */}
                          <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}
                                onClick={() => selectYear(y)}
                                className={`py-2 text-sm rounded-lg transition-colors ${getYearButtonClass(y)}`}
                              >
                                {y}
                              </button>
                            ))}
                          </div>

                          {/* 월 선택 */}
                          <div className="text-center text-sm text-gray-500 mb-3">월</div>
                          <div className="grid grid-cols-4 gap-2">
                            {monthNames.map((m, i) => (
                              <button
                                key={m}
                                onClick={() => selectMonth(i)}
                                className={`py-2 text-sm rounded-lg transition-colors ${getMonthButtonClass(i)}`}
                              >
                                {m}
                              </button>
                            ))}
                          </div>
                        </motion.div>
                      )}
                    </AnimatePresence>
                  </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">
                    {days.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();

                      // 해당 날짜의 일정 목록 (점 표시용, 최대 3개) - 카테고리 필터 반영
                      const daySchedules = schedules
                        .filter((s) => {
                          const scheduleDate = s.date ? s.date.split('T')[0] : '';
                          const matchesDate = scheduleDate === dateStr;
                          const matchesCategory =
                            selectedCategories.length === 0 || selectedCategories.includes(s.category_id);
                          return matchesDate && matchesCategory;
                        })
                        .slice(0, 3);

                      return (
                        <button
                          key={day}
                          onClick={() => !isSearchMode && selectDate(day)}
                          disabled={isSearchMode}
                          className={`aspect-square flex flex-col items-center justify-center rounded-full text-base font-medium transition-all relative
                            ${isSearchMode ? 'cursor-not-allowed opacity-50' : 'hover:bg-gray-100'}
                            ${isSelected && !isSearchMode ? '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>
                          {/* 점: 선택되지 않은 날짜에만 표시, 최대 3개 */}
                          {!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:
                                      getColorStyle(
                                        categories.find((c) => c.id === schedule.category_id)?.color
                                      )?.style?.backgroundColor || '#6b7280',
                                  }}
                                />
                              ))}
                            </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 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>
              </div>
            </motion.div>

            {/* 카테고리 필터 */}
            <motion.div
              animate={{ opacity: isSearchMode && !searchTerm ? 0.4 : 1 }}
              transition={{ duration: 0.2 }}
              className={`bg-white rounded-2xl shadow-sm p-6 ${isSearchMode && !searchTerm ? 'pointer-events-none' : ''}`}
            >
              <h3 className="font-bold text-gray-900 mb-4">카테고리</h3>
              <div className="space-y-2">
                {/* 카테고리 - useMemo로 정렬됨 */}
                {sortedCategories.map((category) => {
                  const isSelected =
                    category.id === 'all'
                      ? selectedCategories.length === 0
                      : selectedCategories.includes(category.id);

                  const handleClick = () => {
                    if (category.id === 'all') {
                      setSelectedCategories([]);
                    } else {
                      if (selectedCategories.includes(category.id)) {
                        setSelectedCategories(selectedCategories.filter((id) => id !== category.id));
                      } else {
                        setSelectedCategories([...selectedCategories, category.id]);
                      }
                    }
                  };

                  return (
                    <button
                      key={category.id}
                      onClick={handleClick}
                      className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl text-left transition-colors ${
                        isSelected ? 'bg-primary/10 text-primary' : 'hover:bg-gray-50 text-gray-700'
                      }`}
                    >
                      <span
                        className={`w-3 h-3 rounded-full ${category.id === 'all' ? 'bg-gray-400' : getColorStyle(category.color).className || ''}`}
                        style={category.id !== 'all' ? getColorStyle(category.color).style : undefined}
                      />
                      <span className="font-medium">{category.name}</span>
                      <span className="ml-auto text-sm text-gray-400">{category.count}</span>
                    </button>
                  );
                })}
              </div>
            </motion.div>
          </div>

          {/* 오른쪽: 일정 목록 */}
          <div className="col-span-2 flex flex-col min-h-0">
            {/* 일정 목록 */}
            <div className="flex-1 flex flex-col min-h-0 bg-white rounded-2xl shadow-sm overflow-hidden">
              <div className="p-5 border-b border-gray-100">
                <div className="flex items-center gap-3">
                  <AnimatePresence mode="wait">
                    {isSearchMode ? (
                      /* 검색 모드 */
                      <motion.div
                        key="search-mode"
                        initial={{ opacity: 0, scale: 0.95 }}
                        animate={{ opacity: 1, scale: 1 }}
                        exit={{ opacity: 0, scale: 0.95 }}
                        transition={{ duration: 0.15, ease: 'easeOut' }}
                        className="flex items-center gap-3 flex-1"
                      >
                        <button
                          onClick={exitSearchMode}
                          className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors"
                        >
                          <ArrowLeft size={20} className="text-gray-500" />
                        </button>

                        {/* 검색 입력 컨테이너 (드롭다운 포함) */}
                        <div className="flex-1 relative" ref={searchContainerRef}>
                          <div className="flex items-center gap-2">
                            <input
                              type="text"
                              placeholder="일정 검색..."
                              value={searchInput}
                              autoFocus
                              onChange={(e) => handleSearchInputChange(e.target.value)}
                              onFocus={() => setShowSuggestions(true)}
                              onKeyDown={handleSearchKeyDown}
                              className="flex-1 bg-transparent focus:outline-none text-gray-700 placeholder-gray-400"
                            />
                            <button
                              onClick={() => handleSearch(searchInput)}
                              disabled={searchLoading}
                              className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors disabled:opacity-50"
                            >
                              <Search size={20} className="text-primary" />
                            </button>
                          </div>

                          {/* 검색어 추천 드롭다운 */}
                          {showSuggestions &&
                            !isLoadingSuggestions &&
                            suggestions.length > 0 && (
                              <div className="absolute top-full left-0 right-8 mt-2 bg-white rounded-xl shadow-lg border border-gray-200 py-1 z-50 overflow-hidden">
                                {suggestions.map((suggestion, index) => (
                                  <button
                                    key={suggestion}
                                    onClick={() => handleSuggestionSelect(suggestion)}
                                    className={`w-full px-4 py-2 text-left text-sm flex items-center gap-3 transition-colors ${
                                      index === selectedSuggestionIndex
                                        ? 'bg-primary/10 text-primary'
                                        : 'text-gray-700 hover:bg-gray-50'
                                    }`}
                                  >
                                    <Search size={14} className="text-gray-400 shrink-0" />
                                    <span>{suggestion}</span>
                                  </button>
                                ))}
                              </div>
                            )}
                        </div>
                      </motion.div>
                    ) : (
                      /* 일반 모드 */
                      <motion.div
                        key="normal-mode"
                        initial={{ opacity: 0, scale: 0.95 }}
                        animate={{ opacity: 1, scale: 1 }}
                        exit={{ opacity: 0, scale: 0.95 }}
                        transition={{ duration: 0.15, ease: 'easeOut' }}
                        className="flex items-center gap-3 flex-1"
                      >
                        <button
                          onClick={() => setIsSearchMode(true)}
                          className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors"
                        >
                          <Search size={20} className="text-gray-500" />
                        </button>
                        <span className="font-medium text-gray-900">
                          {selectedDate
                            ? (() => {
                                const d = new Date(selectedDate);
                                const dayNames = ['일', '월', '화', '수', '목', '금', '토'];
                                return `${d.getMonth() + 1}월 ${d.getDate()}일 ${dayNames[d.getDay()]}요일`;
                              })()
                            : `${month + 1}월 전체 일정`}
                        </span>
                        <div className="flex-1" />
                        {/* 카테고리 필터 */}
                        {selectedCategories.length > 0 && (
                          <div className="relative" ref={categoryTooltipRef}>
                            <button
                              onClick={() => setShowCategoryTooltip(!showCategoryTooltip)}
                              className="flex items-center gap-1 px-2 py-1 bg-gray-100 rounded-md text-sm text-gray-600 hover:bg-gray-200 transition-colors"
                            >
                              <Tag size={14} />
                              <span>{selectedCategories.length}개 일정</span>
                            </button>
                            <AnimatePresence>
                              {showCategoryTooltip && (
                                <motion.div
                                  initial={{ opacity: 0, y: -5 }}
                                  animate={{ opacity: 1, y: 0 }}
                                  exit={{ opacity: 0, y: -5 }}
                                  transition={{ duration: 0.15 }}
                                  className="absolute top-full right-0 mt-1 bg-white rounded-lg shadow-lg border border-gray-200 p-3 z-10 min-w-[120px]"
                                >
                                  {selectedCategories.map((id) => {
                                    const cat = categories.find((c) => c.id === id);
                                    if (!cat) return null;
                                    return (
                                      <div key={id} className="flex items-center gap-2 py-1">
                                        <span
                                          className="w-2 h-2 rounded-full"
                                          style={{
                                            backgroundColor: cat.color?.startsWith('#')
                                              ? cat.color
                                              : undefined,
                                          }}
                                        />
                                        <span className="text-sm">{cat.name}</span>
                                      </div>
                                    );
                                  })}
                                </motion.div>
                              )}
                            </AnimatePresence>
                          </div>
                        )}
                        <span className="text-sm text-gray-400">{filteredSchedules.length}개 일정</span>
                      </motion.div>
                    )}
                  </AnimatePresence>
                </div>
              </div>

              {loading ? (
                <div className="flex justify-center items-center py-20">
                  <div className="animate-spin rounded-full h-12 w-12 border-4 border-primary border-t-transparent"></div>
                </div>
              ) : filteredSchedules.length === 0 ? (
                // 검색 모드에서는 빈 메시지 표시 안 함
                !isSearchMode && (
                  <motion.div
                    initial={{ opacity: 0, y: 10 }}
                    animate={{ opacity: 1, y: 0 }}
                    transition={{ duration: 0.2 }}
                    className="text-center py-16 text-gray-500"
                  >
                    <Calendar size={48} className="mx-auto mb-4 text-gray-300" />
                    <p>등록된 일정이 없습니다</p>
                  </motion.div>
                )
              ) : (
                <div
                  ref={scrollContainerRef}
                  onScroll={handleScroll}
                  id="adminScheduleScrollContainer"
                  className="flex-1 overflow-y-auto divide-y divide-gray-100 py-2"
                >
                  {isSearchMode && searchTerm ? (
                    /* 검색 모드: 가상 스크롤 + ScheduleItem 재사용 */
                    <>
                      <div
                        style={{
                          height: `${virtualizer.getTotalSize()}px`,
                          width: '100%',
                          position: 'relative',
                        }}
                      >
                        {virtualizer.getVirtualItems().map((virtualItem) => {
                          const schedule = filteredSchedules[virtualItem.index];
                          if (!schedule) return null;

                          return (
                            <div
                              key={virtualItem.key}
                              ref={virtualizer.measureElement}
                              data-index={virtualItem.index}
                              style={{
                                position: 'absolute',
                                top: 0,
                                left: 0,
                                width: '100%',
                                transform: `translateY(${virtualItem.start}px)`,
                              }}
                            >
                              <ScheduleItem
                                schedule={schedule}
                                getColorStyle={getColorStyle}
                                navigate={navigate}
                                openDeleteDialog={openDeleteDialog}
                                showYear
                                animated={false}
                                className="border-b border-gray-100"
                              />
                            </div>
                          );
                        })}
                      </div>

                      {/* 무한 스크롤 트리거 & 로딩 인디케이터 */}
                      <div ref={loadMoreRef} className="py-4">
                        {isFetchingNextPage && (
                          <div className="flex justify-center">
                            <div className="w-6 h-6 border-2 border-primary border-t-transparent rounded-full animate-spin" />
                          </div>
                        )}
                        {!hasNextPage && filteredSchedules.length > 0 && (
                          <div className="text-center text-sm text-gray-400">
                            {filteredSchedules.length}개 표시 (모두 로드됨)
                          </div>
                        )}
                      </div>
                    </>
                  ) : (
                    /* 일반 모드: ScheduleItem 컴포넌트 사용 */
                    filteredSchedules.map((schedule, index) => (
                      <ScheduleItem
                        key={`${schedule.id}-${selectedDate || 'all'}`}
                        schedule={schedule}
                        index={index}
                        selectedDate={selectedDate}
                        categories={categories}
                        getColorStyle={getColorStyle}
                        navigate={navigate}
                        openDeleteDialog={openDeleteDialog}
                      />
                    ))
                  )}
                </div>
              )}
            </div>
          </div>
        </div>
      </div>
    </AdminLayout>
  );
}

export default Schedules;
