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/weather_info.dart'; import '../../../domain/entities/restaurant.dart'; import '../../providers/restaurant_provider.dart'; import '../../providers/weather_provider.dart'; import '../../providers/location_provider.dart'; import '../../providers/recommendation_provider.dart'; import 'widgets/recommendation_result_dialog.dart'; class RandomSelectionScreen extends ConsumerStatefulWidget { const RandomSelectionScreen({super.key}); @override ConsumerState createState() => _RandomSelectionScreenState(); } class _RandomSelectionScreenState extends ConsumerState { double _distanceValue = 500; final List _selectedCategories = []; @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(currentLocationProvider); final restaurantsAsync = ref.watch(restaurantListProvider); if (locationAsync.hasValue && restaurantsAsync.hasValue) { final location = locationAsync.value; final restaurants = restaurantsAsync.value; 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: _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: 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 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(currentLocationProvider); final restaurantsAsync = ref.read(restaurantListProvider); if (!locationAsync.hasValue || !restaurantsAsync.hasValue) return false; final location = locationAsync.value; final restaurants = restaurantsAsync.value; if (location == null || restaurants == null || restaurants.isEmpty) return false; final count = _getRestaurantCountInRange(restaurants, location, _distanceValue); return count > 0; } Future _startRecommendation() async { final notifier = ref.read(recommendationNotifierProvider.notifier); await notifier.getRandomRecommendation( maxDistance: _distanceValue, selectedCategories: _selectedCategories, ); final result = ref.read(recommendationNotifierProvider); result.whenData((restaurant) { if (restaurant != null && mounted) { showDialog( context: context, barrierDismissible: false, builder: (context) => RecommendationResultDialog( restaurant: restaurant, onReroll: () { Navigator.pop(context); _startRecommendation(); }, onConfirmVisit: () { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('맛있게 드세요! 🍴'), backgroundColor: AppColors.lightPrimary, ), ); }, ), ); } else if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('조건에 맞는 맛집이 없습니다'), backgroundColor: AppColors.lightError, ), ); } }); } }