import 'package:jwt_decoder/jwt_decoder.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:chepuhagram/core/constants.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; class ApiService extends ChangeNotifier { final _client = http.Client(); final _storage = const FlutterSecureStorage(); Future refreshToken() async { notifyListeners(); try { final refreshToken = await _storage.read(key: 'refresh_token'); final response = await _client.post( Uri.http(AppConstants.baseUrl, 'auth/refresh'), body: jsonEncode({'refresh_token': refreshToken}), headers: {'Content-Type': 'application/json'}, ); 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'], ); notifyListeners(); return true; } else { notifyListeners(); return false; } } catch (e) { notifyListeners(); rethrow; } } Future getAccessToken() async { String? token = await _storage.read(key: 'access_token'); if (token != null) { bool isExpiredSoon = JwtDecoder.isExpired(token) || JwtDecoder.getRemainingTime(token).inMinutes < 2; if (isExpiredSoon) { bool refreshed = await refreshToken(); if (refreshed) { token = await _storage.read(key: 'access_token'); } else { return null; } } } return token; } Future updateFcmToken(String fcmtoken) async { notifyListeners(); try { final token = await getAccessToken(); final response = await _client.post( Uri.http(AppConstants.baseUrl, 'auth/update-fcm', {'token': fcmtoken}), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, ); if (response.statusCode == 200) { return true; } else { print("Ошибка установки ключа: ${response.statusCode}"); return false; } } catch (e) { rethrow; } finally { notifyListeners(); } } Future setPublicKey(String publicKey) async { notifyListeners(); try { final token = await getAccessToken(); final response = await _client.post( Uri.http(AppConstants.baseUrl, 'auth/set-public-key'), body: jsonEncode({'public_key': publicKey}), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, ); if (response.statusCode == 200) { return true; } else { print("Ошибка установки ключа: ${response.statusCode}"); return false; } } catch (e) { rethrow; } finally { notifyListeners(); } } Future> getMe() async { final token = await getAccessToken(); final response = await _client.get( Uri.http(AppConstants.baseUrl, 'users/me'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, ); if (response.statusCode == 200) { return jsonDecode(utf8.decode(response.bodyBytes)) as Map; } throw Exception('Не удалось получить данные пользователя'); } Future updateEncryptedPrivateKey(String encryptedPrivateKey) async { final token = await getAccessToken(); final response = await _client.put( Uri.http(AppConstants.baseUrl, 'users/me/encryption-key'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, body: jsonEncode({'encrypted_private_key': encryptedPrivateKey}), ); return response.statusCode == 200; } Future changePassword(String currentPassword, String newPassword) async { final token = await getAccessToken(); final response = await _client.put( Uri.http(AppConstants.baseUrl, 'users/me/password'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, body: jsonEncode({ 'current_password': currentPassword, 'new_password': newPassword, }), ); return response.statusCode == 200; } Future> getChatHistory(int contactId) async { final token = await getAccessToken(); final response = await http.get( Uri.http( AppConstants.baseUrl, 'messages/history/${contactId.toString()}', ), headers: { 'Content-Type': 'application/json', "Authorization": "Bearer $token", }, ); return jsonDecode(response.body) as List; } Future> updateMe({ required String username, required String firstName, required String lastName, String? phone, String? email, String? about, }) async { final token = await getAccessToken(); final response = await _client.put( Uri.http(AppConstants.baseUrl, 'users/me'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, body: jsonEncode({ 'username': username, 'first_name': firstName, 'last_name': lastName, 'phone': (phone == null || phone.trim().isEmpty) ? null : phone.trim(), 'email': (email == null || email.trim().isEmpty) ? null : email.trim(), 'about': (about == null || about.trim().isEmpty) ? null : about.trim(), }), ); final decoded = jsonDecode(utf8.decode(response.bodyBytes)); if (response.statusCode == 200) { return decoded as Map; } throw Exception((decoded is Map && decoded['detail'] != null) ? decoded['detail'] : 'Failed to update profile'); } Future> getUserById(int userId) async { final token = await getAccessToken(); final response = await _client.get( Uri.http(AppConstants.baseUrl, 'users/$userId'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, ); if (response.statusCode == 200) { return jsonDecode(utf8.decode(response.bodyBytes)) as Map; } throw Exception('Не удалось получить информацию о пользователе'); } Future updatePrivacySettings({ bool? showEmail, bool? showPhone, bool? showAvatar, bool? showAbout, bool? showUsername, }) async { final token = await getAccessToken(); final response = await _client.put( Uri.http(AppConstants.baseUrl, 'users/me/privacy'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, body: jsonEncode({ if (showEmail != null) 'show_email': showEmail, if (showPhone != null) 'show_phone': showPhone, if (showAvatar != null) 'show_avatar': showAvatar, if (showAbout != null) 'show_about': showAbout, if (showUsername != null) 'show_username': showUsername, }), ); return response.statusCode == 200; } Future> getPrivacySettings() async { final token = await getAccessToken(); final response = await _client.get( Uri.http(AppConstants.baseUrl, 'users/me/privacy'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }, ); if (response.statusCode == 200) { return jsonDecode(utf8.decode(response.bodyBytes)) as Map; } throw Exception('Не удалось получить настройки конфиденциальности'); } }