using KronaStaffTerminal.Services; namespace KronaStaffTerminal.Tests.Mocks; public sealed class MockFingerprintScanner : IFingerprintScanner { private readonly List _devices = new(); private readonly Dictionary _loadedTemplates = new(); private int _registrationTargetId; private int _registrationStep; public ScannerState State { get; private set; } = ScannerState.Disconnected; public int DeviceCount => _devices.Count; public int ReaderIndex { get; private set; } = -1; public IReadOnlyList DiscoveredDevices => _devices; public bool IsConnected => State == ScannerState.Connected || State == ScannerState.Busy; public int SkippedTemplateCount { get; set; } = 0; public int ConnectCallCount { get; private set; } = 0; public event Action? FingerRecognized; public event Action? RegistrationProgress; public event Action? RegistrationCompleted; public event Action? StatusChanged; public event Action? StateChanged; public event Action? ConnectionLost; public event Action? RegistrationCancelled; public MockFingerprintScanner() { // Default with 1 virtual SLK20R _devices.Add(new ScannerDeviceInfo(0, "SLK20R-Virtual", "ZK-VIRT-001", "SLK20R [ZK-VIRT-001]")); } public void AddVirtualDevice(int index, string model, string serial) { _devices.Add(new ScannerDeviceInfo(index, model, serial, $"{model} [{serial}]")); } public void ClearDevices() { _devices.Clear(); } public IReadOnlyList DiscoverDevices() { return _devices; } public void Connect(int readerIndex, IEnumerable<(int FingerprintId, string Template)> templates) { ConnectCallCount++; if (_devices.Count == 0) { State = ScannerState.DriverError; StateChanged?.Invoke(ScannerState.DriverError, "No devices found"); return; } ReaderIndex = readerIndex; _loadedTemplates.Clear(); foreach (var (id, tpl) in templates) { _loadedTemplates[id] = tpl; } State = ScannerState.Connected; StateChanged?.Invoke(ScannerState.Connected, "Scanner ready"); StatusChanged?.Invoke("Scanner ready"); } public void Disconnect() { State = ScannerState.Disconnected; ReaderIndex = -1; _loadedTemplates.Clear(); StateChanged?.Invoke(ScannerState.Disconnected, "Scanner disconnected"); StatusChanged?.Invoke("Scanner disconnected"); } public void BeginRegistration(int fingerprintId) { _registrationTargetId = fingerprintId; _registrationStep = 0; State = ScannerState.Busy; StateChanged?.Invoke(ScannerState.Busy, "Enrolling finger"); } public void CancelRegistration() { _registrationTargetId = 0; _registrationStep = 0; if (State == ScannerState.Busy) { State = ScannerState.Connected; StateChanged?.Invoke(ScannerState.Connected, "Registration cancelled"); } RegistrationCancelled?.Invoke(); } public void SimulateFingerScan(int fingerprintId, int score = 85) { if (State != ScannerState.Connected) { return; } FingerRecognized?.Invoke(fingerprintId, score); } public void SimulateEnrollmentSample(string? finalTemplate = null) { if (State != ScannerState.Busy) return; _registrationStep++; RegistrationProgress?.Invoke(_registrationStep); if (_registrationStep >= 3) { string tpl = finalTemplate ?? Convert.ToBase64String(new byte[512]); _loadedTemplates[_registrationTargetId] = tpl; State = ScannerState.Connected; StateChanged?.Invoke(ScannerState.Connected, "Registration complete"); RegistrationCompleted?.Invoke(_registrationTargetId, tpl); } } public void SimulateDisconnect() { State = ScannerState.Disconnected; StateChanged?.Invoke(ScannerState.Disconnected, "Device unplugged"); ConnectionLost?.Invoke(); } public void SimulateReconnect() { State = ScannerState.Connected; StateChanged?.Invoke(ScannerState.Connected, "Device reconnected"); } public void Dispose() { Disconnect(); } }