import 'dart:typed_data'; import 'package:dio/dio.dart'; import '../../domain/entities/server.dart'; import '../../core/constants/api_constants.dart'; import '../../core/storage/token_manager.dart'; import '../data_sources/local/server_local_data_source.dart'; import '../models/server_hive_model.dart'; import 'package:uuid/uuid.dart'; class ExcelImportService { final _uuid = const Uuid(); final Dio _dio = Dio(); final ServerLocalDataSource? _localDataSource; ExcelImportService({ServerLocalDataSource? localDataSource}) : _localDataSource = localDataSource; /// Import servers from Excel file using backend API /// Expected columns (starting from row 2): /// - Column B: Hostname/Alias /// - Column C: Type (GeViScope or G-Core) /// - Column D: IP Server/Host /// - Column E: Username /// - Column F: Password Future> importServersFromExcel(Uint8List fileBytes, String fileName) async { try { print('[ExcelImport] Starting import, file size: ${fileBytes.length} bytes'); // Get auth token final token = TokenManager().accessToken; // Prepare multipart request final formData = FormData.fromMap({ 'file': MultipartFile.fromBytes( fileBytes, filename: fileName, ), }); // Call backend API final response = await _dio.post( '${ApiConstants.baseUrl}/excel/import-servers', data: formData, options: Options( headers: { 'Authorization': 'Bearer $token', }, ), ); if (response.statusCode != 200) { throw Exception('Server returned status ${response.statusCode}'); } final data = response.data as Map; final serversData = data['servers'] as List; print('[ExcelImport] Server returned ${serversData.length} servers'); // Convert API response to Server entities final servers = []; for (final serverData in serversData) { final serverType = serverData['type'] == 'gcore' ? ServerType.gcore : ServerType.geviscope; final server = Server( id: _uuid.v4(), alias: serverData['alias'] as String, host: serverData['host'] as String, user: serverData['user'] as String? ?? 'sysadmin', password: serverData['password'] as String? ?? '', type: serverType, enabled: serverData['enabled'] as bool? ?? true, deactivateEcho: serverData['deactivateEcho'] as bool? ?? false, deactivateLiveCheck: serverData['deactivateLiveCheck'] as bool? ?? false, ); servers.add(server); } print('[ExcelImport] Import completed: ${servers.length} servers parsed'); return servers; } catch (e) { print('[ExcelImport] Fatal error: $e'); if (e is DioException) { print('[ExcelImport] DioException type: ${e.type}'); print('[ExcelImport] Response status: ${e.response?.statusCode}'); print('[ExcelImport] Response data: ${e.response?.data}'); print('[ExcelImport] Request URL: ${e.requestOptions.uri}'); final errorMessage = e.response?.data?['detail'] ?? e.response?.data?['error'] ?? e.message ?? 'Unknown error'; throw Exception('Failed to import Excel file: $errorMessage'); } throw Exception('Failed to import Excel file: $e'); } } /// Merge imported servers with existing servers /// Only adds servers that don't already exist (based on alias or host) List mergeServers({ required List existing, required List imported, }) { final newServers = []; int duplicateCount = 0; for (final importedServer in imported) { // Check if server already exists by alias or host final isDuplicate = existing.any((existingServer) => existingServer.alias.toLowerCase() == importedServer.alias.toLowerCase() || existingServer.host.toLowerCase() == importedServer.host.toLowerCase()); if (!isDuplicate) { newServers.add(importedServer); print('[ExcelImport] New server: ${importedServer.alias}'); } else { duplicateCount++; print('[ExcelImport] Duplicate skipped: ${importedServer.alias}'); } } print('[ExcelImport] Merge complete: ${newServers.length} new servers, $duplicateCount duplicates skipped'); return newServers; } /// Save imported servers directly to local storage as dirty (unsaved) servers /// This bypasses the bloc to avoid triggering multiple rebuilds during import Future saveImportedServersToStorage(List servers) async { if (_localDataSource == null) { throw Exception('LocalDataSource not available for direct storage access'); } print('[ExcelImport] Saving ${servers.length} servers directly to storage...'); for (final server in servers) { final hiveModel = ServerHiveModel( id: server.id, alias: server.alias, host: server.host, user: server.user, password: server.password, serverType: server.type == ServerType.gcore ? 'gcore' : 'geviscope', enabled: server.enabled, deactivateEcho: server.deactivateEcho, deactivateLiveCheck: server.deactivateLiveCheck, isDirty: true, // Mark as dirty (unsaved change) syncOperation: 'create', // Needs to be created on server lastModified: DateTime.now(), ); await _localDataSource!.saveServer(hiveModel); print('[ExcelImport] Saved to storage: ${server.alias}'); } print('[ExcelImport] All ${servers.length} servers saved to storage as unsaved changes'); } }