import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:geolocator/geolocator.dart';

import '../../../core/constants/app_colors.dart';
import '../../../core/constants/app_typography.dart';
import '../../../domain/entities/restaurant.dart';
import '../../../domain/entities/weather_info.dart';
import '../../providers/ad_provider.dart';
import '../../providers/location_provider.dart';
import '../../providers/notification_provider.dart';
import '../../providers/recommendation_provider.dart';
import '../../providers/restaurant_provider.dart';
import '../../providers/settings_provider.dart'
    show notificationDelayMinutesProvider, notificationEnabledProvider;
import '../../providers/visit_provider.dart';
import '../../providers/weather_provider.dart';
import 'widgets/recommendation_result_dialog.dart';

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

  @override
  ConsumerState<RandomSelectionScreen> createState() =>
      _RandomSelectionScreenState();
}

class _RandomSelectionScreenState extends ConsumerState<RandomSelectionScreen> {
  double _distanceValue = 500;
  final List<String> _selectedCategories = [];
  final List<String> _excludedRestaurantIds = [];
  bool _isProcessingRecommendation = false;

  @override
  Widget build(BuildContext context) {
    final isDark = Theme.of(context).brightness == Brightness.dark;

    return Scaffold(
      backgroundColor: isDark
          ? AppColors.darkBackground
          : AppColors.lightBackground,
      appBar: AppBar(
        title: const Text('오늘 뭐 먹Z?'),
        backgroundColor: isDark
            ? AppColors.darkPrimary
            : AppColors.lightPrimary,
        foregroundColor: Colors.white,
        elevation: 0,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // 맛집 리스트 현황 카드
            Card(
              color: isDark ? AppColors.darkSurface : AppColors.lightSurface,
              elevation: 2,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(12),
              ),
              child: Padding(
                padding: const EdgeInsets.all(20),
                child: Column(
                  children: [
                    const Icon(
                      Icons.restaurant,
                      size: 48,
                      color: AppColors.lightPrimary,
                    ),
                    const SizedBox(height: 12),
                    Consumer(
                      builder: (context, ref, child) {
                        final restaurantsAsync = ref.watch(
                          restaurantListProvider,
                        );
                        return restaurantsAsync.when(
                          data: (restaurants) => Text(
                            '${restaurants.length}개',
                            style: AppTypography.heading1(
                              isDark,
                            ).copyWith(color: AppColors.lightPrimary),
                          ),
                          loading: () => const CircularProgressIndicator(
                            color: AppColors.lightPrimary,
                          ),
                          error: (_, __) => Text(
                            '0개',
                            style: AppTypography.heading1(
                              isDark,
                            ).copyWith(color: AppColors.lightPrimary),
                          ),
                        );
                      },
                    ),
                    Text('등록된 맛집', style: AppTypography.body2(isDark)),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 16),

            // 날씨 정보 카드
            Card(
              color: isDark ? AppColors.darkSurface : AppColors.lightSurface,
              elevation: 2,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(12),
              ),
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Consumer(
                  builder: (context, ref, child) {
                    final weatherAsync = ref.watch(weatherProvider);
                    return weatherAsync.when(
                      data: (weather) => Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: [
                          _buildWeatherData('지금', weather.current, isDark),
                          Container(
                            width: 1,
                            height: 50,
                            color: isDark
                                ? AppColors.darkDivider
                                : AppColors.lightDivider,
                          ),
                          _buildWeatherData('1시간 후', weather.nextHour, isDark),
                        ],
                      ),
                      loading: () => const Center(
                        child: CircularProgressIndicator(
                          color: AppColors.lightPrimary,
                        ),
                      ),
                      error: (_, __) => Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: [
                          _buildWeatherInfo(
                            '지금',
                            Icons.wb_sunny,
                            '맑음',
                            20,
                            isDark,
                          ),
                          Container(
                            width: 1,
                            height: 50,
                            color: isDark
                                ? AppColors.darkDivider
                                : AppColors.lightDivider,
                          ),
                          _buildWeatherInfo(
                            '1시간 후',
                            Icons.wb_sunny,
                            '맑음',
                            22,
                            isDark,
                          ),
                        ],
                      ),
                    );
                  },
                ),
              ),
            ),

            const SizedBox(height: 16),

            // 거리 설정 카드
            Card(
              color: isDark ? AppColors.darkSurface : AppColors.lightSurface,
              elevation: 2,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(12),
              ),
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('최대 거리', style: AppTypography.heading2(isDark)),
                    const SizedBox(height: 12),
                    Row(
                      children: [
                        Expanded(
                          child: SliderTheme(
                            data: SliderTheme.of(context).copyWith(
                              activeTrackColor: AppColors.lightPrimary,
                              inactiveTrackColor: AppColors.lightPrimary
                                  .withValues(alpha: 0.3),
                              thumbColor: AppColors.lightPrimary,
                              trackHeight: 4,
                            ),
                            child: Slider(
                              value: _distanceValue,
                              min: 100,
                              max: 2000,
                              divisions: 19,
                              onChanged: (value) {
                                setState(() => _distanceValue = value);
                              },
                            ),
                          ),
                        ),
                        const SizedBox(width: 12),
                        Text(
                          '${_distanceValue.toInt()}m',
                          style: AppTypography.body1(
                            isDark,
                          ).copyWith(fontWeight: FontWeight.bold),
                        ),
                      ],
                    ),
                    const SizedBox(height: 8),
                    Consumer(
                      builder: (context, ref, child) {
                        final locationAsync = ref.watch(
                          currentLocationWithFallbackProvider,
                        );
                        final restaurantsAsync = ref.watch(
                          restaurantListProvider,
                        );

                        final location = locationAsync.maybeWhen(
                          data: (pos) => pos,
                          orElse: () => null,
                        );
                        final restaurants = restaurantsAsync.maybeWhen(
                          data: (list) => list,
                          orElse: () => null,
                        );

                        if (location != null && restaurants != null) {
                          final count = _getRestaurantCountInRange(
                            restaurants,
                            location,
                            _distanceValue,
                          );
                          return Text(
                            '$count개 맛집 포함',
                            style: AppTypography.caption(isDark),
                          );
                        }

                        return Text(
                          '위치 정보를 가져오는 중...',
                          style: AppTypography.caption(isDark),
                        );
                      },
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 16),

            // 카테고리 선택 카드
            Card(
              color: isDark ? AppColors.darkSurface : AppColors.lightSurface,
              elevation: 2,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(12),
              ),
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('카테고리', style: AppTypography.heading2(isDark)),
                    const SizedBox(height: 12),
                    Consumer(
                      builder: (context, ref, child) {
                        final categoriesAsync = ref.watch(categoriesProvider);

                        return categoriesAsync.when(
                          data: (categories) => Wrap(
                            spacing: 8,
                            runSpacing: 8,
                            children: categories.isEmpty
                                ? [const Text('카테고리 없음')]
                                : categories
                                      .map(
                                        (category) => _buildCategoryChip(
                                          category,
                                          isDark,
                                        ),
                                      )
                                      .toList(),
                          ),
                          loading: () => const CircularProgressIndicator(),
                          error: (_, __) => const Text('카테고리를 불러올 수 없습니다'),
                        );
                      },
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 24),

            // 추천받기 버튼
            ElevatedButton(
              onPressed: !_isProcessingRecommendation && _canRecommend()
                  ? () => _startRecommendation()
                  : null,
              style: ElevatedButton.styleFrom(
                backgroundColor: AppColors.lightPrimary,
                foregroundColor: Colors.white,
                padding: const EdgeInsets.symmetric(vertical: 20),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(12),
                ),
                elevation: 3,
              ),
              child: _isProcessingRecommendation
                  ? const SizedBox(
                      height: 24,
                      width: 24,
                      child: CircularProgressIndicator(
                        strokeWidth: 2.5,
                        color: Colors.white,
                      ),
                    )
                  : const Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Icon(Icons.play_arrow, size: 28),
                        SizedBox(width: 8),
                        Text(
                          '광고보고 추천받기',
                          style: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ],
                    ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildWeatherData(String label, WeatherData weatherData, bool isDark) {
    return Column(
      children: [
        Text(label, style: AppTypography.caption(isDark)),
        const SizedBox(height: 8),
        Icon(
          weatherData.isRainy ? Icons.umbrella : Icons.wb_sunny,
          color: weatherData.isRainy ? Colors.blue : Colors.orange,
          size: 32,
        ),
        const SizedBox(height: 4),
        Text(
          '${weatherData.temperature}°C',
          style: AppTypography.body1(
            isDark,
          ).copyWith(fontWeight: FontWeight.bold),
        ),
        Text(weatherData.description, style: AppTypography.caption(isDark)),
      ],
    );
  }

  Widget _buildWeatherInfo(
    String label,
    IconData icon,
    String description,
    int temperature,
    bool isDark,
  ) {
    return Column(
      children: [
        Text(label, style: AppTypography.caption(isDark)),
        const SizedBox(height: 8),
        Icon(icon, color: Colors.orange, size: 32),
        const SizedBox(height: 4),
        Text(
          '$temperature°C',
          style: AppTypography.body1(
            isDark,
          ).copyWith(fontWeight: FontWeight.bold),
        ),
        Text(description, style: AppTypography.caption(isDark)),
      ],
    );
  }

  Widget _buildCategoryChip(String category, bool isDark) {
    final isSelected = _selectedCategories.contains(category);

    return FilterChip(
      label: Text(category),
      selected: isSelected,
      onSelected: (selected) {
        setState(() {
          if (selected) {
            _selectedCategories.add(category);
          } else {
            _selectedCategories.remove(category);
          }
        });
      },
      backgroundColor: isDark
          ? AppColors.darkSurface
          : AppColors.lightBackground,
      selectedColor: AppColors.lightPrimary.withValues(alpha: 0.2),
      checkmarkColor: AppColors.lightPrimary,
      labelStyle: TextStyle(
        color: isSelected
            ? AppColors.lightPrimary
            : (isDark ? AppColors.darkTextPrimary : AppColors.lightTextPrimary),
      ),
      side: BorderSide(
        color: isSelected
            ? AppColors.lightPrimary
            : (isDark ? AppColors.darkDivider : AppColors.lightDivider),
      ),
    );
  }

  int _getRestaurantCountInRange(
    List<Restaurant> restaurants,
    Position location,
    double maxDistance,
  ) {
    return restaurants.where((restaurant) {
      final distance = Geolocator.distanceBetween(
        location.latitude,
        location.longitude,
        restaurant.latitude,
        restaurant.longitude,
      );
      return distance <= maxDistance;
    }).length;
  }

  bool _canRecommend() {
    final locationAsync = ref.read(currentLocationWithFallbackProvider);
    final restaurantsAsync = ref.read(restaurantListProvider);

    final location = locationAsync.maybeWhen(
      data: (pos) => pos,
      orElse: () => null,
    );
    final restaurants = restaurantsAsync.maybeWhen(
      data: (list) => list,
      orElse: () => null,
    );

    if (location == null || restaurants == null || restaurants.isEmpty) {
      return false;
    }

    final count = _getRestaurantCountInRange(
      restaurants,
      location,
      _distanceValue,
    );
    return count > 0;
  }

  Future<void> _startRecommendation({
    bool skipAd = false,
    bool isReroll = false,
  }) async {
    if (_isProcessingRecommendation) return;

    if (!isReroll) {
      _excludedRestaurantIds.clear();
    }

    setState(() {
      _isProcessingRecommendation = true;
    });

    try {
      final candidate = await _generateRecommendationCandidate(
        excludedRestaurantIds: _excludedRestaurantIds,
      );
      if (candidate == null) {
        return;
      }
      final recommendedAt = DateTime.now();

      if (!skipAd) {
        final adService = ref.read(adServiceProvider);
        // Ad dialog 자체가 비동기 동작을 포함하므로 사용 후 mounted 체크를 수행한다.
        // ignore: use_build_context_synchronously
        final adWatched = await adService.showInterstitialAd(context);
        if (!mounted) return;
        if (!adWatched) {
          _showSnack('광고를 끝까지 시청해야 추천을 받을 수 있어요.', type: _SnackType.error);
          return;
        }
      }

      if (!mounted) return;
      await _showRecommendationDialog(candidate, recommendedAt: recommendedAt);
    } catch (_) {
      _showSnack('추천을 준비하는 중 문제가 발생했습니다.', type: _SnackType.error);
    } finally {
      if (mounted) {
        setState(() {
          _isProcessingRecommendation = false;
        });
      }
    }
  }

  Future<Restaurant?> _generateRecommendationCandidate({
    List<String> excludedRestaurantIds = const [],
  }) async {
    final notifier = ref.read(recommendationNotifierProvider.notifier);

    final recommendation = await notifier.getRandomRecommendation(
      maxDistance: _distanceValue,
      selectedCategories: _selectedCategories,
      excludedRestaurantIds: excludedRestaurantIds,
      shouldSaveRecord: false,
    );

    final result = ref.read(recommendationNotifierProvider);

    if (result.hasError) {
      final message = result.error?.toString() ?? '알 수 없는 오류';
      _showSnack('추천 중 오류가 발생했습니다: $message', type: _SnackType.error);
      return null;
    }

    if (recommendation == null) {
      _showSnack(
        '조건에 맞는 식당이 존재하지 않습니다. 광고는 재생되지 않았습니다.',
        type: _SnackType.warning,
      );
    }
    return recommendation;
  }

  Future<void> _showRecommendationDialog(
    Restaurant restaurant, {
    DateTime? recommendedAt,
  }) async {
    final result = await showDialog<RecommendationDialogResult>(
      context: context,
      barrierDismissible: false,
      builder: (dialogContext) =>
          RecommendationResultDialog(restaurant: restaurant),
    );

    if (!mounted) return;

    switch (result) {
      case RecommendationDialogResult.reroll:
        setState(() {
          _excludedRestaurantIds.add(restaurant.id);
        });
        await _startRecommendation(skipAd: true, isReroll: true);
        break;
      case RecommendationDialogResult.confirm:
      case RecommendationDialogResult.autoConfirm:
      default:
        await _handleRecommendationAccepted(
          restaurant,
          recommendedAt ?? DateTime.now(),
        );
        break;
    }
  }

  Future<void> _handleRecommendationAccepted(
    Restaurant restaurant,
    DateTime recommendationTime,
  ) async {
    try {
      final recommendationNotifier = ref.read(
        recommendationNotifierProvider.notifier,
      );
      await recommendationNotifier.saveRecommendationRecord(
        restaurant,
        recommendationTime: recommendationTime,
      );

      final notificationEnabled = await ref.read(
        notificationEnabledProvider.future,
      );
      bool notificationScheduled = false;
      if (notificationEnabled && !kIsWeb) {
        final notificationService = ref.read(notificationServiceProvider);
        final notificationReady = await notificationService.ensureInitialized(
          requestPermission: true,
        );

        if (notificationReady) {
          final delayMinutes = await ref.read(
            notificationDelayMinutesProvider.future,
          );
          await notificationService.scheduleVisitReminder(
            restaurantId: restaurant.id,
            restaurantName: restaurant.name,
            recommendationTime: recommendationTime,
            delayMinutes: delayMinutes,
          );
          notificationScheduled = await notificationService
              .hasVisitReminderScheduled();
        }
      }

      await ref
          .read(visitNotifierProvider.notifier)
          .createVisitFromRecommendation(
            restaurantId: restaurant.id,
            recommendationTime: recommendationTime,
          );

      if (notificationEnabled && !notificationScheduled && !kIsWeb) {
        _showSnack(
          '방문 기록은 저장됐지만 알림 권한이나 설정을 확인해 주세요. 방문 알림을 예약하지 못했습니다.',
          type: _SnackType.warning,
        );
      } else {
        _showSnack('맛있게 드세요! 🍴', type: _SnackType.success);
      }
      if (mounted) {
        setState(() {
          _excludedRestaurantIds.clear();
        });
      }
    } catch (_) {
      _showSnack('방문 기록 또는 알림 예약에 실패했습니다.', type: _SnackType.error);
    }
  }

  void _showSnack(String message, {_SnackType type = _SnackType.info}) {
    if (!mounted) return;
    final bgColor = switch (type) {
      _SnackType.success => Colors.teal.shade600,
      _SnackType.warning => Colors.orange.shade600,
      _SnackType.error => AppColors.lightError,
      _SnackType.info => Colors.blueGrey.shade600,
    };
    final topInset = MediaQuery.of(context).viewPadding.top;
    ScaffoldMessenger.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(
        SnackBar(
          content: Text(message),
          backgroundColor: bgColor,
          behavior: SnackBarBehavior.floating,
          margin: EdgeInsets.fromLTRB(
            16,
            (topInset > 0 ? topInset : 16) + 8,
            16,
            0,
          ),
          duration: const Duration(seconds: 3),
        ),
      );
  }
}

enum _SnackType { info, warning, error, success }
