import 'dart:async'; import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:niogu_app/core/database/app_database.dart'; import 'package:niogu_app/core/models/outlet_model.dart'; import 'package:niogu_app/core/providers/app_provider.dart'; import 'package:niogu_app/core/database/database_holder.dart'; import 'package:niogu_app/core/utils/image_service.dart'; import 'package:niogu_app/core/system/system_secure.dart'; import 'package:niogu_app/core/system/system_setting.dart'; import 'package:niogu_app/core/enums/user_role.dart'; import 'package:niogu_app/features/auth/domain/entities/user.dart'; import 'package:niogu_app/features/auth/domain/repositories/i_auth_repository.dart'; import 'package:niogu_app/features/auth/presentation/providers/auth_provider.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; class AuthController extends AutoDisposeAsyncNotifier { late final IAuthRepository _repository; late final Dio _dio; @override FutureOr build() { _repository = ref.read(authRepositoryProvider); _dio = ref.read(dioProvider); } Future _handleBusinessLogo(String? serverLogoUrl) async { try { if (serverLogoUrl != null && serverLogoUrl.isNotEmpty) { final tempDir = await getTemporaryDirectory(); final tempPath = p.join(tempDir.path, 'temp_logo.jpg'); await _dio.download(serverLogoUrl, tempPath); return await ImageService.saveImageToLocalDirectory( File(tempPath), 'logo_images', ); } return null; } catch (e) { rethrow; } } Future> _handleOutletBanners( List outletModels, ) async { try { final Map localBannerPaths = {}; for (final outlet in outletModels) { final id = outlet.serverId; final banner = outlet.serverBannerUrl; if (banner != null && banner.isNotEmpty) { final tempDir = await getTemporaryDirectory(); final tempPath = p.join(tempDir.path, 'temp_logo.jpg'); await _dio.download(banner, tempPath); final localBannerPath = await ImageService.saveImageToLocalDirectory( File(tempPath), 'outlet_banner_images', ); localBannerPaths.putIfAbsent(id, () => localBannerPath); } } return localBannerPaths; } catch (e) { rethrow; } } Future login(LoginUser user) async { state = const AsyncValue.loading(); final result = await AsyncValue.guard(() async { final response = await _repository.login(user); final data = response.data!; final tenantModel = data.user.tenant; final outletModels = data.user.outlets; final userModel = data.user; final staffModels = userModel.staffs; final localLogoPath = await _handleBusinessLogo( tenantModel.serverLogoUrl, ); final localBannerPaths = await _handleOutletBanners(outletModels); final accessToken = data.accessToken; await clearDatabase(); await SystemSetting.setTenant( tenantId: tenantModel.serverId, tenantCode: tenantModel.businessCode, tenantName: tenantModel.businessName, ); await Future.delayed(Duration.zero); final appDatabase = AppDatabase(); await setDatabase(appDatabase); await appDatabase.customSelect("SELECT 1").getSingle(); await appDatabase.userDao.login( tenantModel: tenantModel, outletModels: outletModels, userModel: userModel, staffModels: staffModels, localLogoPath: localLogoPath, localBannerPaths: localBannerPaths, password: user.password, ); ref.invalidate(appDatabaseProvider); final syncService = ref.read(syncServiceProvider); syncService.stopWatching(); await syncService.startWatching(); await SystemSecure.saveAccessToken(accessToken); await SystemSetting.setIsLoggedIn(); String? outletIdByOwner; final currentUserRole = UserRole.values.byName(userModel.role); if (currentUserRole == UserRole.owner) { outletIdByOwner = userModel.outletId; } await SystemSetting.setOutletIdByOwner(outletIdByOwner); final outletName = outletModels .firstWhere((outlet) => outlet.serverId == userModel.outletId) .name; await SystemSetting.switchOutlet( outletId: userModel.outletId, outletName: outletName, ); await SystemSetting.setUser( userId: userModel.serverId, userName: userModel.name, userEmail: userModel.email, userRole: currentUserRole, ); }); state = result; if (result is AsyncError) throw result.error!; } Future register(RegisterUser register) async { state = const AsyncValue.loading(); final result = await AsyncValue.guard(() async { await _repository.register(register); }); state = result; if (result is AsyncError) throw result.error!; } }