import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:table_calendar/table_calendar.dart';
import '../../../core/constants/app_colors.dart';
import '../../../core/constants/app_typography.dart';
import '../../../domain/entities/restaurant.dart';
import '../../../domain/entities/recommendation_record.dart';
import '../../../domain/entities/visit_record.dart';
import '../../providers/recommendation_provider.dart';
import '../../providers/settings_provider.dart';
import '../../providers/restaurant_provider.dart';
import '../../providers/visit_provider.dart';
import '../../widgets/native_ad_placeholder.dart';
import '../restaurant_list/widgets/edit_restaurant_dialog.dart';
import 'widgets/visit_record_card.dart';
import 'widgets/recommendation_record_card.dart';
import 'widgets/visit_statistics.dart';

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

  @override
  ConsumerState<CalendarScreen> createState() => _CalendarScreenState();
}

class _CalendarScreenState extends ConsumerState<CalendarScreen>
    with SingleTickerProviderStateMixin {
  late DateTime _selectedDay;
  late DateTime _focusedDay;
  late DateTime _selectedMonth;
  late DateTime _firstDay;
  late DateTime _lastDay;
  CalendarFormat _calendarFormat = CalendarFormat.month;
  late TabController _tabController;
  Map<DateTime, List<_CalendarEvent>> _events = {};

  @override
  void initState() {
    super.initState();
    final now = DateTime.now();
    _selectedDay = now;
    _focusedDay = now;
    _selectedMonth = DateTime(now.year, now.month, 1);
    _firstDay = DateTime(now.year - 1, now.month, 1);
    _lastDay = DateTime(now.year + 1, now.month, now.day);
    _tabController = TabController(length: 2, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  List<_CalendarEvent> _getEventsForDay(DateTime day) {
    final normalizedDay = DateTime(day.year, day.month, day.day);
    return _events[normalizedDay] ?? [];
  }

  @override
  Widget build(BuildContext context) {
    final isDark = Theme.of(context).brightness == Brightness.dark;
    final visitRecordsAsync = ref.watch(visitRecordsProvider);
    final recommendationRecordsAsync = ref.watch(recommendationRecordsProvider);
    final screenshotModeEnabled = ref
        .watch(screenshotModeEnabledProvider)
        .maybeWhen(data: (value) => value, orElse: () => false);

    final visits = visitRecordsAsync.value ?? <VisitRecord>[];
    final recommendations =
        recommendationRecordsAsync.valueOrNull ?? <RecommendationRecord>[];

    if (visitRecordsAsync.hasValue && recommendationRecordsAsync.hasValue) {
      _events = _buildEvents(visits, recommendations);
      _updateCalendarRange(visits, recommendations);
    }

    final monthOptions = _buildMonthOptions(_firstDay, _lastDay);

    return Scaffold(
      backgroundColor: isDark
          ? AppColors.darkBackground
          : AppColors.lightBackground,
      appBar: AppBar(
        title: const Text('방문 기록'),
        backgroundColor: isDark
            ? AppColors.darkPrimary
            : AppColors.lightPrimary,
        foregroundColor: Colors.white,
        elevation: 0,
        bottom: TabBar(
          controller: _tabController,
          indicatorColor: Colors.white,
          indicatorWeight: 3,
          tabs: const [
            Tab(text: '캘린더'),
            Tab(text: '통계'),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          // 캘린더 탭
          _buildCalendarTab(isDark: isDark, adsEnabled: !screenshotModeEnabled),
          // 통계 탭
          VisitStatistics(
            selectedMonth: _selectedMonth,
            availableMonths: monthOptions,
            onMonthChanged: _onMonthChanged,
            adsEnabled: !screenshotModeEnabled,
          ),
        ],
      ),
    );
  }

  Widget _buildCalendarTab({required bool isDark, bool adsEnabled = true}) {
    final visitColor = _visitMarkerColor(isDark);
    final recommendationColor = _recommendationMarkerColor(isDark);

    return LayoutBuilder(
      builder: (context, constraints) {
        return SingleChildScrollView(
          padding: const EdgeInsets.only(bottom: 16),
          child: ConstrainedBox(
            constraints: BoxConstraints(minHeight: constraints.maxHeight),
            child: Column(
              children: [
                Card(
                  margin: const EdgeInsets.all(16),
                  color: isDark
                      ? AppColors.darkSurface
                      : AppColors.lightSurface,
                  elevation: 2,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: TableCalendar(
                    firstDay: _firstDay,
                    lastDay: _lastDay,
                    focusedDay: _focusedDay,
                    calendarFormat: _calendarFormat,
                    selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
                    onDaySelected: (selectedDay, focusedDay) {
                      setState(() {
                        _selectedDay = selectedDay;
                        _focusedDay = focusedDay;
                        _selectedMonth = DateTime(
                          focusedDay.year,
                          focusedDay.month,
                          1,
                        );
                      });
                    },
                    onPageChanged: (focusedDay) {
                      setState(() {
                        _focusedDay = focusedDay;
                        _selectedMonth = DateTime(
                          focusedDay.year,
                          focusedDay.month,
                          1,
                        );
                        _selectedDay = focusedDay;
                      });
                    },
                    onFormatChanged: (format) {
                      setState(() {
                        _calendarFormat = format;
                      });
                    },
                    eventLoader: _getEventsForDay,
                    calendarBuilders: CalendarBuilders(
                      markerBuilder: (context, day, events) {
                        if (events.isEmpty) return null;

                        final calendarEvents = events.cast<_CalendarEvent>();
                        final confirmedVisits = calendarEvents.where(
                          (e) => e.visitRecord?.isConfirmed == true,
                        );
                        final recommendedOnly = calendarEvents.where(
                          (e) => e.recommendationRecord != null,
                        );

                        return Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            if (recommendedOnly.isNotEmpty)
                              Container(
                                width: 6,
                                height: 6,
                                margin: const EdgeInsets.symmetric(
                                  horizontal: 1,
                                ),
                                decoration: BoxDecoration(
                                  color: recommendationColor,
                                  shape: BoxShape.circle,
                                ),
                              ),
                            if (confirmedVisits.isNotEmpty)
                              Container(
                                width: 6,
                                height: 6,
                                margin: const EdgeInsets.symmetric(
                                  horizontal: 1,
                                ),
                                decoration: BoxDecoration(
                                  color: visitColor,
                                  shape: BoxShape.circle,
                                ),
                              ),
                          ],
                        );
                      },
                    ),
                    calendarStyle: CalendarStyle(
                      outsideDaysVisible: false,
                      selectedDecoration: const BoxDecoration(
                        color: AppColors.lightPrimary,
                        shape: BoxShape.circle,
                      ),
                      todayDecoration: BoxDecoration(
                        color: AppColors.lightPrimary.withOpacity(0.5),
                        shape: BoxShape.circle,
                      ),
                      markersMaxCount: 2,
                      markerDecoration: BoxDecoration(
                        color: visitColor.withOpacity(0.8),
                        shape: BoxShape.circle,
                      ),
                      weekendTextStyle: const TextStyle(
                        color: AppColors.lightError,
                      ),
                    ),
                    headerStyle: HeaderStyle(
                      formatButtonVisible: true,
                      titleCentered: true,
                      formatButtonShowsNext: false,
                      formatButtonDecoration: BoxDecoration(
                        color: AppColors.lightPrimary.withOpacity(0.1),
                        borderRadius: BorderRadius.circular(12),
                      ),
                      formatButtonTextStyle: const TextStyle(
                        color: AppColors.lightPrimary,
                      ),
                    ),
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      _buildLegend(
                        '추천받음',
                        recommendationColor,
                        isDark,
                        tooltip: '추천 기록이 있는 날',
                        // icon: Icons.star,
                      ),
                      const SizedBox(width: 24),
                      _buildLegend(
                        '방문완료',
                        visitColor,
                        isDark,
                        tooltip: '확정된 방문이 있는 날',
                        // icon: Icons.check_circle,
                      ),
                    ],
                  ),
                ),
                const SizedBox(height: 16),
                NativeAdPlaceholder(
                  enabled: adsEnabled,
                  margin: const EdgeInsets.fromLTRB(16, 0, 16, 16),
                  height: 360,
                ),
                _buildDayRecords(_selectedDay, isDark),
              ],
            ),
          ),
        );
      },
    );
  }

  Widget _buildLegend(
    String label,
    Color color,
    bool isDark, {
    String? tooltip,
    IconData? icon,
  }) {
    final content = Row(
      children: [
        Container(
          width: 14,
          height: 14,
          decoration: BoxDecoration(color: color, shape: BoxShape.circle),
        ),
        const SizedBox(width: 6),
        if (icon != null) ...[
          Icon(icon, size: 14, color: color),
          const SizedBox(width: 4),
        ],
        Text(label, style: AppTypography.body2(isDark)),
      ],
    );

    if (tooltip == null) return content;
    return Tooltip(message: tooltip, child: content);
  }

  Widget _buildDayRecords(DateTime day, bool isDark) {
    final events = _getEventsForDay(day);
    events.sort((a, b) => b.sortDate.compareTo(a.sortDate));
    final visitCount = events.where((e) => e.visitRecord != null).length;
    final recommendationCount = events
        .where((e) => e.recommendationRecord != null)
        .length;

    if (events.isEmpty) {
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(
              Icons.event_available,
              size: 48,
              color: isDark
                  ? AppColors.darkTextSecondary
                  : AppColors.lightTextSecondary,
            ),
            const SizedBox(height: 16),
            Text('이날의 기록이 없습니다', style: AppTypography.body2(isDark)),
          ],
        ),
      );
    }

    return Column(
      children: [
        Padding(
          padding: const EdgeInsets.all(16),
          child: Row(
            children: [
              Icon(
                Icons.calendar_today,
                size: 20,
                color: isDark
                    ? AppColors.darkTextSecondary
                    : AppColors.lightTextSecondary,
              ),
              const SizedBox(width: 8),
              Text(
                '${day.month}월 ${day.day}일 기록',
                style: AppTypography.body1(
                  isDark,
                ).copyWith(fontWeight: FontWeight.bold),
              ),
              const Spacer(),
              Text(
                '${events.length}건 · 방문 $visitCount/추천 $recommendationCount',
                style: AppTypography.body2(isDark).copyWith(
                  color: AppColors.lightPrimary,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ],
          ),
        ),
        ListView.builder(
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          itemCount: events.length,
          itemBuilder: (context, index) {
            final event = events[index];
            if (event.visitRecord != null) {
              return VisitRecordCard(
                visitRecord: event.visitRecord!,
                onTap: () =>
                    _showRecordActions(visitRecord: event.visitRecord!),
              );
            }
            if (event.recommendationRecord != null) {
              return RecommendationRecordCard(
                recommendation: event.recommendationRecord!,
                onTap: () => _showRecordActions(
                  recommendationRecord: event.recommendationRecord!,
                ),
                onConfirmVisit: () async {
                  await ref
                      .read(recommendationNotifierProvider.notifier)
                      .confirmVisit(event.recommendationRecord!.id);
                },
                onDelete: () async {
                  await ref
                      .read(recommendationNotifierProvider.notifier)
                      .deleteRecommendation(event.recommendationRecord!.id);
                },
              );
            }
            return const SizedBox.shrink();
          },
        ),
      ],
    );
  }

  Map<DateTime, List<_CalendarEvent>> _buildEvents(
    List<VisitRecord> visits,
    List<RecommendationRecord> recommendations,
  ) {
    final Map<DateTime, List<_CalendarEvent>> events = {};

    for (final visit in visits) {
      final day = DateTime(
        visit.visitDate.year,
        visit.visitDate.month,
        visit.visitDate.day,
      );
      events[day] = [
        ...(events[day] ?? []),
        _CalendarEvent(visitRecord: visit),
      ];
    }

    for (final reco in recommendations.where((r) => !r.visited)) {
      final day = DateTime(
        reco.recommendationDate.year,
        reco.recommendationDate.month,
        reco.recommendationDate.day,
      );
      events[day] = [
        ...(events[day] ?? []),
        _CalendarEvent(recommendationRecord: reco),
      ];
    }

    return events;
  }

  void _updateCalendarRange(
    List<VisitRecord> visits,
    List<RecommendationRecord> recommendations,
  ) {
    final range = _calculateCalendarRange(visits, recommendations);
    final clampedFocused = _clampDate(
      _focusedDay,
      range.firstDay,
      range.lastDay,
    );
    final clampedSelected = _clampDate(
      _selectedDay,
      range.firstDay,
      range.lastDay,
    );
    final updatedMonth = DateTime(clampedFocused.year, clampedFocused.month, 1);

    final hasRangeChanged =
        !_isSameDate(_firstDay, range.firstDay) ||
        !_isSameDate(_lastDay, range.lastDay);
    final hasFocusChanged = !isSameDay(_focusedDay, clampedFocused);
    final hasSelectedChanged = !isSameDay(_selectedDay, clampedSelected);
    final hasMonthChanged = !_isSameMonth(_selectedMonth, updatedMonth);

    if (hasRangeChanged ||
        hasFocusChanged ||
        hasSelectedChanged ||
        hasMonthChanged) {
      setState(() {
        _firstDay = range.firstDay;
        _lastDay = range.lastDay;
        _focusedDay = clampedFocused;
        _selectedDay = clampedSelected;
        _selectedMonth = updatedMonth;
      });
    }
  }

  ({DateTime firstDay, DateTime lastDay}) _calculateCalendarRange(
    List<VisitRecord> visits,
    List<RecommendationRecord> recommendations,
  ) {
    final now = DateTime.now();
    final dates = <DateTime>[
      ...visits.map(
        (visit) => DateTime(
          visit.visitDate.year,
          visit.visitDate.month,
          visit.visitDate.day,
        ),
      ),
      ...recommendations.map(
        (reco) => DateTime(
          reco.recommendationDate.year,
          reco.recommendationDate.month,
          reco.recommendationDate.day,
        ),
      ),
    ];

    if (dates.isEmpty) {
      return (
        firstDay: DateTime(now.year - 1, now.month, 1),
        lastDay: DateTime(now.year + 1, now.month, now.day),
      );
    }

    final earliest = dates.reduce((a, b) => a.isBefore(b) ? a : b);
    final latest = dates.reduce((a, b) => a.isAfter(b) ? a : b);
    final baseLastDay = latest.isAfter(now) ? latest : now;

    return (
      firstDay: DateTime(earliest.year, earliest.month, earliest.day),
      lastDay: DateTime(
        baseLastDay.year + 1,
        baseLastDay.month,
        baseLastDay.day,
      ),
    );
  }

  DateTime _clampDate(DateTime date, DateTime min, DateTime max) {
    if (date.isBefore(min)) return min;
    if (date.isAfter(max)) return max;
    return date;
  }

  bool _isSameDate(DateTime a, DateTime b) =>
      a.year == b.year && a.month == b.month && a.day == b.day;

  bool _isSameMonth(DateTime a, DateTime b) =>
      a.year == b.year && a.month == b.month;

  List<DateTime> _buildMonthOptions(DateTime firstDay, DateTime lastDay) {
    final months = <DateTime>[];
    var cursor = DateTime(firstDay.year, firstDay.month, 1);
    final end = DateTime(lastDay.year, lastDay.month, 1);

    while (!cursor.isAfter(end)) {
      months.add(cursor);
      cursor = DateTime(cursor.year, cursor.month + 1, 1);
    }

    return months;
  }

  void _onMonthChanged(DateTime month) {
    final targetMonth = DateTime(month.year, month.month, 1);
    final clampedMonth = _clampDate(targetMonth, _firstDay, _lastDay);

    setState(() {
      _focusedDay = clampedMonth;
      _selectedMonth = clampedMonth;
      _selectedDay = clampedMonth;
    });
  }

  Future<void> _showRecordActions({
    VisitRecord? visitRecord,
    RecommendationRecord? recommendationRecord,
  }) async {
    final restaurantId =
        visitRecord?.restaurantId ?? recommendationRecord?.restaurantId;
    if (restaurantId == null) return;

    final isDark = Theme.of(context).brightness == Brightness.dark;

    await showModalBottomSheet<void>(
      context: context,
      showDragHandle: true,
      backgroundColor: isDark ? AppColors.darkSurface : AppColors.lightSurface,
      builder: (sheetContext) {
        return Consumer(
          builder: (context, ref, child) {
            final restaurantAsync = ref.watch(restaurantProvider(restaurantId));
            return restaurantAsync.when(
              data: (restaurant) {
                if (restaurant == null) {
                  return const SizedBox.shrink();
                }

                final visitTime = visitRecord?.visitDate;
                final recoTime = recommendationRecord?.recommendationDate;
                final isVisitConfirmed = visitRecord?.isConfirmed == true;

                return Padding(
                  padding: const EdgeInsets.fromLTRB(16, 12, 16, 20),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        restaurant.name,
                        style: AppTypography.heading2(isDark),
                        maxLines: 2,
                        overflow: TextOverflow.ellipsis,
                      ),
                      const SizedBox(height: 4),
                      Text(
                        restaurant.category,
                        style: AppTypography.body2(isDark).copyWith(
                          color: isDark
                              ? AppColors.darkTextSecondary
                              : AppColors.lightTextSecondary,
                        ),
                      ),
                      const SizedBox(height: 12),
                      _buildInfoRow('주소', restaurant.roadAddress, isDark),
                      if (visitTime != null)
                        _buildInfoRow(
                          isVisitConfirmed ? '방문 완료' : '방문 예정',
                          _formatFullDateTime(visitTime),
                          isDark,
                        ),
                      if (recoTime != null)
                        _buildInfoRow(
                          '추천 시각',
                          _formatFullDateTime(recoTime),
                          isDark,
                        ),
                      const SizedBox(height: 12),
                      Wrap(
                        spacing: 8,
                        runSpacing: 8,
                        children: [
                          TextButton.icon(
                            onPressed: () => _showRestaurantDetailDialog(
                              context,
                              isDark,
                              restaurant,
                            ),
                            icon: const Icon(Icons.info_outline),
                            label: const Text('식당 정보'),
                          ),
                          TextButton.icon(
                            onPressed: () async {
                              Navigator.of(sheetContext).pop();
                              await showDialog<bool>(
                                context: context,
                                builder: (dialogContext) =>
                                    EditRestaurantDialog(
                                      restaurant: restaurant,
                                    ),
                              );
                            },
                            icon: const Icon(Icons.edit_outlined),
                            label: const Text('맛집 수정'),
                          ),
                        ],
                      ),
                      const SizedBox(height: 12),
                      if (visitRecord != null && !isVisitConfirmed)
                        SizedBox(
                          width: double.infinity,
                          child: ElevatedButton.icon(
                            onPressed: () async {
                              await ref
                                  .read(visitNotifierProvider.notifier)
                                  .confirmVisit(visitRecord.id);
                              if (!sheetContext.mounted) return;
                              Navigator.of(sheetContext).pop();
                            },
                            icon: const Icon(Icons.check_circle),
                            label: const Text('방문 확인'),
                          ),
                        ),
                      if (recommendationRecord != null)
                        SizedBox(
                          width: double.infinity,
                          child: ElevatedButton.icon(
                            onPressed: () async {
                              await ref
                                  .read(recommendationNotifierProvider.notifier)
                                  .confirmVisit(recommendationRecord.id);
                              if (!sheetContext.mounted) return;
                              Navigator.of(sheetContext).pop();
                            },
                            icon: const Icon(Icons.playlist_add_check),
                            label: const Text('추천 방문 기록으로 저장'),
                          ),
                        ),
                    ],
                  ),
                );
              },
              loading: () => const SizedBox(
                height: 160,
                child: Center(child: CircularProgressIndicator()),
              ),
              error: (_, __) => Padding(
                padding: const EdgeInsets.all(16),
                child: Text(
                  '맛집 정보를 불러올 수 없습니다.',
                  style: AppTypography.body2(isDark),
                ),
              ),
            );
          },
        );
      },
    );
  }

  Widget _buildInfoRow(String label, String value, bool isDark) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          SizedBox(
            width: 80,
            child: Text(label, style: AppTypography.caption(isDark)),
          ),
          const SizedBox(width: 8),
          Expanded(child: Text(value, style: AppTypography.body2(isDark))),
        ],
      ),
    );
  }

  Future<void> _showRestaurantDetailDialog(
    BuildContext context,
    bool isDark,
    Restaurant restaurant,
  ) async {
    await showDialog<void>(
      context: context,
      builder: (dialogContext) => AlertDialog(
        backgroundColor: isDark
            ? AppColors.darkSurface
            : AppColors.lightSurface,
        title: Text(restaurant.name),
        content: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              _buildInfoRow(
                '카테고리',
                '${restaurant.category} > ${restaurant.subCategory}',
                isDark,
              ),
              if (restaurant.phoneNumber != null)
                _buildInfoRow('전화번호', restaurant.phoneNumber!, isDark),
              _buildInfoRow('도로명', restaurant.roadAddress, isDark),
              _buildInfoRow('지번', restaurant.jibunAddress, isDark),
              if (restaurant.description != null &&
                  restaurant.description!.isNotEmpty)
                _buildInfoRow('메모', restaurant.description!, isDark),
            ],
          ),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(dialogContext).pop(),
            child: const Text('닫기'),
          ),
        ],
      ),
    );
  }

  String _formatFullDateTime(DateTime dateTime) {
    final month = dateTime.month.toString().padLeft(2, '0');
    final day = dateTime.day.toString().padLeft(2, '0');
    final hour = dateTime.hour.toString().padLeft(2, '0');
    final minute = dateTime.minute.toString().padLeft(2, '0');
    return '${dateTime.year}-$month-$day $hour:$minute';
  }

  Color _visitMarkerColor(bool isDark) =>
      isDark ? AppColors.darkPrimary : AppColors.lightPrimary;

  Color _recommendationMarkerColor(bool isDark) =>
      isDark ? AppColors.darkWarning : AppColors.lightWarning;
}

class _CalendarEvent {
  final VisitRecord? visitRecord;
  final RecommendationRecord? recommendationRecord;

  _CalendarEvent({this.visitRecord, this.recommendationRecord});

  DateTime get sortDate =>
      visitRecord?.visitDate ?? recommendationRecord!.recommendationDate;
}
