import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:uuid/uuid.dart'; import '../../domain/entities/restaurant.dart'; import '../providers/restaurant_provider.dart'; /// 식당 추가 화면의 상태 모델 class AddRestaurantState { final bool isLoading; final String? errorMessage; final Restaurant? fetchedRestaurantData; final RestaurantFormData formData; const AddRestaurantState({ this.isLoading = false, this.errorMessage, this.fetchedRestaurantData, required this.formData, }); AddRestaurantState copyWith({ bool? isLoading, String? errorMessage, Restaurant? fetchedRestaurantData, RestaurantFormData? formData, }) { return AddRestaurantState( isLoading: isLoading ?? this.isLoading, errorMessage: errorMessage ?? this.errorMessage, fetchedRestaurantData: fetchedRestaurantData ?? this.fetchedRestaurantData, formData: formData ?? this.formData, ); } } /// 식당 폼 데이터 모델 class RestaurantFormData { final String name; final String category; final String subCategory; final String description; final String phoneNumber; final String roadAddress; final String jibunAddress; final String latitude; final String longitude; final String naverUrl; const RestaurantFormData({ this.name = '', this.category = '', this.subCategory = '', this.description = '', this.phoneNumber = '', this.roadAddress = '', this.jibunAddress = '', this.latitude = '', this.longitude = '', this.naverUrl = '', }); RestaurantFormData copyWith({ String? name, String? category, String? subCategory, String? description, String? phoneNumber, String? roadAddress, String? jibunAddress, String? latitude, String? longitude, String? naverUrl, }) { return RestaurantFormData( name: name ?? this.name, category: category ?? this.category, subCategory: subCategory ?? this.subCategory, description: description ?? this.description, phoneNumber: phoneNumber ?? this.phoneNumber, roadAddress: roadAddress ?? this.roadAddress, jibunAddress: jibunAddress ?? this.jibunAddress, latitude: latitude ?? this.latitude, longitude: longitude ?? this.longitude, naverUrl: naverUrl ?? this.naverUrl, ); } /// TextEditingController로부터 폼 데이터 생성 factory RestaurantFormData.fromControllers({ required TextEditingController nameController, required TextEditingController categoryController, required TextEditingController subCategoryController, required TextEditingController descriptionController, required TextEditingController phoneController, required TextEditingController roadAddressController, required TextEditingController jibunAddressController, required TextEditingController latitudeController, required TextEditingController longitudeController, required TextEditingController naverUrlController, }) { return RestaurantFormData( name: nameController.text.trim(), category: categoryController.text.trim(), subCategory: subCategoryController.text.trim(), description: descriptionController.text.trim(), phoneNumber: phoneController.text.trim(), roadAddress: roadAddressController.text.trim(), jibunAddress: jibunAddressController.text.trim(), latitude: latitudeController.text.trim(), longitude: longitudeController.text.trim(), naverUrl: naverUrlController.text.trim(), ); } /// Restaurant 엔티티로부터 폼 데이터 생성 factory RestaurantFormData.fromRestaurant(Restaurant restaurant) { return RestaurantFormData( name: restaurant.name, category: restaurant.category, subCategory: restaurant.subCategory, description: restaurant.description ?? '', phoneNumber: restaurant.phoneNumber ?? '', roadAddress: restaurant.roadAddress, jibunAddress: restaurant.jibunAddress, latitude: restaurant.latitude.toString(), longitude: restaurant.longitude.toString(), naverUrl: restaurant.naverUrl ?? '', ); } /// Restaurant 엔티티로 변환 Restaurant toRestaurant() { final uuid = const Uuid(); return Restaurant( id: uuid.v4(), name: name, category: category, subCategory: subCategory.isEmpty ? category : subCategory, description: description.isEmpty ? null : description, phoneNumber: phoneNumber.isEmpty ? null : phoneNumber, roadAddress: roadAddress, jibunAddress: jibunAddress.isEmpty ? roadAddress : jibunAddress, latitude: double.tryParse(latitude) ?? 37.5665, longitude: double.tryParse(longitude) ?? 126.9780, naverUrl: naverUrl.isEmpty ? null : naverUrl, source: naverUrl.isNotEmpty ? DataSource.NAVER : DataSource.USER_INPUT, createdAt: DateTime.now(), updatedAt: DateTime.now(), ); } } /// 식당 추가 화면의 ViewModel class AddRestaurantViewModel extends StateNotifier { final Ref _ref; AddRestaurantViewModel(this._ref) : super(const AddRestaurantState(formData: RestaurantFormData())); /// 네이버 URL로부터 식당 정보 가져오기 Future fetchFromNaverUrl(String url) async { if (url.trim().isEmpty) { state = state.copyWith(errorMessage: 'URL을 입력해주세요.'); return; } state = state.copyWith(isLoading: true, errorMessage: null); try { final notifier = _ref.read(restaurantNotifierProvider.notifier); final restaurant = await notifier.addRestaurantFromUrl(url); state = state.copyWith( isLoading: false, fetchedRestaurantData: restaurant, formData: RestaurantFormData.fromRestaurant(restaurant), ); } catch (e) { state = state.copyWith( isLoading: false, errorMessage: e.toString(), ); } } /// 식당 정보 저장 Future saveRestaurant() async { final notifier = _ref.read(restaurantNotifierProvider.notifier); try { Restaurant restaurantToSave; // 네이버에서 가져온 데이터가 있으면 업데이트 final fetchedData = state.fetchedRestaurantData; if (fetchedData != null) { restaurantToSave = fetchedData.copyWith( name: state.formData.name, category: state.formData.category, subCategory: state.formData.subCategory.isEmpty ? state.formData.category : state.formData.subCategory, description: state.formData.description.isEmpty ? null : state.formData.description, phoneNumber: state.formData.phoneNumber.isEmpty ? null : state.formData.phoneNumber, roadAddress: state.formData.roadAddress, jibunAddress: state.formData.jibunAddress.isEmpty ? state.formData.roadAddress : state.formData.jibunAddress, latitude: double.tryParse(state.formData.latitude) ?? fetchedData.latitude, longitude: double.tryParse(state.formData.longitude) ?? fetchedData.longitude, naverUrl: state.formData.naverUrl.isEmpty ? null : state.formData.naverUrl, updatedAt: DateTime.now(), ); } else { // 직접 입력한 경우 restaurantToSave = state.formData.toRestaurant(); } await notifier.addRestaurantDirect(restaurantToSave); return true; } catch (e) { state = state.copyWith(errorMessage: e.toString()); return false; } } /// 폼 데이터 업데이트 void updateFormData(RestaurantFormData formData) { state = state.copyWith(formData: formData); } /// 에러 메시지 초기화 void clearError() { state = state.copyWith(errorMessage: null); } } /// AddRestaurantViewModel Provider final addRestaurantViewModelProvider = StateNotifierProvider.autoDispose( (ref) => AddRestaurantViewModel(ref), );