import 'dart:async'; import 'package:tools/def.dart'; import 'package:tools/models/device.dart'; import 'package:tools/models/post_install_options.dart'; class MockSshService { Future connect(Device device) async { final lastOctet = int.tryParse(device.address.split('.').last) ?? 1; final delayMs = 500 + (lastOctet % 4) * 250; await Future.delayed(Duration(milliseconds: delayMs)); } Future runSelfInstallScript({required Device device}) async { final lastOctet = int.tryParse(device.address.split('.').last) ?? 1; await Future.delayed( Duration(milliseconds: 900 + (lastOctet % 3) * 300), ); } Future runLocalInstallScript({ required Device device, required String localScriptPath, }) async { if (localScriptPath.trim().isEmpty) { throw ArgumentError('localScriptPath is empty'); } final lastOctet = int.tryParse(device.address.split('.').last) ?? 1; await Future.delayed( Duration(milliseconds: 1200 + (lastOctet % 3) * 300), ); } Future runRemoteInstallScript({ required Device device, required String remoteScriptUrl, }) async { final uri = Uri.tryParse(remoteScriptUrl.trim()); if (uri == null || !uri.hasScheme || uri.host.isEmpty) { throw ArgumentError('remoteScriptUrl is invalid'); } final lastOctet = int.tryParse(device.address.split('.').last) ?? 1; await Future.delayed( Duration(milliseconds: 1400 + (lastOctet % 3) * 300), ); } Future runInstallScript({ required Device device, required ScriptDestination destination, required String localScriptPath, required String remoteScriptUrl, }) { return switch (destination) { ScriptDestination.self => runSelfInstallScript(device: device), ScriptDestination.local => runLocalInstallScript( device: device, localScriptPath: localScriptPath, ), ScriptDestination.remote => runRemoteInstallScript( device: device, remoteScriptUrl: remoteScriptUrl, ), }; } Future disconnect() async { await Future.delayed(const Duration(milliseconds: 120)); } Future applyNetworkSettings({ required Device device, required PostInstallOptions options, }) async { if (!options.isValid) { throw ArgumentError('post install options are invalid'); } final lastOctet = int.tryParse(device.address.split('.').last) ?? 1; final baseDelay = options.useDhcp ? 550 : 850; await Future.delayed( Duration(milliseconds: baseDelay + (lastOctet % 3) * 220), ); } Future applyDeviceProfile({ required Device device, required PostInstallOptions options, }) async { if (!options.isValid) { throw ArgumentError('post install options are invalid'); } final lastOctet = int.tryParse(device.address.split('.').last) ?? 1; await Future.delayed( Duration(milliseconds: 700 + (lastOctet % 3) * 200), ); } Future applyPasswords({ required Device device, required PostInstallOptions options, }) async { if (!options.isValid) { throw ArgumentError('post install options are invalid'); } final lastOctet = int.tryParse(device.address.split('.').last) ?? 1; final hasPasswordChanges = options.changeRootPassword || options.changeTrombonPassword; final baseDelay = hasPasswordChanges ? 650 : 250; await Future.delayed( Duration(milliseconds: baseDelay + (lastOctet % 2) * 200), ); } }