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 uploadMedia(List bytes) async { try { final token = getAccessToken(); var request = http.MultipartRequest( 'POST', Uri.parse('${AppConstants.baseUrl}/media/upload'), ); request.headers.addAll({ 'Content-Type': 'application/json', 'Authorization': 'Bearer $token', }); // Добавляем файл в запрос request.files.add( http.MultipartFile.fromBytes( 'file', bytes, filename: 'media.enc', // Имя файла для сервера ), ); // Добавь заголовки авторизации, если они у тебя есть (JWT и т.д.) // request.headers.addAll({'Authorization': 'Bearer $token'}); var streamedResponse = await request.send(); var response = await http.Response.fromStream(streamedResponse); if (response.statusCode == 200) { // Предполагаем, что сервер возвращает JSON {"file_id": "..."} final data = jsonDecode(response.body); return data['file_id']; } return null; } catch (e) { print("Ошибка API при загрузке: $e"); return null; } } Future refreshToken() async { notifyListeners(); try { final refreshToken = await _storage.read(key: 'refresh_token'); final response = await _client.post( Uri.parse('${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.parse('${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.parse('${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.parse('${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.parse('${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.parse('${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 _client.get( Uri.parse( '${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.parse('${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.parse('${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.parse('${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.parse('${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('Не удалось получить настройки конфиденциальности'); } }