import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'dart:convert'; import '/core/constants.dart'; import 'package:http/http.dart' as http; import 'package:chepuhagram/domain/services/api_service.dart'; import 'package:chepuhagram/data/datasources/ws_client.dart'; import 'package:chepuhagram/domain/services/crypto_service.dart'; class AuthProvider extends ChangeNotifier { bool _isLoading = false; bool get isLoading => _isLoading; int? _currentUserId; int? get currentUserId => _currentUserId; String? _username; String? get username => _username; String? _firstName; String? get firstName => _firstName; String? _lastName; String? get lastName => _lastName; String? _phone; String? get phone => _phone; String? _email; String? get email => _email; String? _about; String? get about => _about; // Privacy settings bool? _showEmail; bool? get showEmail => _showEmail; bool? _showPhone; bool? get showPhone => _showPhone; bool? _showAvatar; bool? get showAvatar => _showAvatar; bool? _showAbout; bool? get showAbout => _showAbout; bool? _showUsername; bool? get showUsername => _showUsername; String get displayName { final full = '${_firstName ?? ''} ${_lastName ?? ''}'.trim(); if (full.isNotEmpty) return full; if ((_username ?? '').isNotEmpty) return _username!; return 'User'; } // Флаги для определения пути пользователя bool _needsSetup = false; bool get needsSetup => _needsSetup; bool _needsKeyRecovery = false; bool get needsKeyRecovery => _needsKeyRecovery; bool _hasPublicKeyOnServer = false; bool get hasPublicKeyOnServer => _hasPublicKeyOnServer; final _storage = const FlutterSecureStorage(); final _client = http.Client(); final ApiService _apiService = ApiService(); final SocketService _socketService = SocketService(); final CryptoService _cryptoService = CryptoService(); Future initRealtime() async { try { await _socketService.connect(_apiService); } catch (e) { throw Exception(e); } } void closeRealtime() { _socketService.disconnect(); } SocketService get socketService => _socketService; Future login(String username, String password) async { _isLoading = true; notifyListeners(); try { final response = await _client.post( Uri.parse('${AppConstants.baseUrl}/auth/login'), body: {'username': username, 'password': password}, ); final decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map; if (response.statusCode == 200) { await _storage.write( key: 'access_token', value: decodedResponse['access_token'], ); await _storage.write( key: 'refresh_token', value: decodedResponse['refresh_token'], ); await _storage.write( key: 'user_id', value: decodedResponse['user_id'].toString(), ); _currentUserId = decodedResponse['user_id']; // Проверяем статус аккаунта (нужна ли настройка или восстановление) await _checkAccountStatus(); _isLoading = false; notifyListeners(); return true; } else { _isLoading = false; notifyListeners(); final error = decodedResponse['detail'] ?? 'Ошибка запроса'; throw Exception(error); } } catch (e) { _isLoading = false; notifyListeners(); rethrow; } } Future logout() async { final mode = await _storage.read(key: 'theme_mode'); final color = await _storage.read(key: 'accent_color'); await _storage.deleteAll(); _currentUserId = null; _username = null; _firstName = null; _lastName = null; _phone = null; _email = null; _about = null; if (mode != null) { await _storage.write(key: 'theme_mode', value: mode); } if (color != null) { await _storage.write(key: 'accent_color', value: color); } notifyListeners(); } Future tryAutoLogin() async { final token = await _apiService.getAccessToken(); if (token == null) return false; // Загружаем currentUserId из хранилища /*final userIdStr = await _storage.read(key: 'user_id'); if (userIdStr != null) { _currentUserId = int.tryParse(userIdStr); } try { final response = await _client .get( Uri.parse('${AppConstants.baseUrl}/users/me'), headers: {'Authorization': 'Bearer $token'}, ) .timeout(const Duration(seconds: 5)); if (response.statusCode == 200) { // Проверяем статус аккаунта для определения дальнейшего пути await _checkAccountStatus(); return true; } else if (response.statusCode == 401) { bool isUpdated = await _apiService.refreshToken(); if (isUpdated) { // После обновления токена проверяем статус await _checkAccountStatus(); } return isUpdated; } else { return false; } } catch (e) { // Если сервер недоступен, позволяем offline mode return true; }*/ return true; } Future updateProfileAndSecurity({ required String firstName, String? lastName, required String masterPassword, }) async { notifyListeners(); try { final token = await _apiService.getAccessToken(); // Генерируем ключи и шифруем приватный final keys = await _cryptoService.initAccountSecurity(masterPassword); final response = await _client.post( Uri.parse('${AppConstants.baseUrl}/auth/setup-account'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, body: jsonEncode({ 'first_name': firstName, 'last_name': lastName, 'public_key': keys['public_key'], 'encrypted_private_key': keys['encrypted_private_key'], }), ); if (response.statusCode == 200) { _needsSetup = false; notifyListeners(); return true; } else { print("Ошибка настройки профиля: ${response.body}"); return false; } } catch (e) { print("Ошибка сети: $e"); return false; } finally { notifyListeners(); } } // Приватный метод для проверки статуса аккаунта Future _checkAccountStatus() async { try { final token = await _apiService.getAccessToken(); final response = await _client.get( Uri.parse('${AppConstants.baseUrl}/users/me'), headers: {'Authorization': 'Bearer $token'}, ); if (response.statusCode == 200) { final data = jsonDecode(utf8.decode(response.bodyBytes)) as Map; _currentUserId = data['id'] as int?; _username = data['username']?.toString(); _firstName = data['first_name']?.toString(); _lastName = data['last_name']?.toString(); _phone = data['phone']?.toString(); _email = data['email']?.toString(); _about = data['about']?.toString(); // Проверяем наличие публичного ключа на сервере _hasPublicKeyOnServer = data['public_key'] != null && data['public_key'].isNotEmpty; // Проверяем наличие приватного ключа локально final hasLocalPrivateKey = await _storage.read(key: 'private_key') != null; if (!_hasPublicKeyOnServer) { // Путь А: Первая настройка - нужно создать ключи и профиль _needsSetup = true; _needsKeyRecovery = false; } else if (!hasLocalPrivateKey) { // Путь В: Переустановка - ключ на сервере, но его нет локально _needsKeyRecovery = true; _needsSetup = false; } else { // Путь Б: Нормальный вход - все в порядке _needsSetup = false; _needsKeyRecovery = false; } } // Загружаем настройки конфиденциальности try { final privacyData = await _apiService.getPrivacySettings(); _showEmail = privacyData['show_email'] as bool?; _showPhone = privacyData['show_phone'] as bool?; _showAvatar = privacyData['show_avatar'] as bool?; _showAbout = privacyData['show_about'] as bool?; _showUsername = privacyData['show_username'] as bool?; } catch (e) { print("Ошибка загрузки настроек конфиденциальности: $e"); // Устанавливаем значения по умолчанию _showEmail = true; _showPhone = true; _showAvatar = true; _showAbout = true; _showUsername = true; } } catch (e) { print("Ошибка проверки статуса: $e"); _needsSetup = false; _needsKeyRecovery = false; } notifyListeners(); } Future refreshMe() async { await _checkAccountStatus(); } // Метод для начала с чистого листа (новые ключи) Future resetKeys() async { await _storage.delete(key: 'private_key'); _needsKeyRecovery = false; notifyListeners(); } }