/// 일정 화면 (MVCS의 View 레이어)
///
/// UI 렌더링만 담당하고, 비즈니스 로직은 Controller에 위임합니다.
library;

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:expandable_page_view/expandable_page_view.dart';
import 'package:go_router/go_router.dart';
import '../../core/constants.dart';
import '../../models/schedule.dart';
import '../../controllers/schedule_controller.dart';
import 'widgets/schedule_card.dart';
import 'widgets/search_card.dart';

class ScheduleView extends ConsumerStatefulWidget {
  const ScheduleView({super.key});

  @override
  ConsumerState<ScheduleView> createState() => _ScheduleViewState();
}

class _ScheduleViewState extends ConsumerState<ScheduleView>
    with SingleTickerProviderStateMixin {
  final ScrollController _dateScrollController = ScrollController();
  final ScrollController _contentScrollController = ScrollController();
  final ScrollController _searchScrollController = ScrollController();
  final TextEditingController _searchInputController = TextEditingController();
  final FocusNode _searchFocusNode = FocusNode();
  DateTime? _lastSelectedDate;

  // 검색 모드 상태
  bool _isSearchMode = false;
  // 추천 검색어 화면 표시 여부 (입력창 포커스 시)
  bool _showSuggestions = false;
  // 디바운스 타이머
  Timer? _debounceTimer;
  // 마지막 검색어 (뒤로가기 시 복원용)
  String _lastSearchTerm = '';

  // 달력 팝업 상태
  bool _showCalendar = false;
  DateTime _calendarViewDate = DateTime.now();
  bool _showYearMonthPicker = false;
  int _yearRangeStart = (DateTime.now().year ~/ 12) * 12;

  // 달력 PageView 컨트롤러
  late PageController _calendarPageController;
  late PageController _yearPageController;
  static const int _initialPage = 1000;

  // 달력 애니메이션
  late AnimationController _calendarAnimController;
  late Animation<double> _calendarAnimation;

  @override
  void initState() {
    super.initState();
    _calendarPageController = PageController(initialPage: _initialPage);
    _yearPageController = PageController(initialPage: _initialPage);
    _calendarAnimController = AnimationController(
      duration: const Duration(milliseconds: 280),
      vsync: this,
    );
    _calendarAnimation = CurvedAnimation(
      parent: _calendarAnimController,
      curve: Curves.easeOut,
      reverseCurve: Curves.easeIn,
    );

    // 검색 무한 스크롤 리스너
    _searchScrollController.addListener(_onSearchScroll);
  }

  /// 검색 스크롤 리스너 (무한 스크롤)
  void _onSearchScroll() {
    // 스크롤이 끝에서 500px 전에 다음 페이지 미리 로드
    if (_searchScrollController.position.pixels >=
        _searchScrollController.position.maxScrollExtent - 500) {
      ref.read(searchProvider.notifier).loadMore();
    }
  }

  /// 검색 모드 진입
  void _enterSearchMode() {
    setState(() {
      _isSearchMode = true;
      _showSuggestions = true;
    });
    // 검색 입력창 포커스
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _searchFocusNode.requestFocus();
    });
  }

  /// 검색 모드 종료
  void _exitSearchMode() {
    _debounceTimer?.cancel();
    setState(() {
      _isSearchMode = false;
      _showSuggestions = false;
      _searchInputController.clear();
    });
    ref.read(searchProvider.notifier).clear();
    ref.read(suggestionProvider.notifier).clear();
    _searchFocusNode.unfocus();
    // 검색 종료 시 선택된 날짜로 스크롤
    final selectedDate = ref.read(scheduleProvider).selectedDate;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _scrollToSelectedDate(selectedDate);
    });
  }

  /// 추천 검색어 화면 표시 (유튜브 스타일)
  void _showSuggestionsScreen() {
    setState(() {
      _showSuggestions = true;
    });
    _searchFocusNode.requestFocus();
  }

  /// 추천 검색어 화면에서 뒤로가기 (검색 결과가 있으면 결과 화면으로)
  void _hideSuggestionsScreen() {
    final searchState = ref.read(searchProvider);
    if (searchState.results.isNotEmpty) {
      // 검색 결과가 있으면 결과 화면으로 (검색어 복원)
      setState(() {
        _showSuggestions = false;
        _searchInputController.text = _lastSearchTerm;
      });
      _searchFocusNode.unfocus();
    } else {
      // 검색 결과가 없으면 검색 모드 종료
      _exitSearchMode();
    }
  }

  /// 검색 실행
  void _onSearch(String query) {
    if (query.trim().isNotEmpty) {
      _lastSearchTerm = query; // 검색어 저장
      ref.read(searchProvider.notifier).search(query);
      ref.read(recentSearchProvider.notifier).addSearch(query); // 최근 검색기록 저장
      setState(() {
        _showSuggestions = false;
      });
      _searchFocusNode.unfocus();
    }
  }

  /// 검색어 입력 변경 (디바운스로 추천 검색어 로드)
  void _onSearchInputChanged(String value) {
    setState(() {}); // X 버튼 표시 갱신

    _debounceTimer?.cancel();
    _debounceTimer = Timer(const Duration(milliseconds: 200), () {
      if (value.trim().isNotEmpty) {
        ref.read(suggestionProvider.notifier).loadSuggestions(value);
      } else {
        ref.read(suggestionProvider.notifier).clear();
      }
    });
  }

  @override
  void dispose() {
    _debounceTimer?.cancel();
    _dateScrollController.dispose();
    _contentScrollController.dispose();
    _searchScrollController.removeListener(_onSearchScroll);
    _searchScrollController.dispose();
    _searchInputController.dispose();
    _searchFocusNode.dispose();
    _calendarPageController.dispose();
    _yearPageController.dispose();
    _calendarAnimController.dispose();
    super.dispose();
  }

  /// 달력 열기
  void _openCalendar(DateTime initialDate) {
    final today = DateTime.now();
    final monthDelta =
        (initialDate.year - today.year) * 12 +
        (initialDate.month - today.month);
    _yearRangeStart = (initialDate.year ~/ 12) * 12;

    // 년도 PageView 페이지 계산
    final baseYearRange = (today.year ~/ 12) * 12;
    final yearPageDelta = (_yearRangeStart - baseYearRange) ~/ 12;

    setState(() {
      _calendarViewDate = initialDate;
      _showCalendar = true;
    });

    // 해당 월로 PageView 이동
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted && _calendarPageController.hasClients) {
        _calendarPageController.jumpToPage(_initialPage + monthDelta);
      }
      if (mounted && _yearPageController.hasClients) {
        _yearPageController.jumpToPage(_initialPage + yearPageDelta);
      }
    });

    _calendarAnimController.forward();
  }

  /// 달력 닫기
  void _closeCalendar() {
    _calendarAnimController.reverse().then((_) {
      if (mounted) {
        setState(() {
          _showCalendar = false;
          _showYearMonthPicker = false;
        });
      }
    });
  }

  /// 선택된 날짜로 스크롤
  void _scrollToSelectedDate(DateTime selectedDate) {
    if (!_dateScrollController.hasClients) return;

    final dayIndex = selectedDate.day - 1;
    const itemWidth = 52.0; // 44 + 8 (gap)
    const horizontalPadding = 8.0; // ListView padding
    final targetOffset =
        (dayIndex * itemWidth) +
        horizontalPadding -
        (MediaQuery.of(context).size.width / 2) +
        (itemWidth / 2);
    _dateScrollController.animateTo(
      targetOffset.clamp(0, _dateScrollController.position.maxScrollExtent),
      duration: const Duration(milliseconds: 220),
      curve: Curves.easeOut,
    );
  }

  /// 날짜 선택 핸들러
  void _onDateSelected(DateTime date) {
    // 일정 목록 맨 위로 즉시 이동
    if (_contentScrollController.hasClients) {
      _contentScrollController.jumpTo(0);
    }
    // Controller에 날짜 선택 요청
    ref.read(scheduleProvider.notifier).selectDate(date);
    // 선택된 날짜로 스크롤
    _scrollToSelectedDate(date);
  }

  /// 요일 이름
  String _getDayName(DateTime date) {
    const days = ['일', '월', '화', '수', '목', '금', '토'];
    return days[date.weekday % 7];
  }

  @override
  Widget build(BuildContext context) {
    final scheduleState = ref.watch(scheduleProvider);
    final searchState = ref.watch(searchProvider);
    final suggestionState = ref.watch(suggestionProvider);
    final controller = ref.read(scheduleProvider.notifier);

    // 날짜가 변경되면 스크롤
    if (!_isSearchMode && _lastSelectedDate != scheduleState.selectedDate) {
      _lastSelectedDate = scheduleState.selectedDate;
      WidgetsBinding.instance.addPostFrameCallback((_) {
        _scrollToSelectedDate(scheduleState.selectedDate);
      });
    }

    // 툴바 + 날짜 선택기 높이
    final safeTop = MediaQuery.of(context).padding.top;
    final overlayTop = safeTop + 56 + 80; // toolbar(56) + date selector(80)

    // 뒤로가기 키 처리 (유튜브 스타일)
    // 추천 검색어 화면 → 검색 결과 화면 (결과 있으면) → 일정 화면
    return PopScope(
      canPop: !_isSearchMode,
      onPopInvokedWithResult: (didPop, result) {
        if (!didPop && _isSearchMode) {
          if (_showSuggestions && searchState.results.isNotEmpty) {
            // 추천 검색어 화면에서 검색 결과가 있으면 결과 화면으로
            _hideSuggestionsScreen();
          } else {
            // 그 외에는 검색 모드 종료
            _exitSearchMode();
          }
        }
      },
      child: Stack(
        children: [
          // 메인 콘텐츠
          Column(
            children: [
              // 툴바 (검색 모드 전환 애니메이션)
              AnimatedSwitcher(
                duration: const Duration(milliseconds: 250),
                switchInCurve: Curves.easeOut,
                switchOutCurve: Curves.easeIn,
                transitionBuilder: (child, animation) {
                  return FadeTransition(opacity: animation, child: child);
                },
                child: _isSearchMode
                    ? KeyedSubtree(
                        key: const ValueKey('search_toolbar'),
                        child: _buildSearchToolbar(),
                      )
                    : KeyedSubtree(
                        key: const ValueKey('normal_toolbar'),
                        child: _buildToolbar(scheduleState, controller),
                      ),
              ),
              // 날짜 선택기 (검색 모드 전환 애니메이션)
              AnimatedSize(
                duration: const Duration(milliseconds: 250),
                curve: Curves.easeOut,
                child: _isSearchMode
                    ? const SizedBox.shrink()
                    : _buildDateSelector(scheduleState, controller),
              ),
              // 일정 목록, 추천 검색어, 또는 검색 결과
              Expanded(
                child: AnimatedSwitcher(
                  duration: const Duration(milliseconds: 200),
                  child: _isSearchMode
                      ? (_showSuggestions
                            ? KeyedSubtree(
                                key: const ValueKey('suggestions'),
                                child: _buildSuggestions(suggestionState),
                              )
                            : KeyedSubtree(
                                key: const ValueKey('search_results'),
                                child: _buildSearchResults(searchState),
                              ))
                      : KeyedSubtree(
                          key: const ValueKey('schedule_list'),
                          child: _buildScheduleList(scheduleState),
                        ),
                ),
              ),
            ],
          ),
          // 달력 팝업 오버레이 (검색 모드가 아닐 때만)
          if (_showCalendar && !_isSearchMode) ...[
            // 배경 오버레이 (날짜 선택기 아래부터)
            Positioned(
              top: overlayTop,
              left: 0,
              right: 0,
              bottom: 0,
              child: AnimatedBuilder(
                animation: _calendarAnimation,
                builder: (context, child) {
                  return GestureDetector(
                    onTap: _closeCalendar,
                    child: Container(
                      color: Colors.black.withValues(
                        alpha: 0.4 * _calendarAnimation.value,
                      ),
                    ),
                  );
                },
              ),
            ),
            // 달력 팝업 (애니메이션)
            Positioned(
              top: safeTop + 56,
              left: 0,
              right: 0,
              child: _buildCalendarPopup(scheduleState, controller),
            ),
          ],
        ],
      ),
    );
  }

  /// 검색 툴바 빌드
  Widget _buildSearchToolbar() {
    return Container(
      color: Colors.white,
      child: SafeArea(
        bottom: false,
        child: Container(
          height: 56,
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
          child: Row(
            children: [
              // 검색 입력창
              Expanded(
                child: Container(
                  height: 40,
                  decoration: BoxDecoration(
                    color: AppColors.background,
                    borderRadius: BorderRadius.circular(20),
                  ),
                  child: Row(
                    children: [
                      const SizedBox(width: 16),
                      const Icon(
                        Icons.search,
                        size: 18,
                        color: AppColors.textTertiary,
                      ),
                      const SizedBox(width: 8),
                      Expanded(
                        child: TextField(
                          controller: _searchInputController,
                          focusNode: _searchFocusNode,
                          style: const TextStyle(
                            fontFamily: 'Pretendard',
                            fontSize: 14,
                          ),
                          decoration: const InputDecoration(
                            hintText: '일정 검색...',
                            hintStyle: TextStyle(
                              fontFamily: 'Pretendard',
                              fontSize: 14,
                              color: AppColors.textTertiary,
                            ),
                            border: InputBorder.none,
                            contentPadding: EdgeInsets.zero,
                            isDense: true,
                          ),
                          textInputAction: TextInputAction.search,
                          onTap: () {
                            // 입력창 클릭 시 추천 검색어 화면 표시
                            if (!_showSuggestions) {
                              _showSuggestionsScreen();
                            }
                          },
                          onChanged: _onSearchInputChanged,
                          onSubmitted: _onSearch,
                        ),
                      ),
                      // 입력 내용 삭제 버튼 (클릭 시 추천 검색어 화면으로)
                      if (_searchInputController.text.isNotEmpty)
                        GestureDetector(
                          onTap: () {
                            setState(() {
                              _searchInputController.clear();
                              _showSuggestions = true;
                            });
                            ref.read(suggestionProvider.notifier).clear();
                            _searchFocusNode.requestFocus();
                          },
                          child: const Padding(
                            padding: EdgeInsets.all(8),
                            child: Icon(
                              Icons.close,
                              size: 18,
                              color: AppColors.textTertiary,
                            ),
                          ),
                        )
                      else
                        const SizedBox(width: 8),
                    ],
                  ),
                ),
              ),
              const SizedBox(width: 12),
              // 취소 버튼
              GestureDetector(
                onTap: _exitSearchMode,
                child: const Text(
                  '취소',
                  style: TextStyle(
                    fontFamily: 'Pretendard',
                    fontSize: 14,
                    color: AppColors.textSecondary,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  /// 추천 검색어 빌드 (유튜브 스타일)
  Widget _buildSuggestions(SuggestionState suggestionState) {
    final recentSearchState = ref.watch(recentSearchProvider);

    // 입력값이 없을 때 - 최근 검색기록 표시
    if (_searchInputController.text.isEmpty) {
      if (recentSearchState.searches.isEmpty) {
        return Padding(
          padding: const EdgeInsets.only(top: 100),
          child: Align(
            alignment: Alignment.topCenter,
            child: Text(
              '검색어를 입력하세요',
              style: const TextStyle(
                fontFamily: 'Pretendard',
                fontSize: 14,
                color: AppColors.textTertiary,
              ),
            ),
          ),
        );
      }
      // 최근 검색기록 목록
      return _buildRecentSearches(recentSearchState.searches);
    }

    // 추천 검색어 없음
    if (suggestionState.suggestions.isEmpty) {
      return Padding(
        padding: const EdgeInsets.only(top: 100),
        child: Align(
          alignment: Alignment.topCenter,
          child: Text(
            '추천 검색어가 없습니다',
            style: const TextStyle(
              fontFamily: 'Pretendard',
              fontSize: 14,
              color: AppColors.textTertiary,
            ),
          ),
        ),
      );
    }

    // 추천 검색어 목록
    return ListView.builder(
      padding: const EdgeInsets.symmetric(horizontal: 16),
      itemCount: suggestionState.suggestions.length,
      itemBuilder: (context, index) {
        final suggestion = suggestionState.suggestions[index];
        return GestureDetector(
          onTap: () {
            _searchInputController.text = suggestion;
            _onSearch(suggestion);
          },
          behavior: HitTestBehavior.opaque,
          child: Container(
            padding: const EdgeInsets.symmetric(vertical: 14),
            decoration: BoxDecoration(
              border: Border(
                bottom: BorderSide(
                  color: AppColors.divider.withValues(alpha: 0.5),
                  width: 1,
                ),
              ),
            ),
            child: Row(
              children: [
                const Icon(
                  Icons.search,
                  size: 18,
                  color: AppColors.textTertiary,
                ),
                const SizedBox(width: 16),
                Expanded(
                  child: Text(
                    suggestion,
                    style: const TextStyle(
                      fontFamily: 'Pretendard',
                      fontSize: 15,
                      color: AppColors.textPrimary,
                    ),
                  ),
                ),
                // 화살표 아이콘 (검색어를 입력창에 채우기)
                GestureDetector(
                  onTap: () {
                    _searchInputController.text = suggestion;
                    _searchInputController.selection =
                        TextSelection.fromPosition(
                          TextPosition(offset: suggestion.length),
                        );
                    _onSearchInputChanged(suggestion);
                  },
                  child: const Padding(
                    padding: EdgeInsets.all(4),
                    child: Icon(
                      Icons.north_west,
                      size: 16,
                      color: AppColors.textTertiary,
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  /// 최근 검색기록 빌드
  Widget _buildRecentSearches(List<String> searches) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // 헤더
        Padding(
          padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              const Text(
                '최근 검색',
                style: TextStyle(
                  fontFamily: 'Pretendard',
                  fontSize: 14,
                  fontWeight: FontWeight.w600,
                  color: AppColors.textSecondary,
                ),
              ),
              GestureDetector(
                onTap: () {
                  ref.read(recentSearchProvider.notifier).clearAll();
                },
                child: const Text(
                  '전체 삭제',
                  style: TextStyle(
                    fontFamily: 'Pretendard',
                    fontSize: 12,
                    color: AppColors.textTertiary,
                  ),
                ),
              ),
            ],
          ),
        ),
        // 검색기록 목록
        Expanded(
          child: ListView.builder(
            padding: const EdgeInsets.symmetric(horizontal: 16),
            itemCount: searches.length,
            itemBuilder: (context, index) {
              final search = searches[index];
              return GestureDetector(
                onTap: () {
                  _searchInputController.text = search;
                  _onSearch(search);
                },
                behavior: HitTestBehavior.opaque,
                child: Container(
                  padding: const EdgeInsets.symmetric(vertical: 14),
                  decoration: BoxDecoration(
                    border: Border(
                      bottom: BorderSide(
                        color: AppColors.divider.withValues(alpha: 0.5),
                        width: 1,
                      ),
                    ),
                  ),
                  child: Row(
                    children: [
                      const Icon(
                        Icons.history,
                        size: 18,
                        color: AppColors.textTertiary,
                      ),
                      const SizedBox(width: 16),
                      Expanded(
                        child: Text(
                          search,
                          style: const TextStyle(
                            fontFamily: 'Pretendard',
                            fontSize: 15,
                            color: AppColors.textPrimary,
                          ),
                        ),
                      ),
                      // 삭제 버튼
                      GestureDetector(
                        onTap: () {
                          ref.read(recentSearchProvider.notifier).removeSearch(search);
                        },
                        child: const Padding(
                          padding: EdgeInsets.all(4),
                          child: Icon(
                            Icons.close,
                            size: 16,
                            color: AppColors.textTertiary,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              );
            },
          ),
        ),
      ],
    );
  }

  /// 검색 결과 빌드
  Widget _buildSearchResults(SearchState searchState) {
    // 검색어가 없을 때
    if (searchState.searchTerm.isEmpty) {
      return Padding(
        padding: const EdgeInsets.only(top: 100),
        child: Align(
          alignment: Alignment.topCenter,
          child: Text(
            '검색어를 입력하세요',
            style: const TextStyle(
              fontFamily: 'Pretendard',
              fontSize: 14,
              color: AppColors.textTertiary,
            ),
          ),
        ),
      );
    }

    // 로딩 중
    if (searchState.isLoading) {
      return Padding(
        padding: const EdgeInsets.only(top: 100),
        child: Align(
          alignment: Alignment.topCenter,
          child: const CircularProgressIndicator(color: AppColors.primary),
        ),
      );
    }

    // 검색 결과 없음
    if (searchState.results.isEmpty) {
      return Padding(
        padding: const EdgeInsets.only(top: 100),
        child: Align(
          alignment: Alignment.topCenter,
          child: Text(
            '검색 결과가 없습니다',
            style: const TextStyle(
              fontFamily: 'Pretendard',
              fontSize: 14,
              color: AppColors.textTertiary,
            ),
          ),
        ),
      );
    }

    // 검색 결과 목록 (화면 전체 페이드 애니메이션)
    return AnimatedSwitcher(
      duration: const Duration(milliseconds: 200),
      child: ListView.builder(
        key: ValueKey('search_list_${searchState.searchTerm}'),
        controller: _searchScrollController,
        padding: const EdgeInsets.all(16),
        itemCount:
            searchState.results.length + (searchState.isFetchingMore ? 1 : 0),
        itemBuilder: (context, index) {
          // 로딩 인디케이터
          if (index >= searchState.results.length) {
            return const Padding(
              padding: EdgeInsets.symmetric(vertical: 16),
              child: Center(
                child: SizedBox(
                  width: 24,
                  height: 24,
                  child: CircularProgressIndicator(
                    color: AppColors.primary,
                    strokeWidth: 2,
                  ),
                ),
              ),
            );
          }

          final schedule = searchState.results[index];
          return Padding(
            padding: EdgeInsets.only(
              bottom: index < searchState.results.length - 1 ? 12 : 0,
            ),
            child: GestureDetector(
              onTap: schedule.isSpecial ? null : () => context.push('/schedule/${schedule.id}'),
              child: SearchScheduleCard(
                schedule: schedule,
                categoryColor: parseColor(schedule.categoryColor),
              ),
            ),
          );
        },
      ),
    );
  }

  /// 툴바 빌드
  Widget _buildToolbar(ScheduleState state, ScheduleController controller) {
    // 달력이 열려있을 때는 달력 뷰 날짜 기준, 아니면 선택된 날짜 기준
    final displayDate = _showCalendar ? _calendarViewDate : state.selectedDate;
    final yearMonthText = '${displayDate.year}년 ${displayDate.month}월';

    return Container(
      color: Colors.white,
      child: SafeArea(
        bottom: false,
        child: Container(
          height: 56,
          padding: const EdgeInsets.symmetric(horizontal: 4),
          child: Row(
            children: [
              // 달력 아이콘
              IconButton(
                onPressed: () {
                  if (_showCalendar) {
                    _closeCalendar();
                  } else {
                    _openCalendar(state.selectedDate);
                  }
                },
                icon: const Icon(Icons.calendar_today_outlined, size: 20),
                color: _showCalendar
                    ? AppColors.primary
                    : AppColors.textSecondary,
              ),
              // 이전 월 (데이트픽커가 펼쳐지면 숨김, 페이드 애니메이션)
              AnimatedSwitcher(
                duration: const Duration(milliseconds: 200),
                child: !_showYearMonthPicker
                    ? IconButton(
                        key: const ValueKey('prev_button'),
                        onPressed: () {
                          if (_showCalendar) {
                            _calendarPageController.previousPage(
                              duration: const Duration(milliseconds: 300),
                              curve: Curves.easeInOut,
                            );
                          } else {
                            controller.changeMonth(-1);
                          }
                        },
                        icon: const Icon(Icons.chevron_left, size: 24),
                        color: AppColors.textPrimary,
                      )
                    : const SizedBox(key: ValueKey('prev_empty'), width: 48),
              ),
              // 년월 표시
              Expanded(
                child: GestureDetector(
                  behavior: HitTestBehavior.opaque,
                  onTap: _showCalendar
                      ? () {
                          setState(() {
                            _showYearMonthPicker = !_showYearMonthPicker;
                            _yearRangeStart =
                                (_calendarViewDate.year ~/ 12) * 12;
                          });
                        }
                      : null,
                  child: Center(
                    child: Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        // 화살표 공간 (왼쪽에 보이지 않는 공간으로 균형, 페이드 애니메이션)
                        AnimatedSwitcher(
                          duration: const Duration(milliseconds: 200),
                          child: _showCalendar
                              ? const SizedBox(
                                  key: ValueKey('arrow_space'),
                                  width: 20,
                                )
                              : const SizedBox(
                                  key: ValueKey('no_space'),
                                  width: 0,
                                ),
                        ),
                        // 년월 텍스트 (항상 가운데 고정)
                        Text(
                          yearMonthText,
                          style: TextStyle(
                            fontFamily: 'Pretendard',
                            fontSize: 16,
                            fontWeight: FontWeight.bold,
                            color: _showYearMonthPicker
                                ? AppColors.primary
                                : AppColors.textPrimary,
                          ),
                        ),
                        // 드롭다운 화살표 (페이드 애니메이션)
                        AnimatedSwitcher(
                          duration: const Duration(milliseconds: 200),
                          child: _showCalendar
                              ? Row(
                                  key: ValueKey(
                                    'dropdown_$_showYearMonthPicker',
                                  ),
                                  mainAxisSize: MainAxisSize.min,
                                  children: [
                                    const SizedBox(width: 2),
                                    Icon(
                                      _showYearMonthPicker
                                          ? Icons.keyboard_arrow_up
                                          : Icons.keyboard_arrow_down,
                                      size: 18,
                                      color: _showYearMonthPicker
                                          ? AppColors.primary
                                          : AppColors.textPrimary,
                                    ),
                                  ],
                                )
                              : const SizedBox(
                                  key: ValueKey('no_dropdown'),
                                  width: 0,
                                ),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
              // 다음 월 (데이트픽커가 펼쳐지면 숨김, 페이드 애니메이션)
              AnimatedSwitcher(
                duration: const Duration(milliseconds: 200),
                child: !_showYearMonthPicker
                    ? IconButton(
                        key: const ValueKey('next_button'),
                        onPressed: () {
                          if (_showCalendar) {
                            _calendarPageController.nextPage(
                              duration: const Duration(milliseconds: 300),
                              curve: Curves.easeInOut,
                            );
                          } else {
                            controller.changeMonth(1);
                          }
                        },
                        icon: const Icon(Icons.chevron_right, size: 24),
                        color: AppColors.textPrimary,
                      )
                    : const SizedBox(key: ValueKey('next_empty'), width: 48),
              ),
              // 검색 아이콘
              IconButton(
                onPressed: _enterSearchMode,
                icon: const Icon(Icons.search, size: 20),
                color: AppColors.textSecondary,
              ),
            ],
          ),
        ),
      ),
    );
  }

  /// 달력 팝업 빌드
  Widget _buildCalendarPopup(
    ScheduleState state,
    ScheduleController controller,
  ) {
    return AnimatedBuilder(
      animation: _calendarAnimation,
      builder: (context, child) {
        return ClipRect(
          child: Align(
            alignment: Alignment.topCenter,
            heightFactor: _calendarAnimation.value,
            child: Opacity(opacity: _calendarAnimation.value, child: child),
          ),
        );
      },
      child: Material(
        color: Colors.white,
        elevation: 0,
        child: AnimatedSize(
          duration: const Duration(milliseconds: 200),
          curve: Curves.easeOut,
          alignment: Alignment.topCenter,
          child: AnimatedSwitcher(
            duration: const Duration(milliseconds: 150),
            switchInCurve: Curves.easeOut,
            switchOutCurve: Curves.easeIn,
            layoutBuilder: (currentChild, previousChildren) {
              // 콘텐츠를 항상 상단에 고정
              return Stack(
                alignment: Alignment.topCenter,
                children: [
                  ...previousChildren,
                  if (currentChild != null) currentChild,
                ],
              );
            },
            transitionBuilder: (child, animation) {
              // 년월 선택기에만 슬라이드 효과 추가
              final isYearMonthPicker =
                  child.key == const ValueKey('yearMonth');
              if (isYearMonthPicker) {
                return FadeTransition(
                  opacity: animation,
                  child: SlideTransition(
                    position: Tween<Offset>(
                      begin: const Offset(0, -0.05),
                      end: Offset.zero,
                    ).animate(animation),
                    child: child,
                  ),
                );
              }
              return FadeTransition(opacity: animation, child: child);
            },
            child: _showYearMonthPicker
                ? KeyedSubtree(
                    key: const ValueKey('yearMonth'),
                    child: _buildYearMonthPicker(),
                  )
                : KeyedSubtree(
                    key: const ValueKey('calendar'),
                    child: _buildCalendarGrid(state, controller),
                  ),
          ),
        ),
      ),
    );
  }

  /// 년월 선택기
  Widget _buildYearMonthPicker() {
    final today = DateTime.now();

    return Padding(
      padding: const EdgeInsets.fromLTRB(16, 4, 16, 16),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          // 년도 범위 헤더
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              IconButton(
                onPressed: () {
                  _yearPageController.previousPage(
                    duration: const Duration(milliseconds: 300),
                    curve: Curves.easeInOut,
                  );
                },
                icon: const Icon(Icons.chevron_left, size: 20),
                color: AppColors.textPrimary,
                splashRadius: 20,
                padding: EdgeInsets.zero,
                constraints: const BoxConstraints(minWidth: 40, minHeight: 40),
              ),
              Text(
                '$_yearRangeStart - ${_yearRangeStart + 11}',
                style: const TextStyle(
                  fontFamily: 'Pretendard',
                  fontSize: 14,
                  fontWeight: FontWeight.w600,
                ),
              ),
              IconButton(
                onPressed: () {
                  _yearPageController.nextPage(
                    duration: const Duration(milliseconds: 300),
                    curve: Curves.easeInOut,
                  );
                },
                icon: const Icon(Icons.chevron_right, size: 20),
                color: AppColors.textPrimary,
                splashRadius: 20,
                padding: EdgeInsets.zero,
                constraints: const BoxConstraints(minWidth: 40, minHeight: 40),
              ),
            ],
          ),
          const SizedBox(height: 8),
          // 년도 라벨
          const Text(
            '년도',
            style: TextStyle(
              fontFamily: 'Pretendard',
              fontSize: 12,
              color: AppColors.textTertiary,
            ),
          ),
          const SizedBox(height: 4),
          // 년도 그리드 (ExpandablePageView로 스와이프 애니메이션)
          ExpandablePageView.builder(
            controller: _yearPageController,
            itemCount: _initialPage * 2,
            onPageChanged: (page) {
              final delta = page - _initialPage;
              final baseYearRange = (today.year ~/ 12) * 12;
              setState(() {
                _yearRangeStart = baseYearRange + (delta * 12);
              });
            },
            itemBuilder: (context, page) {
              final delta = page - _initialPage;
              final baseYearRange = (today.year ~/ 12) * 12;
              final rangeStart = baseYearRange + (delta * 12);
              final yearRange = List.generate(12, (i) => rangeStart + i);
              return _buildYearGrid(yearRange: yearRange, today: today);
            },
          ),
          const SizedBox(height: 16),
          // 월 라벨
          const Text(
            '월',
            style: TextStyle(
              fontFamily: 'Pretendard',
              fontSize: 12,
              color: AppColors.textTertiary,
            ),
          ),
          const SizedBox(height: 4),
          // 월 그리드
          GridView.builder(
            shrinkWrap: true,
            padding: EdgeInsets.zero,
            physics: const NeverScrollableScrollPhysics(),
            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 4,
              mainAxisSpacing: 6,
              crossAxisSpacing: 8,
              childAspectRatio: 2.0,
            ),
            itemCount: 12,
            itemBuilder: (context, index) {
              final month = index + 1;
              final isSelected = month == _calendarViewDate.month;
              final isCurrentMonth =
                  month == today.month && _calendarViewDate.year == today.year;
              return GestureDetector(
                onTap: () {
                  setState(() {
                    _calendarViewDate = DateTime(
                      _calendarViewDate.year,
                      month,
                      1,
                    );
                    _showYearMonthPicker = false;
                  });
                },
                child: AnimatedContainer(
                  duration: const Duration(milliseconds: 150),
                  curve: Curves.easeOut,
                  decoration: BoxDecoration(
                    color: isSelected ? AppColors.primary : Colors.transparent,
                    borderRadius: BorderRadius.circular(8),
                  ),
                  alignment: Alignment.center,
                  child: AnimatedDefaultTextStyle(
                    duration: const Duration(milliseconds: 150),
                    style: TextStyle(
                      fontFamily: 'Pretendard',
                      fontSize: 14,
                      fontWeight: isSelected || isCurrentMonth
                          ? FontWeight.w600
                          : FontWeight.w400,
                      color: isSelected
                          ? Colors.white
                          : isCurrentMonth
                          ? AppColors.primary
                          : AppColors.textPrimary,
                    ),
                    child: Text('$month월'),
                  ),
                ),
              );
            },
          ),
        ],
      ),
    );
  }

  /// 특정 월의 달력 데이터 생성
  List<DateTime> _getMonthDays(int year, int month) {
    final firstDay = DateTime(year, month, 1);
    final lastDay = DateTime(year, month + 1, 0);
    final startWeekday = firstDay.weekday % 7;
    final daysInMonth = lastDay.day;

    final prevMonth = DateTime(year, month, 0);
    final prevMonthDays = List.generate(
      startWeekday,
      (i) => DateTime(year, month - 1, prevMonth.day - startWeekday + 1 + i),
    );

    final currentMonthDays = List.generate(
      daysInMonth,
      (i) => DateTime(year, month, i + 1),
    );

    final totalDays = prevMonthDays.length + currentMonthDays.length;
    final remaining = (7 - (totalDays % 7)) % 7;
    final nextMonthDays = List.generate(
      remaining,
      (i) => DateTime(year, month + 1, i + 1),
    );

    return [...prevMonthDays, ...currentMonthDays, ...nextMonthDays];
  }

  /// 년도 그리드 위젯
  Widget _buildYearGrid({
    required List<int> yearRange,
    required DateTime today,
  }) {
    return GridView.builder(
      shrinkWrap: true,
      padding: EdgeInsets.zero,
      physics: const NeverScrollableScrollPhysics(),
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 4,
        mainAxisSpacing: 6,
        crossAxisSpacing: 8,
        childAspectRatio: 2.0,
      ),
      itemCount: 12,
      itemBuilder: (context, index) {
        final year = yearRange[index];
        final isSelected = year == _calendarViewDate.year;
        final isCurrentYear = year == today.year;
        return GestureDetector(
          onTap: () {
            setState(() {
              _calendarViewDate = DateTime(year, _calendarViewDate.month, 1);
            });
          },
          child: AnimatedContainer(
            duration: const Duration(milliseconds: 150),
            curve: Curves.easeOut,
            decoration: BoxDecoration(
              color: isSelected ? AppColors.primary : Colors.transparent,
              borderRadius: BorderRadius.circular(8),
            ),
            alignment: Alignment.center,
            child: AnimatedDefaultTextStyle(
              duration: const Duration(milliseconds: 150),
              style: TextStyle(
                fontFamily: 'Pretendard',
                fontSize: 14,
                fontWeight: isSelected || isCurrentYear
                    ? FontWeight.w600
                    : FontWeight.w400,
                color: isSelected
                    ? Colors.white
                    : isCurrentYear
                    ? AppColors.primary
                    : AppColors.textPrimary,
              ),
              child: Text('$year'),
            ),
          ),
        );
      },
    );
  }

  /// 달력 그리드
  Widget _buildCalendarGrid(
    ScheduleState state,
    ScheduleController controller,
  ) {
    return Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          // 요일 헤더
          Row(
            children: ['일', '월', '화', '수', '목', '금', '토'].asMap().entries.map((
              entry,
            ) {
              final index = entry.key;
              final day = entry.value;
              return Expanded(
                child: Center(
                  child: Text(
                    day,
                    style: TextStyle(
                      fontFamily: 'Pretendard',
                      fontSize: 12,
                      fontWeight: FontWeight.w500,
                      color: index == 0
                          ? Colors.red.shade400
                          : index == 6
                          ? Colors.blue.shade400
                          : AppColors.textSecondary,
                    ),
                  ),
                ),
              );
            }).toList(),
          ),
          const SizedBox(height: 16),
          // 날짜 그리드 (ExpandablePageView로 높이 자동 조절)
          ExpandablePageView.builder(
            controller: _calendarPageController,
            itemCount: _initialPage * 2, // 충분히 큰 범위
            onPageChanged: (page) {
              final delta = page - _initialPage;
              final newDate = DateTime(
                DateTime.now().year,
                DateTime.now().month + delta,
                1,
              );
              setState(() {
                _calendarViewDate = newDate;
              });
              // 해당 월의 일정을 비동기로 로드 (점 표시용)
              controller.loadCalendarMonth(newDate.year, newDate.month);
            },
            itemBuilder: (context, page) {
              final delta = page - _initialPage;
              final targetDate = DateTime(
                DateTime.now().year,
                DateTime.now().month + delta,
                1,
              );
              // 해당 월의 일정이 캐시에 없으면 비동기 로드
              if (!state.hasMonthCache(targetDate.year, targetDate.month)) {
                controller.loadCalendarMonth(targetDate.year, targetDate.month);
              }
              final allDays = _getMonthDays(targetDate.year, targetDate.month);
              return _buildCalendarDaysGrid(
                allDays: allDays,
                month: targetDate.month,
                state: state,
                controller: controller,
              );
            },
          ),
          const SizedBox(height: 16),
          // 오늘 버튼
          GestureDetector(
            onTap: () {
              final today = DateTime.now();
              controller.goToDate(today);
              if (_contentScrollController.hasClients) {
                _contentScrollController.jumpTo(0);
              }
              _calendarPageController.jumpToPage(_initialPage);
              _closeCalendar();
            },
            child: Container(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
              decoration: BoxDecoration(
                color: AppColors.primary.withValues(alpha: 0.1),
                borderRadius: BorderRadius.circular(20),
              ),
              child: const Text(
                '오늘',
                style: TextStyle(
                  fontSize: 12,
                  fontWeight: FontWeight.w600,
                  color: AppColors.primary,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  /// 날짜 그리드
  Widget _buildCalendarDaysGrid({
    required List<DateTime> allDays,
    required int month,
    required ScheduleState state,
    required ScheduleController controller,
  }) {
    return GridView.builder(
      shrinkWrap: true,
      clipBehavior: Clip.none,
      padding: const EdgeInsets.only(top: 4),
      physics: const NeverScrollableScrollPhysics(),
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 7,
        mainAxisSpacing: 6,
        crossAxisSpacing: 4,
        mainAxisExtent: 50, // Container(36) + SizedBox(6) + 여백
      ),
      itemCount: allDays.length,
      itemBuilder: (context, index) {
        final date = allDays[index];
        final isCurrentMonth = date.month == month;
        final isSelected = controller.isSelected(date);
        final isToday = controller.isToday(date);
        final dayOfWeek = index % 7;
        final daySchedules = isCurrentMonth
            ? state.getDaySchedules(date)
            : <Schedule>[];

        return GestureDetector(
          onTap: () {
            controller.goToDate(date);
            if (_contentScrollController.hasClients) {
              _contentScrollController.jumpTo(0);
            }
            _closeCalendar();
          },
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                width: 36,
                height: 36,
                decoration: BoxDecoration(
                  color: isSelected ? AppColors.primary : Colors.transparent,
                  shape: BoxShape.circle,
                  boxShadow: isSelected
                      ? [
                          BoxShadow(
                            color: AppColors.primary.withValues(alpha: 0.3),
                            blurRadius: 4,
                          ),
                        ]
                      : null,
                ),
                alignment: Alignment.center,
                child: Text(
                  '${date.day}',
                  style: TextStyle(
                    fontFamily: 'Pretendard',
                    fontSize: 14,
                    fontWeight: isSelected || isToday
                        ? FontWeight.bold
                        : FontWeight.w400,
                    color: !isCurrentMonth
                        ? AppColors.textTertiary.withValues(alpha: 0.5)
                        : isSelected
                        ? Colors.white
                        : isToday
                        ? AppColors.primary
                        : dayOfWeek == 0
                        ? Colors.red.shade500
                        : dayOfWeek == 6
                        ? Colors.blue.shade500
                        : AppColors.textPrimary,
                  ),
                ),
              ),
              SizedBox(
                height: 6,
                child: !isSelected && daySchedules.isNotEmpty
                    ? Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: daySchedules.map((schedule) {
                          return Container(
                            width: 4,
                            height: 4,
                            margin: const EdgeInsets.symmetric(horizontal: 1),
                            decoration: BoxDecoration(
                              color: parseColor(schedule.categoryColor),
                              shape: BoxShape.circle,
                            ),
                          );
                        }).toList(),
                      )
                    : const SizedBox.shrink(),
              ),
            ],
          ),
        );
      },
    );
  }

  /// 날짜 선택기 빌드
  Widget _buildDateSelector(
    ScheduleState state,
    ScheduleController controller,
  ) {
    return Container(
      height: 80,
      color: Colors.white,
      child: ListView.builder(
        controller: _dateScrollController,
        scrollDirection: Axis.horizontal,
        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
        itemCount: state.daysInMonth.length,
        itemBuilder: (context, index) {
          final date = state.daysInMonth[index];
          final isSelected = controller.isSelected(date);
          final isToday = controller.isToday(date);
          final dayOfWeek = date.weekday;
          final daySchedules = state.getDaySchedules(date);

          return GestureDetector(
            onTap: () => _onDateSelected(date),
            child: Container(
              width: 44,
              margin: const EdgeInsets.symmetric(horizontal: 4),
              decoration: BoxDecoration(
                color: isSelected ? AppColors.primary : Colors.transparent,
                borderRadius: BorderRadius.circular(12),
              ),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  // 요일
                  Text(
                    _getDayName(date),
                    style: TextStyle(
                      fontSize: 10,
                      fontWeight: FontWeight.w500,
                      color: isSelected
                          ? Colors.white.withValues(alpha: 0.8)
                          : dayOfWeek == 7
                          ? Colors.red.shade400
                          : dayOfWeek == 6
                          ? Colors.blue.shade400
                          : AppColors.textTertiary,
                    ),
                  ),
                  const SizedBox(height: 4),
                  // 날짜
                  Text(
                    '${date.day}',
                    style: TextStyle(
                      fontSize: 14,
                      fontWeight: FontWeight.w600,
                      color: isSelected
                          ? Colors.white
                          : isToday
                          ? AppColors.primary
                          : AppColors.textPrimary,
                    ),
                  ),
                  const SizedBox(height: 4),
                  // 일정 점 (최대 3개)
                  SizedBox(
                    height: 6,
                    child: !isSelected && daySchedules.isNotEmpty
                        ? Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: daySchedules.map((schedule) {
                              return Container(
                                width: 4,
                                height: 4,
                                margin: const EdgeInsets.symmetric(
                                  horizontal: 1,
                                ),
                                decoration: BoxDecoration(
                                  color: parseColor(schedule.categoryColor),
                                  shape: BoxShape.circle,
                                ),
                              );
                            }).toList(),
                          )
                        : const SizedBox.shrink(),
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }

  /// 일정 목록 빌드
  Widget _buildScheduleList(ScheduleState state) {
    if (state.isLoading) {
      return const Center(
        child: CircularProgressIndicator(color: AppColors.primary),
      );
    }

    if (state.selectedDateSchedules.isEmpty) {
      return Center(
        child: Text(
          '${state.selectedDate.month}월 ${state.selectedDate.day}일 일정이 없습니다',
          style: const TextStyle(fontSize: 14, color: AppColors.textTertiary),
        ),
      );
    }

    return ListView.builder(
      controller: _contentScrollController,
      padding: const EdgeInsets.all(16),
      itemCount: state.selectedDateSchedules.length,
      itemBuilder: (context, index) {
        final schedule = state.selectedDateSchedules[index];

        // 특별 일정 카드 (생일/데뷔/기념일)
        Widget card;
        if (schedule.isBirthday) {
          card = BirthdayCard(schedule: schedule);
        } else if (schedule.isDebut || schedule.isAnniversary) {
          card = DebutCard(schedule: schedule);
        } else {
          card = GestureDetector(
            onTap: () => context.push('/schedule/${schedule.id}'),
            child: AnimatedScheduleCard(
              key: ValueKey('${schedule.id}_${state.selectedDate.toString()}'),
              index: index,
              schedule: schedule,
              categoryColor: parseColor(schedule.categoryColor),
            ),
          );
        }

        return Padding(
          padding: EdgeInsets.only(
            bottom: index < state.selectedDateSchedules.length - 1 ? 12 : 0,
          ),
          child: card,
        );
      },
    );
  }
}
